/**************************************************************************//** * * @copyright (C) 2019 Nuvoton Technology Corp. All rights reserved. * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2022-10-10 Wayne First version * ******************************************************************************/ #include #if defined(BSP_USING_WHC) #include "drv_whc.h" #include #define DBG_ENABLE #define DBG_LEVEL DBG_LOG #define DBG_SECTION_NAME "whc.demo" #define DBG_COLOR #include #define USE_WORMHOLE_CHNAME "whc0-0" typedef enum { evCMD_MEM_ALLOCATE, evCMD_MEM_FREE, evCMD_MEM_COPY, evCMD_DEVMEM_WRITE, evCMD_DEVMEM_READ, evCMD_MEM_SET } nu_whc_cmd; typedef enum { evCMD_REQ, evCMD_RESP, } nu_whc_cmd_type; #define CMD_TYPE_Pos 16 #define CMD_TYPE_Msk (3<>CMD_TYPE_Pos)==evCMD_REQ) #define CMD_IS_RESP(m) (((m.u32Cmd&CMD_TYPE_Msk)>>CMD_TYPE_Pos)==evCMD_RESP) typedef struct { union { nu_whc_msg sMsgBuf; struct { uint32_t u32Cmd; uint32_t u32Addr0; //Dst, free, allocate, set uint32_t u32Addr1; //Src, value uint32_t u32Size; } msg; }; } whc_mem; typedef whc_mem *whc_mem_t; static struct rt_semaphore tx_sem; static struct rt_semaphore rx_sem; static rt_device_t device = RT_NULL; static rt_err_t whc_tx_complete(rt_device_t dev, void *buffer) { return rt_sem_release(&tx_sem); } static rt_err_t whc_rx_indicate(rt_device_t dev, rt_size_t size) { return rt_sem_release(&rx_sem); } static rt_err_t proc_msg(whc_mem_t req, whc_mem_t resp) { switch ((nu_whc_cmd)req->msg.u32Cmd) { case evCMD_MEM_ALLOCATE: resp->msg.u32Addr0 = (uint32_t)rt_malloc(req->msg.u32Size); resp->msg.u32Size = req->msg.u32Size; resp->msg.u32Cmd = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_ALLOCATE); break; case evCMD_MEM_FREE: rt_free((void *)req->msg.u32Addr0); resp->msg.u32Addr0 = (uint32_t)req->msg.u32Addr0; resp->msg.u32Cmd = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_FREE); resp->msg.u32Size = 0; break; case evCMD_MEM_COPY: rt_memcpy((void *)req->msg.u32Addr0, (void *)req->msg.u32Addr1, req->msg.u32Size); resp->msg.u32Cmd = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_COPY); resp->msg.u32Addr0 = (uint32_t)req->msg.u32Addr0; resp->msg.u32Addr1 = (uint32_t)req->msg.u32Addr1; resp->msg.u32Size = req->msg.u32Size; break; case evCMD_MEM_SET: rt_memset((void *)req->msg.u32Addr0, (req->msg.u32Addr1 & 0xff), req->msg.u32Size); resp->msg.u32Cmd = PACK_MSG_CMD(evCMD_RESP, evCMD_MEM_SET); resp->msg.u32Addr0 = (uint32_t)req->msg.u32Addr0; resp->msg.u32Addr1 = (uint32_t)(req->msg.u32Addr1 & 0xff); resp->msg.u32Size = req->msg.u32Size; break; case evCMD_DEVMEM_WRITE: *((vu32 *)req->msg.u32Addr0) = req->msg.u32Addr1; resp->msg.u32Cmd = PACK_MSG_CMD(evCMD_RESP, evCMD_DEVMEM_WRITE); resp->msg.u32Addr0 = 0; resp->msg.u32Addr1 = 0; resp->msg.u32Size = sizeof(uint32_t); break; case evCMD_DEVMEM_READ: resp->msg.u32Cmd = PACK_MSG_CMD(evCMD_RESP, evCMD_DEVMEM_READ); resp->msg.u32Addr0 = *((vu32 *)req->msg.u32Addr0); resp->msg.u32Addr1 = 0; resp->msg.u32Size = sizeof(uint32_t); break; default: return -RT_ERROR; } return -RT_ERROR; } static rt_err_t send_msg(whc_mem_t req) { if (device) { if (sizeof(nu_whc_msg) != rt_device_write(device, 0, req, sizeof(nu_whc_msg))) { LOG_E("Failed to send msg."); return -RT_ERROR; } if (-RT_ETIMEOUT == rt_sem_take(&tx_sem, 100)) LOG_E("Timeout cant get ACK."); } return RT_EOK; } static void whc_daemon(void *parameter) { rt_err_t ret; device = rt_device_find(USE_WORMHOLE_CHNAME); RT_ASSERT(device); /* Init semaphores */ ret = rt_sem_init(&tx_sem, "whc_tx", 0, RT_IPC_FLAG_PRIO); RT_ASSERT(ret == RT_EOK); ret = rt_sem_init(&rx_sem, "whc_rx", 0, RT_IPC_FLAG_PRIO); RT_ASSERT(ret == RT_EOK); /* Set tx complete function */ ret = rt_device_set_tx_complete(device, whc_tx_complete); RT_ASSERT(ret == RT_EOK); /* Set rx indicate function */ ret = rt_device_set_rx_indicate(device, whc_rx_indicate); RT_ASSERT(ret == RT_EOK); ret = rt_device_open(device, 0); if (!device) { LOG_E("Failed to open %s", USE_WORMHOLE_CHNAME); return; } while (1) { if (rt_sem_take(&rx_sem, RT_WAITING_FOREVER) == RT_EOK) { nu_whc_msg sNuWhcMsg; whc_mem_t psWhcMem = (whc_mem_t)&sNuWhcMsg; if (sizeof(nu_whc_msg) != rt_device_read(device, 0, psWhcMem, sizeof(nu_whc_msg))) continue; if (CMD_IS_REQ(psWhcMem->msg)) { nu_whc_msg sNuWhcMsg_Resp; proc_msg((whc_mem_t)&sNuWhcMsg, (whc_mem_t)&sNuWhcMsg_Resp); send_msg((whc_mem_t)&sNuWhcMsg_Resp); } else if (CMD_IS_RESP(psWhcMem->msg)) { LOG_I("Get Resp. 0x%08x 0x%08x 0x%08x %d", psWhcMem->msg.u32Cmd, psWhcMem->msg.u32Addr0, psWhcMem->msg.u32Addr1, psWhcMem->msg.u32Size); } } //if } //while } static int wormhole_app(void) { rt_err_t result = 0; rt_thread_t thread; thread = rt_thread_create("whcD", whc_daemon, RT_NULL, 2048, 25, 20); if (thread != RT_NULL) { result = rt_thread_startup(thread); RT_ASSERT(result == RT_EOK); } return 0; } INIT_COMPONENT_EXPORT(wormhole_app); void *whc_malloc(uint32_t u32Size) { whc_mem sWhcMem; sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_MEM_ALLOCATE); sWhcMem.msg.u32Size = (uint32_t)u32Size; send_msg(&sWhcMem); return 0; } RTM_EXPORT(whc_malloc); void *whc_memcpy(void *pvDst, void *pvSrc, uint32_t u32Size) { whc_mem sWhcMem; sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_MEM_COPY); sWhcMem.msg.u32Addr0 = (uint32_t)pvDst; sWhcMem.msg.u32Addr1 = (uint32_t)pvSrc; sWhcMem.msg.u32Size = (uint32_t)u32Size; send_msg(&sWhcMem); return 0; } RTM_EXPORT(whc_memcpy); uint32_t whc_devmem_write(void *pvaddr, uint32_t u32value) { whc_mem sWhcMem; sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_DEVMEM_WRITE); sWhcMem.msg.u32Addr0 = (uint32_t)pvaddr; sWhcMem.msg.u32Addr1 = u32value; sWhcMem.msg.u32Size = sizeof(uint32_t); send_msg(&sWhcMem); return 0; } RTM_EXPORT(whc_devmem_write); uint32_t whc_devmem_read(void *pvaddr) { whc_mem sWhcMem; sWhcMem.msg.u32Cmd = PACK_MSG_CMD(evCMD_REQ, evCMD_DEVMEM_READ); sWhcMem.msg.u32Addr0 = (uint32_t)pvaddr; sWhcMem.msg.u32Addr1 = 0; sWhcMem.msg.u32Size = sizeof(uint32_t); send_msg(&sWhcMem); return 0; } RTM_EXPORT(whc_devmem_read); void whc_devmem(int argc, char *argv[]) { volatile unsigned int u32Addr; unsigned int value = 0, mode = 0; if (argc < 2 || argc > 3) { goto exit_devmem; } if (argc == 3) { if (sscanf(argv[2], "0x%x", &value) != 1) goto exit_devmem; mode = 1; //Write } if (sscanf(argv[1], "0x%x", &u32Addr) != 1) goto exit_devmem; else if (u32Addr & (4 - 1)) goto exit_devmem; if (mode) { whc_devmem_write((void *) u32Addr, value); } rt_kprintf("0x%08x\n", whc_devmem_read((void *)u32Addr)); return; exit_devmem: rt_kprintf("Read: whc_devmem \n"); rt_kprintf("Write: whc_devmem \n"); return; } MSH_CMD_EXPORT(whc_devmem, dump device registers); #endif /* #if defined(BSP_USING_HWSEM)*/