123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374 |
- /*
- * Copyright (c) 2016-2019 UAVCAN Team
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- *
- * Contributors: https://github.com/UAVCAN/libcanard/contributors
- */
- #include <catch.hpp>
- #include <canard.h>
- //Independent implementation of ID layout from https://uavcan.org/Specification/4._CAN_bus_transport_layer/
- #define CONSTRUCT_PRIO(prio) (((prio) & 0x1F) << 24)
- #define CONSTRUCT_MTID(mtid) (((mtid) & 0xFFFF) << 8)
- #define CONSTRUCT_SID(sid) (((sid) & 0x7F))
- #define CONSTRUCT_DISC(disc) (((disc) & 0x3FFF) << 10)
- #define CONSTRUCT_DISC_MTID(mtid) (((mtid) & 0x3) << 8)
- #define CONSTRUCT_STID(stid) (((stid) & 0xFF) << 16)
- #define CONSTRUCT_DID(did) (((did) & 0x7F) << 8)
- #define CONSTRUCT_REQUEST(request) (((request) & 0x1) << 15)
- #define CONSTRUCT_SNM_BIT (1 << 7)
- #define CONSTRUCT_ANON_MSG_ID(prio, disc, mtid, sid) (CONSTRUCT_PRIO(prio) | \
- CONSTRUCT_DISC_MTID(mtid) | \
- CONSTRUCT_DISC(disc) | \
- CONSTRUCT_SID(sid) \
- CANARD_CAN_FRAME_EFF)
- #define CONSTRUCT_MSG_ID(prio, mtid, sid) (CONSTRUCT_PRIO(prio) | \
- CONSTRUCT_MTID(mtid) | \
- CONSTRUCT_SID(sid) | \
- CANARD_CAN_FRAME_EFF)
- #define CONSTRUCT_SVC_ID(prio, stid, request, did, sid) (CONSTRUCT_PRIO(prio) | \
- CONSTRUCT_STID(stid) | \
- CONSTRUCT_REQUEST(request) | \
- CONSTRUCT_DID(did) | \
- CONSTRUCT_SID(sid) | \
- CONSTRUCT_SNM_BIT | \
- CANARD_CAN_FRAME_EFF)
- #define CONSTRUCT_START(start) (((start) & 0x1) << 7)
- #define CONSTRUCT_END(end) (((end) & 0x1) << 6)
- #define CONSTRUCT_TOGGLE(toggle) (((toggle) & 0x1) << 5)
- #define CONSTRUCT_TID(tid) (((tid) & 0x1F))
- #define CONSTRUCT_TAIL_BYTE(start, end, toggle, tid) (CONSTRUCT_START(start) | \
- CONSTRUCT_END(end) | \
- CONSTRUCT_TOGGLE(toggle) | \
- CONSTRUCT_TID(tid))
- static bool g_should_accept = true;
- /**
- * This callback is invoked by the library when a new message or request or response is received.
- */
- static void onTransferReceived(CanardInstance* ins,
- CanardRxTransfer* transfer)
- {
- (void)ins;
- (void)transfer;
- }
- static bool shouldAcceptTransfer(const CanardInstance* ins,
- uint64_t* out_data_type_signature,
- uint16_t data_type_id,
- CanardTransferType transfer_type,
- uint8_t source_node_id)
- {
- (void)ins;
- (void)out_data_type_signature;
- (void)data_type_id;
- (void)transfer_type;
- (void)source_node_id;
- return g_should_accept;
- }
- TEST_CASE("canardHandleRxFrame incompatible packet handling, Correctness")
- {
- uint8_t canard_memory_pool[1024];
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- //Setup frame data to be single frame transfer
- frame.data[0] = CONSTRUCT_TAIL_BYTE(1, 1, 0, 0);
- canardInit(&canard, canard_memory_pool, sizeof(canard_memory_pool),
- onTransferReceived, shouldAcceptTransfer, &canard);
- g_should_accept = true;
- //Frame with good RTR/ERR/data_len bad EFF
- frame.id = 0;
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_INCOMPATIBLE_PACKET == err);
- //Frame with good EFF/ERR/data_len, bad RTR
- frame.id = 0 | CANARD_CAN_FRAME_RTR | CANARD_CAN_FRAME_EFF;
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_INCOMPATIBLE_PACKET == err);
- //Frame with good EFF/RTR/data_len, bad ERR
- frame.id = 0 | CANARD_CAN_FRAME_ERR | CANARD_CAN_FRAME_EFF;
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_INCOMPATIBLE_PACKET == err);
- //Frame with good EFF/RTR/ERR, bad data_len
- frame.id = 0 | CANARD_CAN_FRAME_EFF;
- frame.data_len = 0;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_INCOMPATIBLE_PACKET == err);
- //Frame with good EFF/RTR/ERR/data_len
- frame.id = 0 | CANARD_CAN_FRAME_EFF;
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- }
- TEST_CASE("canardHandleRxFrame wrong address handling, Correctness")
- {
- uint8_t canard_memory_pool[1024];
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- //Setup frame data to be single frame transfer
- frame.data[0] = CONSTRUCT_TAIL_BYTE(1, 1, 0, 0);
- //Open canard to accept all transfers with a node ID of 20
- canardInit(&canard, canard_memory_pool, sizeof(canard_memory_pool),
- onTransferReceived, shouldAcceptTransfer, &canard);
- canardSetLocalNodeID(&canard, 20);
- g_should_accept = true;
- //Send package with ID 24, should not be wanted
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 24, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_WRONG_ADDRESS == err);
- //Send package with ID 20, should be OK
- frame.id = 0 | CANARD_CAN_FRAME_EFF; //Set EFF
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- }
- TEST_CASE("canardHandleRxFrame shouldAccept handling, Correctness")
- {
- uint8_t canard_memory_pool[1024];
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- //Setup frame data to be single frame transfer
- frame.data[0] = CONSTRUCT_TAIL_BYTE(1, 1, 0, 0);
- //Open canard to accept all transfers with a node ID of 20
- canardInit(&canard, canard_memory_pool, sizeof(canard_memory_pool),
- onTransferReceived, shouldAcceptTransfer, &canard);
- canardSetLocalNodeID(&canard, 20);
- //Send packet, don't accept
- g_should_accept = false;
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_NOT_WANTED == err);
- //Send packet, accept
- g_should_accept = true;
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- }
- TEST_CASE("canardHandleRxFrame no state handling, Correctness")
- {
- uint8_t canard_memory_pool[1024];
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- g_should_accept = true;
- //Open canard to accept all transfers with a node ID of 20
- canardInit(&canard, canard_memory_pool, sizeof(canard_memory_pool),
- onTransferReceived, shouldAcceptTransfer, &canard);
- canardSetLocalNodeID(&canard, 20);
- //Not start or end of packet, should fail
- frame.data[0] = CONSTRUCT_TAIL_BYTE(0, 0, 0, 0);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_MISSED_START == err);
- //End of packet, should fail
- frame.data[0] = CONSTRUCT_TAIL_BYTE(0, 1, 0, 0);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_MISSED_START == err);
- //1 Frame packet, should pass
- frame.data[0] = CONSTRUCT_TAIL_BYTE(1, 1, 0, 0);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- //Send a start packet, should pass
- frame.data[7] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- //Send a middle packet, from the same ID, but don't toggle
- frame.data[0] = CONSTRUCT_TAIL_BYTE(0, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 1;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_WRONG_TOGGLE == err);
- //Send a middle packet, toggle, but use wrong ID
- frame.data[7] = CONSTRUCT_TAIL_BYTE(0, 0, 1, 2);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_UNEXPECTED_TID == err);
- //Send a middle packet, toggle, and use correct ID
- frame.data[7] = CONSTRUCT_TAIL_BYTE(0, 0, 1, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8;
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- }
- TEST_CASE("canardHandleRxFrame missed start handling, Correctness")
- {
- uint8_t canard_memory_pool[1024];
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- g_should_accept = true;
- //Open canard to accept all transfers with a node ID of 20
- canardInit(&canard, canard_memory_pool, sizeof(canard_memory_pool),
- onTransferReceived, shouldAcceptTransfer, &canard);
- canardSetLocalNodeID(&canard, 20);
- //Send a start packet, should pass
- frame.data[7] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- //Send a middle packet, toggle, and use correct ID - but timeout
- frame.data[7] = CONSTRUCT_TAIL_BYTE(0, 0, 1, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8;
- err = canardHandleRxFrame(&canard, &frame, 4000000);
- REQUIRE(-CANARD_ERROR_RX_MISSED_START == err);
- //Send a start packet, should pass
- frame.data[7] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- //Send a middle packet, toggle, and use correct ID - but timestamp 0
- frame.data[7] = CONSTRUCT_TAIL_BYTE(0, 0, 1, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8;
- err = canardHandleRxFrame(&canard, &frame, 0);
- REQUIRE(-CANARD_ERROR_RX_MISSED_START == err);
- //Send a start packet, should pass
- frame.data[7] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(CANARD_OK == err);
- //Send a middle packet, toggle, and use an incorrect TID
- frame.data[7] = CONSTRUCT_TAIL_BYTE(0, 0, 1, 3);
- frame.data[7] = 0 | 3 | (1<<5);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8;
- err = canardHandleRxFrame(&canard, &frame, 0);
- REQUIRE(-CANARD_ERROR_RX_MISSED_START == err);
- }
- TEST_CASE("canardHandleRxFrame short frame handling, Correctness")
- {
- uint8_t canard_memory_pool[1024];
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- g_should_accept = true;
- //Open canard to accept all transfers with a node ID of 20
- canardInit(&canard, canard_memory_pool, sizeof(canard_memory_pool),
- onTransferReceived, shouldAcceptTransfer, &canard);
- canardSetLocalNodeID(&canard, 20);
- //Send a start packet which is short, should fail
- frame.data[1] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 2; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_SHORT_FRAME == err);
- //Send a start packet which is short, should fail
- frame.data[2] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 3; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_RX_SHORT_FRAME == err);
- }
- TEST_CASE("canardHandleRxFrame OOM handling, Correctness")
- {
- uint8_t dummy_buf;
- CanardInstance canard;
- CanardCANFrame frame;
- int16_t err;
- g_should_accept = true;
- //Open canard to accept all transfers with a node ID of 20
- canardInit(&canard, &dummy_buf, 0,
- onTransferReceived, shouldAcceptTransfer, &canard);
- canardSetLocalNodeID(&canard, 20);
- //Send a start packet - we shouldn't have any memory
- frame.data[7] = CONSTRUCT_TAIL_BYTE(1, 0, 0, 1);
- frame.id = CONSTRUCT_SVC_ID(0, 0, 1, 20, 0);
- frame.data_len = 8; //Data length MUST be full packet
- err = canardHandleRxFrame(&canard, &frame, 1);
- REQUIRE(-CANARD_ERROR_OUT_OF_MEMORY == err);
- }
|