int can_send(can_id_t id, uint8_t data[], uint8_t dlc, CSP_BASE_TYPE * task_woken) { int i, m = -1; /* Disable CAN interrupt while looping MOBs */ CAN_CLEAR_INTERRUPT(); /* Disable interrupts while looping mailboxes */ if (task_woken == NULL) { portENTER_CRITICAL(); } /* Search free MOB from 0 -> CAN_TX_MOBs */ for(i = 0; i < CAN_TX_MOBS; i++) { if (mbox[i] == MBOX_FREE && !(CANEN2 & (1 << i))) { mbox[i] = MBOX_USED; m = i; break; } } /* Enable interrupts */ if (task_woken == NULL) { portEXIT_CRITICAL(); } /* Enable CAN interrupt */ CAN_SET_INTERRUPT(); /* Return if no available MOB was found */ if (m < 0) { csp_log_warn("TX overflow, no available MOB\r\n"); return -1; } /* Select and clear mob */ CAN_SET_MOB(m); CAN_MOB_ABORT(); CAN_CLEAR_STATUS_MOB(); /* Set identifier */ CAN_SET_EXT_ID(id); /* Set data - CANMSG is auto incrementing */ for (i = 0; i < dlc; i++) CANMSG = data[i]; /* Set DLC */ CAN_CLEAR_DLC(); CAN_SET_DLC(dlc); /* Start TX */ CAN_CONFIG_TX(); return 0; }
PROCESS_THREAD(can_drv_process, ev, data) { static can_cmd_t * cmd; static uint8_t mob_handle; uint8_t do_create_recv_buf = 0; PROCESS_BEGIN(); for(;;) { // wait on polling or timer event PROCESS_WAIT_EVENT(); // Post event about completed commands and free the mob for(mob_handle = 0; mob_handle < NB_MOB; ++mob_handle) { cmd = can_mob[mob_handle]; do_create_recv_buf = 0; if(cmd != NULL) { if(cmd->status != MOB_PENDING) { if(cmd->status & MOB_TX_COMPLETED) { ftimer_unregister_func(cmd->ftimer_id); can_send_callback(CAN_DRV_RC_NORM, cmd->frame, cmd->context); } else if(cmd->status & MOB_RX_COMPLETED) { can_recv_callback(cmd->frame); do_create_recv_buf = 1; } can_mob[mob_handle] = NULL; free(cmd); CAN_SET_MOB(mob_handle); CAN_MOB_ABORT(); } } if(do_create_recv_buf) { create_recv_buf(); } } // If waiting queue not empty, try to schedule waiting commands while( list_head(can_cmd_list) != 0 ) { if(can_get_mob_free() != NO_MOB) { cmd = list_pop(can_cmd_list); post_cmd(cmd); } else { break; } } } PROCESS_END(); }
static void abort_cmd(can_cmd_t * cmd) { uint8_t cpt; if(cmd == NULL) return; if(cmd->next != NULL) { // remove command from waiting queue list_remove(can_cmd_list, cmd); } else { // remove from pending table for(cpt = 0; cpt < NB_MOB; ++cpt) { if(cmd == can_mob[cpt]) { can_mob[cpt] = NULL; CAN_SET_MOB(cpt); CAN_MOB_ABORT(); break; } } } }