#include "chip.h" #include "board.h" #define MAILBOX_BASE REGS_MAILBOX_BASE #define MBDBUG(fmt, args...) printf("[MBDBUG]: "fmt , ##args) #define MBERR(fmt, args...) printf("[MBERR]: "fmt , ##args) #define MODE_AUTO_LINK (1<<1) #define MODE_AUTO_ACKNOWLEDGE (1<<0) #define SEND_MSG_TO_DEST (1<<0) #define SEND_MSG_TO_SRC (1<<1) #define MAILBOX_MIS0_REG_OFFSET 0X800 #define MAILBOX_RIS0_REG_OFFSET 0X804 #define READ_MIS(COREx) *((volatile uint32_t *)(COREx * 0x08 + MAILBOX_MIS0_REG_OFFSET + MAILBOX_BASE)) #define READ_RIS(COREx) *((volatile uint32_t *)(COREx * 0x08 + MAILBOX_RIS0_REG_OFFSET + MAILBOX_BASE)) typedef struct { mb_rx_cb_func_t cb; void *param; }mb_rx_cb_inf_t; #ifdef MAILBOX_SUPPORT static QueueHandle_t mailbox_tx_flg[TX_MAILBOX_NUM] = {0}; static mb_rx_cb_inf_t mailbox_rx_cb_inf_tab[RX_MAILBOX_NUM] = {0}; static void mailbox_int_handler(void *param) { int i,j; mail_t mail; uint32_t RIS = 0; mailbox_t *p_mailbox = NULL; reply_t reply_dat; uint32_t mstatus; RIS = READ_RIS(MAILBOX_MY_CORE_NUM); for (i=0; iSRC == MAILBOX_MY_CORE_ID) { p_mailbox->MCLR = 0xffffffff; p_mailbox->SEND = 0x0; if (((i - TX_MAILBOX_START_ID) >= 0) && ((i - TX_MAILBOX_START_ID) < TX_MAILBOX_NUM)) { xQueueSendFromISR(mailbox_tx_flg[i - TX_MAILBOX_START_ID], NULL, 0); } } else { mail.sender = p_mailbox->SRC; mail.recipients = p_mailbox->DSTA; mail.mailbox_id = i; for (j=0; jDR[j]; } if (p_mailbox->MODE & MODE_AUTO_LINK) { mail.auto_link = 1; } else { mail.auto_link = 0; } if (p_mailbox->MODE & MODE_AUTO_ACKNOWLEDGE) { mail.auto_acknowledge = 1; } else { mail.auto_acknowledge = 0; } if (((mail.mailbox_id - RX_MAILBOX_START_ID) >= 0) && \ ((mail.mailbox_id - RX_MAILBOX_START_ID) < RX_MAILBOX_NUM)) { if (mailbox_rx_cb_inf_tab[mail.mailbox_id - RX_MAILBOX_START_ID].cb) { reply_dat = mailbox_rx_cb_inf_tab[mail.mailbox_id - RX_MAILBOX_START_ID].cb(mail, \ mailbox_rx_cb_inf_tab[mail.mailbox_id - RX_MAILBOX_START_ID].param); } } if (mail.auto_acknowledge) { p_mailbox->DCLR = MAILBOX_MY_CORE_ID; } else { if (((mail.mailbox_id - RX_MAILBOX_START_ID) >= 0) && \ ((mail.mailbox_id - RX_MAILBOX_START_ID) < RX_MAILBOX_NUM)) { if (mailbox_rx_cb_inf_tab[mail.mailbox_id - RX_MAILBOX_START_ID].cb) { for (j=0; jDR[j] = reply_dat.data[j]; } } } mstatus = p_mailbox->MSTA; p_mailbox->MCLR = 0xffffffff; p_mailbox->SEND = 0; p_mailbox->MSET = (mstatus | p_mailbox->SRC) & (~p_mailbox->DSTA); p_mailbox->SEND = SEND_MSG_TO_SRC; } } } } } /** *@note: * 1.自动确认模式下,接收方返回确认信息时不会修改原邮件内容。 * 2.自动连接的邮箱号必须按递增顺序,连接的最后一个邮箱需auto_link设为0。 */ int mailbox_send_mail(mail_t *mail, uint32_t mail_num) { int ret = 0; int i,j; uint32_t val; int dest_cnt = 0; mailbox_t *p_mailbox = NULL; int mail_last_num; int mail_cnt; int mailbox_cnt; int link_start; mail_status status; mail_t *pmail = NULL; if ((!mail) || (mail_num == 0)) { ret = -1; goto exit; } for (mail_cnt=0; mail_cnt 0) && (pmail->mailbox_id != (mail[link_start].mailbox_id + mailbox_cnt))) { status = mail_s_link_discontinuous; } if ((pmail->mailbox_id >= TX_MAILBOX_MAX_ID) || (pmail->mailbox_id < TX_MAILBOX_START_ID)) { status = mail_s_mb_num_err; } } if (status == mail_s_done) { p_mailbox = (mailbox_t *)(pmail->mailbox_id*0X40 + MAILBOX_BASE); if (p_mailbox->SRC != pmail->sender) { status = mail_s_occ; } else { p_mailbox->MCLR = 0xffffffff; p_mailbox->DCLR = 0xffffffff; p_mailbox->DEST = pmail->recipients; dest_cnt = 0; for (i=0; i<32; i++) { if ((pmail->recipients >> i) & 0x01) { dest_cnt++; } } val = 0; if (dest_cnt > 1) // 多个目标核心必须开启自动确认 val |= MODE_AUTO_ACKNOWLEDGE; if (pmail->auto_acknowledge) val |= MODE_AUTO_ACKNOWLEDGE; if (pmail->auto_link && (mail_cnt < (mail_num-1))) val |= MODE_AUTO_LINK; p_mailbox->MODE = val; for (i=0; iDR[i] = pmail->data[i]; } p_mailbox->MSET = pmail->recipients; } } if (link_start < 0) { link_start = mail_cnt; } if (status == mail_s_done) { mailbox_cnt++; } if (pmail->auto_link) { if (mail_cnt < (mail_num -1)) { mail_cnt++; } else { break; } } else { break; } } if (status == mail_s_done) { p_mailbox = (mailbox_t *)(mail[link_start].mailbox_id*0X40 + MAILBOX_BASE); xQueueReset(mailbox_tx_flg[mail[mail_cnt].mailbox_id - TX_MAILBOX_START_ID]); p_mailbox->SEND = SEND_MSG_TO_DEST; if (xQueueReceive(mailbox_tx_flg[mail[mail_cnt].mailbox_id - TX_MAILBOX_START_ID], NULL, \ mail[mail_cnt].tx_tout_tick) != pdTRUE) { status = mail_s_tx_tout; MBERR("mailbox wait acknowledge time out!\n"); } } for (i=0; itx_status = status; } for (j=0; jdata[j] = p_mailbox->DR[j]; } } } exit: return ret; } /** *@berief: * 注册接收回调函数。 * 使用回调方式接收数据可带答复数据(仅当接收的邮件类型为非自动答复类型)。 * *@note: * 回调函数将在中断被调用。 */ int mailbox_register_rx_cb(int id, mb_rx_cb_func_t cb, void *param) { if ((id >= RX_MAILBOX_MAX_ID) || (id < RX_MAILBOX_START_ID)){ printf("%s id error!\n", __func__); return -1; } portENTER_CRITICAL(); mailbox_rx_cb_inf_tab[id - RX_MAILBOX_START_ID].cb = cb; mailbox_rx_cb_inf_tab[id - RX_MAILBOX_START_ID].param = param; portEXIT_CRITICAL(); return 0; } /* *@param: * id: 指定邮箱号(TX_MAILBOX_START_ID : (TX_MAILBOX_MAX_ID - 1)),小于0时,则自动找一个空闲邮箱。 * *@return: * 返回值小于0时,表示分配失败。 */ int mailbox_request(int id) { int ret = -1; int i; mailbox_t *p_mailbox = NULL; int retry; if (id >= 0) { if ((id < TX_MAILBOX_START_ID) || (id >= TX_MAILBOX_MAX_ID)) { printf("%s id error!\n", __func__); return -1; } } portENTER_CRITICAL(); if (id >= 0) { p_mailbox = (mailbox_t *)(id*0X40 + MAILBOX_BASE); if (p_mailbox->SRC == 0) { retry = 10; do { p_mailbox->SRC = 0; p_mailbox->SRC = MAILBOX_MY_CORE_ID; } while ((p_mailbox->SRC != MAILBOX_MY_CORE_ID) && (--retry)); if (p_mailbox->SRC == MAILBOX_MY_CORE_ID) ret = id; else p_mailbox->SRC = 0; } } else { for (i = TX_MAILBOX_START_ID; i < TX_MAILBOX_MAX_ID; i++) { p_mailbox = (mailbox_t *)(i*0X40 + MAILBOX_BASE); if (p_mailbox->SRC == 0) { retry = 10; do { p_mailbox->SRC = 0; p_mailbox->SRC = MAILBOX_MY_CORE_ID; } while ((p_mailbox->SRC != MAILBOX_MY_CORE_ID) && (--retry)); if (p_mailbox->SRC == MAILBOX_MY_CORE_ID) { ret = i; break; } else { p_mailbox->SRC = 0; } } } } portEXIT_CRITICAL(); return ret; } int mailbox_release(int id) { mailbox_t *p_mailbox = NULL; if ((id >= TX_MAILBOX_MAX_ID) || (id < TX_MAILBOX_START_ID)){ printf("%s id error!\n", __func__); return -1; } p_mailbox = (mailbox_t *)(id*0X40 + MAILBOX_BASE); if (p_mailbox->SRC == MAILBOX_MY_CORE_ID) { p_mailbox->SRC = 0; } return 0; } int mailbox_init(void) { int i; for (i = 0; i < TX_MAILBOX_NUM; i++) { mailbox_tx_flg[i] = xQueueCreate(1, 0); } request_irq(MAILBOX_IRQn + MAILBOX_MY_CORE_NUM, 0, mailbox_int_handler, NULL); return 0; } void mailbox_reset(void) { int i; mailbox_t *p_mailbox = NULL; for (i = TX_MAILBOX_START_ID; i < TX_MAILBOX_MAX_ID; i++) { p_mailbox = (mailbox_t *)(i*0X40 + MAILBOX_BASE); p_mailbox->SRC = 0x0; } } #endif