Beispiel #1
0
can_fullcan_msg_t* CAN_fullcan_get_entry_ptr(can_std_id_t fc_id)
{
    /* Number of entries depends on how far SFF_sa is from base of 0 */
    const uint16_t num_entries = CAN_fullcan_get_num_entries();
    uint16_t idx = 0;

    /* The FullCAN entries are at the base of the CAN RAM */
    const can_std_id_t *id_list = (can_std_id_t*) &(LPC_CANAF_RAM->mask[0]);

    /* Find the standard ID entered into the RAM
     * Once we find the ID, its message's RAM location is after
     * LPC_CANAF->ENDofTable based on the index location
     */
    for (idx = 0; idx < num_entries; idx++) {
        if (id_list[idx].id == fc_id.id) {
            break;
        }
    }

    can_fullcan_msg_t *real_entry = NULL;
    if (idx < num_entries) {
        /* If we find an index, we have to convert it to the actual message pointer */
        can_fullcan_msg_t *base_msg_entry = (can_fullcan_msg_t*)
                                                   (((uint8_t*) &(LPC_CANAF_RAM->mask[0])) + LPC_CANAF->ENDofTable);
        real_entry = (base_msg_entry + idx);
    }

    return real_entry;
}
Beispiel #2
0
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;
}
Beispiel #3
0
bool CAN_fullcan_add_entry(can_t can, can_std_id_t id1, can_std_id_t id2)
{
    /* Return if invalid CAN given */
    if (!CAN_VALID(can)) {
        return false;
    }

    /* Check for enough room for more FullCAN entries
     * Each entry takes 2-byte entry, and 12-byte message RAM.
     */
    const uint16_t existing_entries = CAN_fullcan_get_num_entries();
    const uint16_t size_per_entry = sizeof(can_std_id_t) + sizeof(can_fullcan_msg_t);
    if ((existing_entries * size_per_entry) >= sizeof(LPC_CANAF_RAM->mask)) {
        return false;
    }

    /* Locate where we should write the next entry */
    uint8_t *base = (uint8_t*) &(LPC_CANAF_RAM->mask[0]);
    uint8_t *next_entry_ptr = base + LPC_CANAF->SFF_sa;

    /* Copy the new entry into the RAM filter */
    LPC_CANAF->AFMR = afmr_disabled;
    do {
        const uint32_t entries = ((uint32_t) id2.raw & UINT16_MAX) | ((uint32_t) id1.raw << 16);
        * (uint32_t*) (next_entry_ptr) = entries;

        /* The new start of Standard Frame Filter is after the two new entries */
        const uint32_t new_sff_sa = LPC_CANAF->SFF_sa + sizeof(id1) + sizeof(id2);
        LPC_CANAF->SFF_sa = new_sff_sa;

        /* Next filters start at SFF_sa (they are disabled) */
        LPC_CANAF->SFF_GRP_sa = new_sff_sa;
        LPC_CANAF->EFF_sa     = new_sff_sa;
        LPC_CANAF->EFF_GRP_sa = new_sff_sa;
        LPC_CANAF->ENDofTable = new_sff_sa;
    } while(0);
    LPC_CANAF->AFMR = afmr_fullcan;

    return true;
}
Beispiel #4
0
can_fullcan_msg_t* CAN_fullcan_get_entry_ptr(can_std_id_t fc_id)
{
    /* Number of entries depends on how far SFF_sa is from base of 0 */
    const uint16_t num_entries = CAN_fullcan_get_num_entries();
    uint16_t idx = 0;

    /* The FullCAN entries are at the base of the CAN RAM */
    const can_std_id_t *id_list = (can_std_id_t*) &(LPC_CANAF_RAM->mask[0]);

    /* Find the standard ID entered into the RAM
     * Once we find the ID, its message's RAM location is after
     * LPC_CANAF->ENDofTable based on the index location.
     *
     * Note that due to MSB/LSB of the CAN RAM, we check in terms of 16-bit WORDS
     * and LSB word match means we will find it at index + 1, and MSB word match
     * means we will find it at the index.
     */
    for (idx = 0; idx < num_entries; idx+=2) {
        if (id_list[idx].id == fc_id.id) {
            ++idx;
            break;
        }
        if (id_list[idx+1].id == fc_id.id) {
            break;
        }
    }

    can_fullcan_msg_t *real_entry = NULL;
    if (idx < num_entries) {
        /* If we find an index, we have to convert it to the actual message pointer */
        can_fullcan_msg_t *base_msg_entry = (can_fullcan_msg_t*)
                                                   (((uint8_t*) &(LPC_CANAF_RAM->mask[0])) + LPC_CANAF->ENDofTable);
        real_entry = (base_msg_entry + idx);
    }

    return real_entry;
}
Beispiel #5
0
bool CAN_test(void)
{
    uint32_t i = 0;

    #define can_test_msg(msg, id, rxtrue) do {              \
            u0_dbg_printf("Send ID: 0x%08X\n", id);         \
            msg.msg_id = id;                                \
            CAN_ASSERT(CAN_tx(can1, &msg, 0));              \
            msg.msg_id = 0;                                 \
            CAN_ASSERT(rxtrue == CAN_rx(can1, &msg, 10));   \
            if (rxtrue) CAN_ASSERT(id == msg.msg_id);       \
         } while(0)

    u0_dbg_printf("  Test init()\n");
    CAN_ASSERT(!CAN_init(can_max, 100, 0, 0, NULL, NULL));
    CAN_ASSERT(CAN_init(can1, 100, 5, 5, CAN_test_bufoff_cb, CAN_test_bufovr_cb));
    CAN_ASSERT(LPC_CAN1->MOD == can_mod_reset);
    CAN_bypass_filter_accept_all_msgs();

    CAN_ASSERT(g_can_rx_qs[0] != NULL);
    CAN_ASSERT(g_can_tx_qs[0] != NULL);
    CAN_ASSERT(LPC_CANAF->SFF_sa     == 0);
    CAN_ASSERT(LPC_CANAF->SFF_GRP_sa == 0);
    CAN_ASSERT(LPC_CANAF->EFF_sa     == 0);
    CAN_ASSERT(LPC_CANAF->EFF_GRP_sa == 0);
    CAN_ASSERT(LPC_CANAF->ENDofTable == 0);

    CAN_reset_bus(can1);
    CAN_ASSERT(LPC_CAN1->MOD == can_mod_selftest);

    /* Create a message, and test tx with bad input */
    uint32_t id = 0x100;
    can_msg_t msg;
    memset(&msg, 0, sizeof(msg));
    msg.frame = 0;
    msg.msg_id = id;
    msg.frame_fields.is_29bit = 0;
    msg.frame_fields.data_len = 8;
    msg.data.qword = 0x1122334455667788;
    CAN_ASSERT(!CAN_tx(can_max, &msg, 0));  // Invalid CAN
    CAN_ASSERT(!CAN_rx(can1, NULL, 0));     // Invalid message pointer

    /* Send msg and test receive */
    u0_dbg_printf("  Test Tx/Rx\n");
    can_test_msg(msg, 0x100, true);
    can_test_msg(msg, 0x200, true);
    can_test_msg(msg, 0x300, true);
    can_test_msg(msg, 0x400, true);
    can_test_msg(msg, 0x500, true);

    const can_std_id_t slist[]      = { CAN_gen_sid(can1, 0x100), CAN_gen_sid(can1, 0x110),   // 2 entries
                                        CAN_gen_sid(can1, 0x120), CAN_gen_sid(can1, 0x130)    // 2 entries
    };
    const can_std_grp_id_t sglist[] = { {CAN_gen_sid(can1, 0x200), CAN_gen_sid(can1, 0x210)}, // Group 1
                                      {CAN_gen_sid(can1, 0x220), CAN_gen_sid(can1, 0x230)}  // Group 2
    };
    const can_ext_id_t elist[]      = { CAN_gen_eid(can1, 0x7500), CAN_gen_eid(can1, 0x8500)};
    const can_ext_grp_id_t eglist[] = { {CAN_gen_eid(can1, 0xA000), CAN_gen_eid(can1, 0xB000)} }; // Group 1

    /* Test filter setup */
    u0_dbg_printf("  Test filter setup\n");
    CAN_setup_filter(slist, 4, sglist, 2, elist, 2, eglist, 1);

    /* We use offset of zero if 2 FullCAN messages are added, otherwise 4 if none were added above */
    const uint8_t offset = 4;
    CAN_ASSERT(LPC_CANAF->SFF_sa     == 4  - offset);
    CAN_ASSERT(LPC_CANAF->SFF_GRP_sa == 12 - offset);
    CAN_ASSERT(LPC_CANAF->EFF_sa     == 20 - offset);
    CAN_ASSERT(LPC_CANAF->EFF_GRP_sa == 28 - offset);
    CAN_ASSERT(LPC_CANAF->ENDofTable == 36 - offset);
    for ( i = 0; i < 10; i++) {
        u0_dbg_printf("%2i: 0x%08X\n", i, (uint32_t) LPC_CANAF_RAM->mask[i]);
    }

    /* Send a message defined in filter */
    u0_dbg_printf("  Test filter messages\n");
    msg.frame = 0;
    msg.frame_fields.is_29bit = 0;
    msg.frame_fields.data_len = 8;
    msg.data.qword = 0x1122334455667788;

    /* Test reception of messages defined in the filter */
    u0_dbg_printf("  Test message reception according to filter\n");
    msg.frame_fields.is_29bit = 0;
    can_test_msg(msg, 0x100, true);   // standard id
    can_test_msg(msg, 0x110, true);   // standard id
    can_test_msg(msg, 0x120, true);   // standard id
    can_test_msg(msg, 0x130, true);   // standard id
    can_test_msg(msg, 0x200, true);   // Start of standard ID group
    can_test_msg(msg, 0x210, true);   // Last of standard ID group
    can_test_msg(msg, 0x220, true);   // Start of standard ID group
    can_test_msg(msg, 0x230, true);   // Last of standard ID group

    msg.frame_fields.is_29bit = 1;
    can_test_msg(msg, 0x7500, true);   // extended id
    can_test_msg(msg, 0x8500, true);   // extended id
    can_test_msg(msg, 0xA000, true);   // extended id group start
    can_test_msg(msg, 0xB000, true);   // extended id group end

    u0_dbg_printf("  Test messages that should not be received\n");
    /* Send a message not defined in filter */
    msg.frame_fields.is_29bit = 0;
    can_test_msg(msg, 0x0FF, false);
    can_test_msg(msg, 0x111, false);
    can_test_msg(msg, 0x131, false);
    can_test_msg(msg, 0x1FF, false);
    can_test_msg(msg, 0x211, false);
    can_test_msg(msg, 0x21f, false);
    can_test_msg(msg, 0x231, false);

    msg.frame_fields.is_29bit = 1;
    can_test_msg(msg, 0x7501, false);
    can_test_msg(msg, 0x8501, false);
    can_test_msg(msg, 0xA000-1, false);
    can_test_msg(msg, 0xB000+1, false);

    /* Test FullCAN */
    u0_dbg_printf("  Test FullCAN\n");
    CAN_init(can1, 100, 5, 5, CAN_test_bufoff_cb, CAN_test_bufovr_cb);
    CAN_reset_bus(can1);
    id = 0x100;
    CAN_ASSERT(0 == CAN_fullcan_get_num_entries());

    CAN_ASSERT(CAN_fullcan_add_entry(can1, CAN_gen_sid(can1, id), CAN_gen_sid(can1, id+1)));
    CAN_ASSERT(2 == CAN_fullcan_get_num_entries());
    CAN_ASSERT(LPC_CANAF->SFF_sa     == 4);
    CAN_ASSERT(LPC_CANAF->SFF_GRP_sa == 4);
    CAN_ASSERT(LPC_CANAF->EFF_sa     == 4);
    CAN_ASSERT(LPC_CANAF->EFF_GRP_sa == 4);
    CAN_ASSERT(LPC_CANAF->ENDofTable == 4);

    CAN_ASSERT(CAN_fullcan_add_entry(can1, CAN_gen_sid(can1, id+2), CAN_gen_sid(can1, id+3)));
    CAN_ASSERT(4 == CAN_fullcan_get_num_entries());
    CAN_ASSERT(LPC_CANAF->SFF_sa     == 8);

    for ( i = 0; i < 3; i++) {
        u0_dbg_printf("%2i: 0x%08X\n", i, (uint32_t) LPC_CANAF_RAM->mask[i]);
    }

    can_fullcan_msg_t *fc1 = CAN_fullcan_get_entry_ptr(CAN_gen_sid(can1, id));
    can_fullcan_msg_t *fc2 = CAN_fullcan_get_entry_ptr(CAN_gen_sid(can1, id+1));
    can_fullcan_msg_t *fc3 = CAN_fullcan_get_entry_ptr(CAN_gen_sid(can1, id+2));
    can_fullcan_msg_t *fc4 = CAN_fullcan_get_entry_ptr(CAN_gen_sid(can1, id+3));
    CAN_ASSERT((LPC_CANAF_RAM_BASE + LPC_CANAF->SFF_sa) == (uint32_t)fc1);
    CAN_ASSERT((LPC_CANAF_RAM_BASE + LPC_CANAF->SFF_sa + 1*sizeof(can_fullcan_msg_t)) == (uint32_t)fc2);
    CAN_ASSERT((LPC_CANAF_RAM_BASE + LPC_CANAF->SFF_sa + 2*sizeof(can_fullcan_msg_t)) == (uint32_t)fc3);
    CAN_ASSERT((LPC_CANAF_RAM_BASE + LPC_CANAF->SFF_sa + 3*sizeof(can_fullcan_msg_t)) == (uint32_t)fc4);

    can_fullcan_msg_t fc_temp;
    CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc1, &fc_temp));
    CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc2, &fc_temp));
    CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc3, &fc_temp));
    CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc4, &fc_temp));

    /* Send message, see if fullcan captures it */
    msg.frame = 0;
    msg.msg_id = id;
    msg.frame_fields.is_29bit = 0;
    msg.frame_fields.data_len = 8;

    #define can_test_fullcan_msg(fc, msg_copy, id)              \
        do {                                                    \
        msg.msg_id = id;                                        \
        CAN_ASSERT(CAN_tx(can1, &msg, 0));                      \
        CAN_ASSERT(!CAN_rx(can1, &msg, 10));                    \
        CAN_ASSERT(CAN_fullcan_read_msg_copy(fc, &msg_copy));   \
        CAN_ASSERT(fc->msg_id == id)                            \
        } while(0)
    can_test_fullcan_msg(fc1, fc_temp, id+0);   CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc2, &fc_temp));
    can_test_fullcan_msg(fc2, fc_temp, id+1);   CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc3, &fc_temp));
    can_test_fullcan_msg(fc3, fc_temp, id+2);   CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc4, &fc_temp));
    can_test_fullcan_msg(fc4, fc_temp, id+3);   CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc1, &fc_temp));

    u0_dbg_printf("  \n--> All tests successful! <--\n");
    return true;
}
Beispiel #6
0
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;
}
Beispiel #7
0
bool CAN_test(void)
{
    #define CAN_TEST_RX 0

    CAN_ASSERT(!CAN_init(can_inv, 100, 0, 0, NULL, NULL));
    CAN_ASSERT(CAN_init(can1, 100, 0, 0, CAN_test_bufoff_cb, CAN_test_bufovr_cb));
    CAN_ASSERT(LPC_CAN1->MOD == can_mod_reset);
    CAN_ASSERT(g_can_rx_qs[0] != NULL);
    CAN_ASSERT(g_can_tx_qs[0] != NULL);
    CAN_ASSERT(LPC_CANAF->SFF_sa     == 0);
    CAN_ASSERT(LPC_CANAF->SFF_GRP_sa == 0);
    CAN_ASSERT(LPC_CANAF->EFF_sa     == 0);
    CAN_ASSERT(LPC_CANAF->EFF_GRP_sa == 0);
    CAN_ASSERT(LPC_CANAF->ENDofTable == 0);

    CAN_reset_bus(can1);
    CAN_ASSERT(LPC_CAN1->MOD == can_mod_normal);

    /* Send 11-bit CANID message */
    uint32_t id = 0x100;
    can_msg_t msg;
    msg.frame = 0;
    msg.msg_id = id;
    msg.frame_fields.is_29bit = 0;
    msg.frame_fields.data_len = 7;
    msg.data.qword = 0x1122334455667788;
    CAN_ASSERT(!CAN_tx(can_inv, &msg, 0));
    CAN_ASSERT(!CAN_rx(can1, &msg, 0));

    /* Send msg and test receive */
    CAN_ASSERT(CAN_tx(can1, &msg, 0));

#if CAN_TEST_RX
    memset(&msg, 0, sizeof(msg));
    CAN_ASSERT(CAN_rx(can1, &msg, 1000));
    CAN_ASSERT(msg.msg_id = id);
    CAN_ASSERT(!msg.frame_fields.is_29bit);
#endif

    /* Test filters */
    CAN_ASSERT(0 == CAN_fullcan_get_num_entries());
    CAN_ASSERT(CAN_fullcan_add_entry(can1, CAN_gen_sid(can1, id), CAN_gen_sid(can1, id+1)));
    CAN_ASSERT(2 == CAN_fullcan_get_num_entries());
    CAN_ASSERT(4 == LPC_CANAF->SFF_sa);

    can_fullcan_msg_t *fc1 = CAN_fullcan_get_entry_ptr(CAN_gen_sid(can1, id));
    can_fullcan_msg_t *fc2 = CAN_fullcan_get_entry_ptr(CAN_gen_sid(can1, id+1));
    CAN_ASSERT(0 != fc1);
    CAN_ASSERT(0 != fc2);

#if CAN_TEST_RX
    /* Send message, see if fullcan captures it */
    msg.frame = 0;
    msg.msg_id = id;
    msg.frame_fields.is_29bit = 0;
    msg.frame_fields.data_len = 8;

    can_fullcan_msg_t fc_temp;
    CAN_ASSERT(!CAN_fullcan_read_msg_copy(fc1, &fc_temp));
    CAN_ASSERT(CAN_tx(can1, &msg, 0));
    CAN_ASSERT(CAN_fullcan_read_msg_copy(fc1, &fc_temp));
    CAN_ASSERT(fc1->msg_id == id);
#endif

    const can_std_id_t slist[]      = { CAN_gen_sid(can1, 0x100), CAN_gen_sid(can1, 0x110),   // 2 entries
                                        CAN_gen_sid(can1, 0x120), CAN_gen_sid(can1, 0x130)    // 2 entries
    };
    const can_std_grp_id_t sglist[] = { {CAN_gen_sid(can1, 0x150), CAN_gen_sid(can1, 0x200)}, // Group 1
                                        {CAN_gen_sid(can2, 0x300), CAN_gen_sid(can2, 0x400)}  // Group 2
    };
    const can_ext_id_t *elist       = NULL; // Not used, so set it to NULL
    const can_ext_grp_id_t eglist[] = { {CAN_gen_eid(can1, 0x3500), CAN_gen_eid(can1, 0x4500)} }; // Group 1

    /* Test filter setup */
    CAN_setup_filter(slist, 4, sglist, 2, elist, 0, eglist, 1);

    CAN_ASSERT(2 == CAN_fullcan_get_num_entries());
    CAN_ASSERT(LPC_CANAF->SFF_sa     == 4);
    CAN_ASSERT(LPC_CANAF->SFF_GRP_sa == 12);
    CAN_ASSERT(LPC_CANAF->EFF_sa     == 20);
    CAN_ASSERT(LPC_CANAF->EFF_GRP_sa == 20);
    CAN_ASSERT(LPC_CANAF->ENDofTable == 28);

    /* Send a message defined in filter */

    /* Send a message not defined in filter */

    return true;
}