/* * Copyright (c) 2021 Carlo Caione * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #define STACKSIZE (4096) #define PRIORITY K_PRIO_PREEMPT(2) K_THREAD_STACK_DEFINE(ipc0A_stack, STACKSIZE); K_THREAD_STACK_DEFINE(ipc0B_stack, STACKSIZE); K_THREAD_STACK_DEFINE(ipc1_stack, STACKSIZE); static volatile uint8_t ipc0A_received_data; static volatile uint8_t ipc0B_received_data; static volatile uint8_t ipc1_received_data; static K_SEM_DEFINE(ipc0A_bound_sem, 0, 1); static K_SEM_DEFINE(ipc0B_bound_sem, 0, 1); static K_SEM_DEFINE(ipc1_bound_sem, 0, 1); static K_SEM_DEFINE(ipc0A_data_sem, 0, 1); static K_SEM_DEFINE(ipc0B_data_sem, 0, 1); static K_SEM_DEFINE(ipc1_data_sem, 0, 1); /* * ==> THREAD 0A (IPC instance 0 - endpoint A) <== */ static void ipc0A_ept_bound(void *priv) { k_sem_give(&ipc0A_bound_sem); } static void ipc0A_ept_recv(const void *data, size_t len, void *priv) { ipc0A_received_data = *((uint8_t *) data); k_sem_give(&ipc0A_data_sem); } static struct ipc_ept_cfg ipc0A_ept_cfg = { .name = "ipc0A", .cb = { .bound = ipc0A_ept_bound, .received = ipc0A_ept_recv, }, }; static void ipc0A_entry(void *dummy0, void *dummy1, void *dummy2) { ARG_UNUSED(dummy0); ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); const struct device *ipc0_instance; unsigned char message = 0; struct ipc_ept ipc0A_ept; int ret; printk("IPC-service HOST [INST 0 - ENDP A] demo started\n"); ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); ret = ipc_service_open_instance(ipc0_instance); if (ret < 0 && ret != -EALREADY) { printk("ipc_service_open_instance() failure\n"); return; } /* * Wait 1 sec to give the opportunity to the SECONDARY core to register * the endpoint first */ k_sleep(K_MSEC(1000)); ret = ipc_service_register_endpoint(ipc0_instance, &ipc0A_ept, &ipc0A_ept_cfg); if (ret < 0) { printf("ipc_service_register_endpoint() failure\n"); return; } k_sem_take(&ipc0A_bound_sem, K_FOREVER); while (message < 100) { ret = ipc_service_send(&ipc0A_ept, &message, sizeof(message)); if (ret < 0) { printk("send_message(%d) failed with ret %d\n", message, ret); break; } k_sem_take(&ipc0A_data_sem, K_FOREVER); message = ipc0A_received_data; printk("HOST [0A]: %d\n", message); message++; } printk("IPC-service HOST [INST 0 - ENDP A] demo ended.\n"); } K_THREAD_DEFINE(ipc0A_thread_id, STACKSIZE, ipc0A_entry, NULL, NULL, NULL, PRIORITY, 0, 0); /* * ==> THREAD 0B (IPC instance 0 - endpoint B) <== */ static void ipc0B_ept_bound(void *priv) { k_sem_give(&ipc0B_bound_sem); } static void ipc0B_ept_recv(const void *data, size_t len, void *priv) { ipc0B_received_data = *((uint8_t *) data); k_sem_give(&ipc0B_data_sem); } static struct ipc_ept_cfg ipc0B_ept_cfg = { .name = "ipc0B", .cb = { .bound = ipc0B_ept_bound, .received = ipc0B_ept_recv, }, }; static void ipc0B_entry(void *dummy0, void *dummy1, void *dummy2) { ARG_UNUSED(dummy0); ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); const struct device *ipc0_instance; unsigned char message = 0; struct ipc_ept ipc0B_ept; int ret; printk("IPC-service HOST [INST 0 - ENDP B] demo started\n"); ipc0_instance = DEVICE_DT_GET(DT_NODELABEL(ipc0)); ret = ipc_service_open_instance(ipc0_instance); if (ret < 0 && ret != -EALREADY) { printk("ipc_service_open_instance() failure\n"); return; } ret = ipc_service_register_endpoint(ipc0_instance, &ipc0B_ept, &ipc0B_ept_cfg); if (ret < 0) { printf("ipc_service_register_endpoint() failure\n"); return; } k_sem_take(&ipc0B_bound_sem, K_FOREVER); while (message < 100) { ret = ipc_service_send(&ipc0B_ept, &message, sizeof(message)); if (ret < 0) { printk("send_message(%d) failed with ret %d\n", message, ret); break; } k_sem_take(&ipc0B_data_sem, K_FOREVER); message = ipc0B_received_data; printk("HOST [0B]: %d\n", message); message++; } printk("IPC-service HOST [INST 0 - ENDP B] demo ended.\n"); } K_THREAD_DEFINE(ipc0B_thread_id, STACKSIZE, ipc0B_entry, NULL, NULL, NULL, PRIORITY, 0, 0); /* * ==> THREAD 1 (IPC instance 1) <== * * NOTE: This instance is using the NOCOPY copability of the backend. */ static struct ipc_ept ipc1_ept; static void *recv_data; static void ipc1_ept_bound(void *priv) { k_sem_give(&ipc1_bound_sem); } static void ipc1_ept_recv(const void *data, size_t len, void *priv) { int ret; ret = ipc_service_hold_rx_buffer(&ipc1_ept, (void *) data); if (ret < 0) { printk("ipc_service_hold_rx_buffer failed with ret %d\n", ret); } /* * This will only support a synchronous request-answer mechanism. For * asynchronous cases a chain list should be implemented. */ recv_data = (void *) data; k_sem_give(&ipc1_data_sem); } static struct ipc_ept_cfg ipc1_ept_cfg = { .name = "ipc1", .cb = { .bound = ipc1_ept_bound, .received = ipc1_ept_recv, }, }; static void ipc1_entry(void *dummy0, void *dummy1, void *dummy2) { ARG_UNUSED(dummy0); ARG_UNUSED(dummy1); ARG_UNUSED(dummy2); const struct device *ipc1_instance; unsigned char message = 0; int ret; printk("IPC-service HOST [INST 1] demo started\n"); ipc1_instance = DEVICE_DT_GET(DT_NODELABEL(ipc1)); ret = ipc_service_open_instance(ipc1_instance); if (ret < 0 && ret != -EALREADY) { printk("ipc_service_open_instance() failure\n"); return; } ret = ipc_service_register_endpoint(ipc1_instance, &ipc1_ept, &ipc1_ept_cfg); if (ret < 0) { printf("ipc_service_register_endpoint() failure\n"); return; } k_sem_take(&ipc1_bound_sem, K_FOREVER); while (message < 50) { uint32_t len = 0; void *data; ret = ipc_service_get_tx_buffer(&ipc1_ept, &data, &len, K_FOREVER); if (ret < 0) { printk("ipc_service_get_tx_buffer failed with ret %d\n", ret); break; } if (message != 0) { *((unsigned char *) data) = *((unsigned char *) recv_data) + 1; ret = ipc_service_release_rx_buffer(&ipc1_ept, recv_data); if (ret < 0) { printk("ipc_service_release_rx_buffer failed with ret %d\n", ret); break; } } else { *((unsigned char *) data) = 0; } ret = ipc_service_send_nocopy(&ipc1_ept, data, sizeof(unsigned char)); if (ret < 0) { printk("send_message(%d) failed with ret %d\n", message, ret); break; } k_sem_take(&ipc1_data_sem, K_FOREVER); printk("HOST [1]: %d\n", *((unsigned char *) recv_data)); message++; } printk("IPC-service HOST [INST 1] demo ended.\n"); } K_THREAD_DEFINE(ipc1_thread_id, STACKSIZE, ipc1_entry, NULL, NULL, NULL, PRIORITY, 0, 0);