#include #include #include #include "trikke_ble_protocol.h" #include "trikke_protocol.h" static int fail(int code, const char *message) { fprintf(stderr, "BLE protocol fixture failure %d: %s\n", code, message); return code; } static void put_u16_le(uint8_t *output, uint16_t value) { output[0] = (uint8_t)value; output[1] = (uint8_t)(value >> 8); } static void put_u32_le(uint8_t *output, uint32_t value) { output[0] = (uint8_t)value; output[1] = (uint8_t)(value >> 8); output[2] = (uint8_t)(value >> 16); output[3] = (uint8_t)(value >> 24); } int main(void) { uint8_t packet[TRIKKE_WIRE_HEADER_SIZE + 16] = {0}; memcpy(packet, "TRK1", 4); packet[4] = TRIKKE_WIRE_VERSION; packet[6] = TRIKKE_WIRE_HEADER_SIZE; put_u16_le(packet + 10, 16); put_u32_le(packet + 12, 0x78563412); for (size_t i = TRIKKE_WIRE_HEADER_SIZE; i < sizeof(packet); ++i) { packet[i] = (uint8_t)i; } uint8_t fragment[32] = {0}; size_t size = trikke_ble_encode_fragment( fragment, sizeof(fragment), packet, sizeof(packet), 0, 20); if (size != 20 || memcmp(fragment, "\x12\x34\x56\x78\x00\x00\x34\x00", 8) != 0 || memcmp(fragment + 8, packet, 12) != 0) { return fail(1, "first fragment envelope"); } size = trikke_ble_encode_fragment( fragment, sizeof(fragment), packet, sizeof(packet), 48, 20); if (size != 12 || fragment[4] != 48 || memcmp(fragment + 8, packet + 48, 4) != 0) { return fail(2, "last fragment envelope"); } uint8_t ack[TRIKKE_BLE_ACK_SIZE] = {'A', 'C', 'K', '1', 0x12, 0x34, 0x56, 0x78}; uint32_t sequence = 0; if (!trikke_ble_decode_ack(ack, sizeof(ack), &sequence) || sequence != 0x78563412) { return fail(3, "ACK decoding"); } ack[0] = 'N'; if (trikke_ble_decode_ack(ack, sizeof(ack), &sequence) || trikke_ble_encode_fragment(fragment, sizeof(fragment), packet, sizeof(packet), sizeof(packet), 20) != 0 || trikke_ble_encode_fragment(fragment, sizeof(fragment), packet, sizeof(packet), 0, 8) != 0) { return fail(4, "invalid input rejection"); } const uint8_t begin[TRIKKE_BLE_BEGIN_SESSION_SIZE] = { 'B', 'G', 'N', '1', 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, }; uint64_t session_token = 0; if (!trikke_ble_decode_begin_session( begin, sizeof(begin), &session_token) || session_token != UINT64_C(0x0102030405060708)) { return fail(5, "begin-session decoding"); } uint8_t invalid_begin[TRIKKE_BLE_BEGIN_SESSION_SIZE] = {0}; memcpy(invalid_begin, begin, sizeof(begin)); invalid_begin[3] = '2'; if (trikke_ble_decode_begin_session( invalid_begin, sizeof(invalid_begin), &session_token) || trikke_ble_decode_begin_session( begin, sizeof(begin) - 1, &session_token)) { return fail(6, "invalid begin-session rejection"); } bool subscribed = false; if (trikke_ble_update_subscription(true, false, &subscribed) || subscribed || !trikke_ble_update_subscription(true, true, &subscribed) || !subscribed) { return fail(7, "CCCD-before-control subscription ordering"); } subscribed = false; if (trikke_ble_update_subscription(false, true, &subscribed) || subscribed || !trikke_ble_update_subscription(true, true, &subscribed) || !subscribed || !trikke_ble_update_subscription(false, true, &subscribed) || subscribed) { return fail(8, "control-before-CCCD subscription ordering"); } return 0; }