bool CAN_setup_filter(const can_std_id_t *std_id_list, uint16_t sid_cnt, const can_std_grp_id_t *std_group_id_list, uint16_t sgp_cnt, const can_ext_id_t *ext_id_list, uint16_t eid_cnt, const can_ext_grp_id_t *ext_group_id_list, uint16_t egp_cnt) { bool ok = true; // Count of standard IDs must be even if (sid_cnt & 1) { return false; } LPC_CANAF->AFMR = afmr_disabled; { /* Filter RAM is after the FulLCAN entries */ uint8_t *can_ram_base = (uint8_t*)&(LPC_CANAF_RAM->mask[0]); uint8_t *filter_ram_base = can_ram_base + LPC_CANAF->SFF_sa; // Our filter RAM is after FullCAN entries /* FullCAN entries take up 2 bytes each at beginning RAM, and 12-byte sections at the end */ uint8_t *end = can_ram_base + sizeof(LPC_CANAF_RAM->mask) - ( sizeof(can_fullcan_msg_t) * CAN_fullcan_get_num_entries()); uint8_t *ptr = filter_ram_base; #define CAN_add_filter_list(list, ptr, end, cnt, entry_size) \ do { if (NULL != list) { \ if (ptr + (cnt * entry_size) < end) { \ memcpy(ptr, list, (cnt * entry_size)); \ ptr += (cnt * entry_size); \ } else { ok = false; } } } while(0) /* The sa (start addresses) are byte address offset from CAN RAM * and must be 16-bit (WORD) aligned * LPC_CANAF->SFF_sa should already be setup by FullCAN if used, or * set to zero by the can init function. */ CAN_add_filter_list(std_id_list, ptr, end, sid_cnt, sizeof(can_std_id_t)); LPC_CANAF->SFF_GRP_sa = (ptr - can_ram_base); CAN_add_filter_list(std_group_id_list, ptr, end, sgp_cnt, sizeof(can_std_grp_id_t)); LPC_CANAF->EFF_sa = (ptr - can_ram_base); CAN_add_filter_list(ext_id_list, ptr, end, eid_cnt, sizeof(can_ext_id_t)); LPC_CANAF->EFF_GRP_sa = (ptr - can_ram_base); CAN_add_filter_list(ext_group_id_list, ptr, end, egp_cnt, sizeof(can_ext_grp_id_t)); /* End of table is where the FullCAN messages are stored */ LPC_CANAF->ENDofTable = (ptr - can_ram_base); } /* If there was no FullCAN entry, then SFF_sa will be zero. * If it was zero, we just enable the AFMR, but if it was not zero, that means * FullCAN entry was added, so we restore AMFR to fullcan enable */ LPC_CANAF->AFMR = (0 == LPC_CANAF->SFF_sa) ? afmr_enabled : afmr_fullcan; return ok; }
bool CAN_setup_filter(const can_std_id_t *std_id_list, uint16_t sid_cnt, const can_std_grp_id_t *std_group_id_list, uint16_t sgp_cnt, const can_ext_id_t *ext_id_list, uint16_t eid_cnt, const can_ext_grp_id_t *ext_group_id_list, uint16_t egp_cnt) { bool ok = true; uint32_t i = 0; uint32_t temp32 = 0; // Count of standard IDs must be even if (sid_cnt & 1) { return false; } LPC_CANAF->AFMR = afmr_disabled; do { /* Filter RAM is after the FulLCAN entries */ uint32_t can_ram_base_addr = (uint32_t) &(LPC_CANAF_RAM->mask[0]); /* FullCAN entries take up 2 bytes each at beginning RAM, and 12-byte sections at the end */ const uint32_t can_ram_end_addr = can_ram_base_addr + sizeof(LPC_CANAF_RAM->mask) - ( sizeof(can_fullcan_msg_t) * CAN_fullcan_get_num_entries()); /* Our filter RAM is after FullCAN entries */ uint32_t *ptr = (uint32_t*) (can_ram_base_addr + LPC_CANAF->SFF_sa); /* macro to swap top and bottom 16-bits of 32-bit DWORD */ #define CAN_swap32(t32) do { \ t32 = (t32 >> 16) | (t32 << 16);\ } while (0) /** * Standard ID list and group list need to swapped otherwise setting the wrong * filter will make the CAN ISR go into a loop for no apparent reason. * It looks like the filter data is motorolla big-endian format. * See "configuration example 5" in CAN chapter. */ #define CAN_add_filter_list(list, ptr, end, cnt, entry_size, swap) \ do { if (NULL != list) { \ if ((uint32_t)ptr + (cnt * entry_size) < end) { \ for (i = 0; i < (cnt * entry_size)/4; i++) { \ if(swap) { \ temp32 = ((uint32_t*)list) [i]; \ CAN_swap32(temp32); \ ptr[i] = temp32; \ } \ else { \ ptr[i] = ((uint32_t*)list) [i]; \ } \ } \ ptr += (cnt * entry_size)/4; \ } else { ok = false; } } } while(0) /* The sa (start addresses) are byte address offset from CAN RAM * and must be 16-bit (WORD) aligned * LPC_CANAF->SFF_sa should already be setup by FullCAN if used, or * set to zero by the can init function. */ CAN_add_filter_list(std_id_list, ptr, can_ram_end_addr, sid_cnt, sizeof(can_std_id_t), true); LPC_CANAF->SFF_GRP_sa = ((uint32_t)ptr - can_ram_base_addr); CAN_add_filter_list(std_group_id_list, ptr, can_ram_end_addr, sgp_cnt, sizeof(can_std_grp_id_t), true); LPC_CANAF->EFF_sa = ((uint32_t)ptr - can_ram_base_addr); CAN_add_filter_list(ext_id_list, ptr, can_ram_end_addr, eid_cnt, sizeof(can_ext_id_t), false); LPC_CANAF->EFF_GRP_sa = ((uint32_t)ptr - can_ram_base_addr); CAN_add_filter_list(ext_group_id_list, ptr, can_ram_end_addr, egp_cnt, sizeof(can_ext_grp_id_t), false); /* End of table is where the FullCAN messages are stored */ LPC_CANAF->ENDofTable = ((uint32_t)ptr - can_ram_base_addr); } while(0); /* If there was no FullCAN entry, then SFF_sa will be zero. * If it was zero, we just enable the AFMR, but if it was not zero, that means * FullCAN entry was added, so we restore AMFR to fullcan enable */ LPC_CANAF->AFMR = (0 == LPC_CANAF->SFF_sa) ? afmr_enabled : afmr_fullcan; return ok; }