| /* |
| * Copyright (c) 2022 Nordic Semiconductor ASA |
| * |
| * SPDX-License-Identifier: Apache-2.0 |
| */ |
| |
| #include <zephyr/kernel.h> |
| #include <zephyr/device.h> |
| |
| #include <zephyr/ipc/ipc_service.h> |
| #include <hal/nrf_reset.h> |
| #include <string.h> |
| |
| #include "common.h" |
| |
| #include <zephyr/logging/log.h> |
| LOG_MODULE_REGISTER(host, LOG_LEVEL_INF); |
| |
| |
| #define DT_DRV_COMPAT zephyr_ipc_icmsg |
| |
| K_SEM_DEFINE(bound_sem, 0, 1); |
| static unsigned char expected_message = 'A'; |
| static size_t expected_len = PACKET_SIZE_START; |
| |
| static void ep_bound(void *priv) |
| { |
| k_sem_give(&bound_sem); |
| LOG_INF("Ep bounded"); |
| } |
| |
| static void ep_recv(const void *data, size_t len, void *priv) |
| { |
| struct data_packet *packet = (struct data_packet *)data; |
| |
| __ASSERT(packet->data[0] == expected_message, "Unexpected message. Expected %c, got %c", |
| expected_message, packet->data[0]); |
| __ASSERT(len == expected_len, "Unexpected length. Expected %zu, got %zu", |
| expected_len, len); |
| |
| expected_message++; |
| expected_len++; |
| |
| if (expected_message > 'Z') { |
| expected_message = 'A'; |
| } |
| |
| if (expected_len > sizeof(struct data_packet)) { |
| expected_len = PACKET_SIZE_START; |
| } |
| } |
| |
| static int send_for_time(struct ipc_ept *ep, const int64_t sending_time_ms) |
| { |
| struct data_packet msg = {.data[0] = 'a'}; |
| size_t mlen = PACKET_SIZE_START; |
| size_t bytes_sent = 0; |
| int ret = 0; |
| |
| LOG_INF("Perform sends for %lld [ms]", sending_time_ms); |
| |
| int64_t start = k_uptime_get(); |
| |
| while ((k_uptime_get() - start) < sending_time_ms) { |
| ret = ipc_service_send(ep, &msg, mlen); |
| if (ret == -ENOMEM) { |
| /* No space in the buffer. Retry. */ |
| continue; |
| } else if (ret < 0) { |
| LOG_ERR("Failed to send (%c) failed with ret %d", msg.data[0], ret); |
| break; |
| } |
| |
| msg.data[0]++; |
| if (msg.data[0] > 'z') { |
| msg.data[0] = 'a'; |
| } |
| |
| bytes_sent += mlen; |
| mlen++; |
| |
| if (mlen > sizeof(struct data_packet)) { |
| mlen = PACKET_SIZE_START; |
| } |
| |
| k_usleep(1); |
| } |
| |
| LOG_INF("Sent %zu [Bytes] over %lld [ms]", bytes_sent, sending_time_ms); |
| |
| return ret; |
| } |
| |
| static struct ipc_ept_cfg ep_cfg = { |
| .cb = { |
| .bound = ep_bound, |
| .received = ep_recv, |
| }, |
| }; |
| |
| int main(void) |
| { |
| const struct device *ipc0_instance; |
| struct ipc_ept ep; |
| int ret; |
| |
| LOG_INF("IPC-service HOST demo started"); |
| |
| ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); |
| |
| ret = ipc_service_open_instance(ipc0_instance); |
| if ((ret < 0) && (ret != -EALREADY)) { |
| LOG_ERR("ipc_service_open_instance() failure"); |
| return ret; |
| } |
| |
| ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); |
| if (ret < 0) { |
| LOG_ERR("ipc_service_register_endpoint() failure"); |
| return ret; |
| } |
| |
| k_sem_take(&bound_sem, K_FOREVER); |
| |
| ret = send_for_time(&ep, SENDING_TIME_MS); |
| if (ret < 0) { |
| LOG_ERR("send_for_time() failure"); |
| return ret; |
| } |
| |
| LOG_INF("Wait 500ms. Let net core finish its sends"); |
| k_msleep(500); |
| |
| LOG_INF("Stop network core"); |
| nrf_reset_network_force_off(NRF_RESET, true); |
| |
| LOG_INF("Reset IPC service"); |
| |
| ret = ipc_service_deregister_endpoint(&ep); |
| if (ret != 0) { |
| LOG_ERR("ipc_service_register_endpoint() failure"); |
| return ret; |
| } |
| |
| /* Reset message and expected message value and len. */ |
| expected_message = 'A'; |
| expected_len = PACKET_SIZE_START; |
| |
| /* Reset bound sem. */ |
| ret = k_sem_init(&bound_sem, 0, 1); |
| if (ret != 0) { |
| LOG_ERR("k_sem_init() failure"); |
| return ret; |
| } |
| |
| uintptr_t tx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(0, tx_region)); |
| uintptr_t tx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(0, tx_region)); |
| uintptr_t rx_shm_size = DT_REG_SIZE(DT_INST_PHANDLE(0, rx_region)); |
| uintptr_t rx_shm_addr = DT_REG_ADDR(DT_INST_PHANDLE(0, rx_region)); |
| |
| LOG_INF("Clean shared memory"); |
| |
| memset((void *)tx_shm_addr, 0, tx_shm_size); |
| memset((void *)rx_shm_addr, 0, rx_shm_size); |
| |
| ret = ipc_service_register_endpoint(ipc0_instance, &ep, &ep_cfg); |
| if (ret != 0) { |
| LOG_INF("ipc_service_register_endpoint() failure"); |
| return ret; |
| } |
| |
| LOG_INF("Run network core"); |
| nrf_reset_network_force_off(NRF_RESET, false); |
| |
| k_sem_take(&bound_sem, K_FOREVER); |
| |
| ret = send_for_time(&ep, SENDING_TIME_MS); |
| if (ret < 0) { |
| LOG_ERR("send_for_time() failure"); |
| return ret; |
| } |
| |
| LOG_INF("IPC-service HOST demo ended"); |
| |
| return 0; |
| } |