1*4cedf01cSMatthias Ringwald #include "CppUTest/TestHarness.h" 2*4cedf01cSMatthias Ringwald #include "CppUTest/CommandLineTestRunner.h" 3*4cedf01cSMatthias Ringwald #include "btstack_util.h" 4*4cedf01cSMatthias Ringwald #include "btstack_debug.h" 5*4cedf01cSMatthias Ringwald 6*4cedf01cSMatthias Ringwald // HFP H2 Sync 7*4cedf01cSMatthias Ringwald #include <string.h> 8*4cedf01cSMatthias Ringwald 9*4cedf01cSMatthias Ringwald #define HFP_H2_SYNC_FRAME_SIZE 60 10*4cedf01cSMatthias Ringwald 11*4cedf01cSMatthias Ringwald typedef struct { 12*4cedf01cSMatthias Ringwald // callback returns true if data was valid 13*4cedf01cSMatthias Ringwald bool (*callback)(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len); 14*4cedf01cSMatthias Ringwald uint8_t frame_data[HFP_H2_SYNC_FRAME_SIZE]; 15*4cedf01cSMatthias Ringwald uint16_t frame_len; 16*4cedf01cSMatthias Ringwald uint16_t dropped_bytes; 17*4cedf01cSMatthias Ringwald } hfp_h2_sync_t; 18*4cedf01cSMatthias Ringwald 19*4cedf01cSMatthias Ringwald // find position of h2 sync header, returns -1 if not found, or h2 sync position 20*4cedf01cSMatthias Ringwald static int16_t hfp_h2_sync_find(const uint8_t * frame_data, uint16_t frame_len){ 21*4cedf01cSMatthias Ringwald uint16_t i; 22*4cedf01cSMatthias Ringwald for (i=0;i<(frame_len - 1);i++){ 23*4cedf01cSMatthias Ringwald // check: first byte == 1 24*4cedf01cSMatthias Ringwald uint8_t h2_first_byte = frame_data[i]; 25*4cedf01cSMatthias Ringwald if (h2_first_byte == 0x01) { 26*4cedf01cSMatthias Ringwald uint8_t h2_second_byte = frame_data[i + 1]; 27*4cedf01cSMatthias Ringwald // check lower nibble of second byte == 0x08 28*4cedf01cSMatthias Ringwald if ((h2_second_byte & 0x0F) == 8) { 29*4cedf01cSMatthias Ringwald // check if bits 0+2 == bits 1+3 30*4cedf01cSMatthias Ringwald uint8_t hn = h2_second_byte >> 4; 31*4cedf01cSMatthias Ringwald if (((hn >> 1) & 0x05) == (hn & 0x05)) { 32*4cedf01cSMatthias Ringwald return (int16_t) i; 33*4cedf01cSMatthias Ringwald } 34*4cedf01cSMatthias Ringwald } 35*4cedf01cSMatthias Ringwald } 36*4cedf01cSMatthias Ringwald } 37*4cedf01cSMatthias Ringwald return -1; 38*4cedf01cSMatthias Ringwald } 39*4cedf01cSMatthias Ringwald 40*4cedf01cSMatthias Ringwald static void hfp_h2_sync_reset(hfp_h2_sync_t * hfp_h2_sync){ 41*4cedf01cSMatthias Ringwald hfp_h2_sync->frame_len = 0; 42*4cedf01cSMatthias Ringwald } 43*4cedf01cSMatthias Ringwald 44*4cedf01cSMatthias Ringwald void hfp_h2_sync_init(hfp_h2_sync_t * hfp_h2_sync, 45*4cedf01cSMatthias Ringwald bool (*callback)(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len)){ 46*4cedf01cSMatthias Ringwald hfp_h2_sync->callback = callback; 47*4cedf01cSMatthias Ringwald hfp_h2_sync->dropped_bytes = 0; 48*4cedf01cSMatthias Ringwald hfp_h2_sync_reset(hfp_h2_sync); 49*4cedf01cSMatthias Ringwald } 50*4cedf01cSMatthias Ringwald 51*4cedf01cSMatthias Ringwald static void hfp_h2_report_bad_frames(hfp_h2_sync_t *hfp_h2_sync){ 52*4cedf01cSMatthias Ringwald // report bad frames 53*4cedf01cSMatthias Ringwald while (hfp_h2_sync->dropped_bytes >= HFP_H2_SYNC_FRAME_SIZE){ 54*4cedf01cSMatthias Ringwald hfp_h2_sync->dropped_bytes -= HFP_H2_SYNC_FRAME_SIZE; 55*4cedf01cSMatthias Ringwald (void)(*hfp_h2_sync->callback)(true,NULL, HFP_H2_SYNC_FRAME_SIZE); 56*4cedf01cSMatthias Ringwald } 57*4cedf01cSMatthias Ringwald } 58*4cedf01cSMatthias Ringwald 59*4cedf01cSMatthias Ringwald static void hfp_h2_sync_drop_bytes(hfp_h2_sync_t * hfp_h2_sync, uint16_t bytes_to_drop){ 60*4cedf01cSMatthias Ringwald btstack_assert(bytes_to_drop <= hfp_h2_sync->frame_len); 61*4cedf01cSMatthias Ringwald memmove(hfp_h2_sync->frame_data, &hfp_h2_sync->frame_data[bytes_to_drop], hfp_h2_sync->frame_len - bytes_to_drop); 62*4cedf01cSMatthias Ringwald hfp_h2_sync->dropped_bytes += bytes_to_drop; 63*4cedf01cSMatthias Ringwald hfp_h2_sync->frame_len -= bytes_to_drop; 64*4cedf01cSMatthias Ringwald hfp_h2_report_bad_frames(hfp_h2_sync); 65*4cedf01cSMatthias Ringwald } 66*4cedf01cSMatthias Ringwald 67*4cedf01cSMatthias Ringwald void hfp_h2_sync_process(hfp_h2_sync_t *hfp_h2_sync, bool bad_frame, const uint8_t *frame_data, uint16_t frame_len) { 68*4cedf01cSMatthias Ringwald 69*4cedf01cSMatthias Ringwald if (bad_frame){ 70*4cedf01cSMatthias Ringwald // drop all data 71*4cedf01cSMatthias Ringwald hfp_h2_sync->dropped_bytes += hfp_h2_sync->frame_len; 72*4cedf01cSMatthias Ringwald hfp_h2_sync->frame_len = 0; 73*4cedf01cSMatthias Ringwald // all new data is bad, too 74*4cedf01cSMatthias Ringwald hfp_h2_sync->dropped_bytes += frame_len; 75*4cedf01cSMatthias Ringwald // report frames 76*4cedf01cSMatthias Ringwald hfp_h2_report_bad_frames(hfp_h2_sync); 77*4cedf01cSMatthias Ringwald return; 78*4cedf01cSMatthias Ringwald } 79*4cedf01cSMatthias Ringwald 80*4cedf01cSMatthias Ringwald while (frame_len > 0){ 81*4cedf01cSMatthias Ringwald // Fill hfp_h2_sync->frame_buffer 82*4cedf01cSMatthias Ringwald uint16_t bytes_free_in_frame_buffer = HFP_H2_SYNC_FRAME_SIZE - hfp_h2_sync->frame_len; 83*4cedf01cSMatthias Ringwald uint16_t bytes_to_append = btstack_min(frame_len, bytes_free_in_frame_buffer); 84*4cedf01cSMatthias Ringwald memcpy(&hfp_h2_sync->frame_data[hfp_h2_sync->frame_len], frame_data, bytes_to_append); 85*4cedf01cSMatthias Ringwald frame_data += bytes_to_append; 86*4cedf01cSMatthias Ringwald frame_len -= bytes_to_append; 87*4cedf01cSMatthias Ringwald hfp_h2_sync->frame_len += bytes_to_append; 88*4cedf01cSMatthias Ringwald // check complete frame for h2 sync 89*4cedf01cSMatthias Ringwald if (hfp_h2_sync->frame_len == HFP_H2_SYNC_FRAME_SIZE){ 90*4cedf01cSMatthias Ringwald bool valid_frame = true; 91*4cedf01cSMatthias Ringwald int16_t h2_pos = hfp_h2_sync_find(hfp_h2_sync->frame_data, hfp_h2_sync->frame_len); 92*4cedf01cSMatthias Ringwald if (h2_pos < 0){ 93*4cedf01cSMatthias Ringwald // no h2 sync, no valid frame, keep last byte if it is 0x01 94*4cedf01cSMatthias Ringwald if (hfp_h2_sync->frame_data[HFP_H2_SYNC_FRAME_SIZE-1] == 0x01){ 95*4cedf01cSMatthias Ringwald hfp_h2_sync_drop_bytes(hfp_h2_sync, HFP_H2_SYNC_FRAME_SIZE - 1); 96*4cedf01cSMatthias Ringwald } else { 97*4cedf01cSMatthias Ringwald hfp_h2_sync_drop_bytes(hfp_h2_sync, HFP_H2_SYNC_FRAME_SIZE); 98*4cedf01cSMatthias Ringwald } 99*4cedf01cSMatthias Ringwald valid_frame = false; 100*4cedf01cSMatthias Ringwald } 101*4cedf01cSMatthias Ringwald else if (h2_pos > 0){ 102*4cedf01cSMatthias Ringwald // drop data before h2 sync 103*4cedf01cSMatthias Ringwald hfp_h2_sync_drop_bytes(hfp_h2_sync, h2_pos); 104*4cedf01cSMatthias Ringwald valid_frame = false; 105*4cedf01cSMatthias Ringwald } 106*4cedf01cSMatthias Ringwald if (valid_frame) { 107*4cedf01cSMatthias Ringwald // h2 sync at pos 0 and complete frame 108*4cedf01cSMatthias Ringwald bool codec_ok = (*hfp_h2_sync->callback)(false, hfp_h2_sync->frame_data, hfp_h2_sync->frame_len); 109*4cedf01cSMatthias Ringwald if (codec_ok){ 110*4cedf01cSMatthias Ringwald hfp_h2_sync_reset(hfp_h2_sync); 111*4cedf01cSMatthias Ringwald } else { 112*4cedf01cSMatthias Ringwald // drop first two bytes 113*4cedf01cSMatthias Ringwald hfp_h2_sync_drop_bytes(hfp_h2_sync, 2); 114*4cedf01cSMatthias Ringwald } 115*4cedf01cSMatthias Ringwald } 116*4cedf01cSMatthias Ringwald } 117*4cedf01cSMatthias Ringwald } 118*4cedf01cSMatthias Ringwald } 119*4cedf01cSMatthias Ringwald 120*4cedf01cSMatthias Ringwald // Test 121*4cedf01cSMatthias Ringwald static uint8_t test_data[HFP_H2_SYNC_FRAME_SIZE]; 122*4cedf01cSMatthias Ringwald static uint8_t test_valid_sbc_frame[HFP_H2_SYNC_FRAME_SIZE]; 123*4cedf01cSMatthias Ringwald static uint8_t test_invalid_sbc_frame[HFP_H2_SYNC_FRAME_SIZE]; 124*4cedf01cSMatthias Ringwald static uint8_t test_invalid_frame[HFP_H2_SYNC_FRAME_SIZE]; 125*4cedf01cSMatthias Ringwald static hfp_h2_sync_t test_hfp_h2_sync; 126*4cedf01cSMatthias Ringwald static uint8_t test_num_good_frames; 127*4cedf01cSMatthias Ringwald static uint8_t test_num_bad_frames; 128*4cedf01cSMatthias Ringwald 129*4cedf01cSMatthias Ringwald static bool test_hfp_h2_sync_callback(bool bad_frame, const uint8_t * frame_data, uint16_t frame_len){ 130*4cedf01cSMatthias Ringwald btstack_assert(frame_len == HFP_H2_SYNC_FRAME_SIZE); 131*4cedf01cSMatthias Ringwald if (bad_frame){ 132*4cedf01cSMatthias Ringwald test_num_bad_frames++; 133*4cedf01cSMatthias Ringwald return false; 134*4cedf01cSMatthias Ringwald } else { 135*4cedf01cSMatthias Ringwald // mSBC frame ok <=> sync word = 0xAD 136*4cedf01cSMatthias Ringwald if (frame_data[2] == 0xAD) { 137*4cedf01cSMatthias Ringwald test_num_good_frames++; 138*4cedf01cSMatthias Ringwald return true; 139*4cedf01cSMatthias Ringwald } 140*4cedf01cSMatthias Ringwald } 141*4cedf01cSMatthias Ringwald return false; 142*4cedf01cSMatthias Ringwald } 143*4cedf01cSMatthias Ringwald 144*4cedf01cSMatthias Ringwald TEST_GROUP(HFP_H2_SYNC){ 145*4cedf01cSMatthias Ringwald void setup(void){ 146*4cedf01cSMatthias Ringwald test_num_good_frames = 0; 147*4cedf01cSMatthias Ringwald test_num_bad_frames = 0; 148*4cedf01cSMatthias Ringwald test_valid_sbc_frame[0] = 0x01; 149*4cedf01cSMatthias Ringwald test_valid_sbc_frame[1] = 0x08; 150*4cedf01cSMatthias Ringwald test_valid_sbc_frame[2] = 0xAD; 151*4cedf01cSMatthias Ringwald test_invalid_sbc_frame[0] = 0x01; 152*4cedf01cSMatthias Ringwald test_invalid_sbc_frame[1] = 0x08; 153*4cedf01cSMatthias Ringwald test_invalid_sbc_frame[2] = 0xFF; 154*4cedf01cSMatthias Ringwald hfp_h2_sync_init(&test_hfp_h2_sync, &test_hfp_h2_sync_callback); 155*4cedf01cSMatthias Ringwald } 156*4cedf01cSMatthias Ringwald void teardown(void){ 157*4cedf01cSMatthias Ringwald } 158*4cedf01cSMatthias Ringwald }; 159*4cedf01cSMatthias Ringwald 160*4cedf01cSMatthias Ringwald // initial setting 161*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, ValidSBCFrame){ 162*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_valid_sbc_frame, sizeof(test_valid_sbc_frame)); 163*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_good_frames); 164*4cedf01cSMatthias Ringwald } 165*4cedf01cSMatthias Ringwald 166*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, ValidSBCFramefter59){ 167*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_invalid_frame, sizeof(test_invalid_frame)-1); 168*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_valid_sbc_frame, sizeof(test_valid_sbc_frame)); 169*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_good_frames); 170*4cedf01cSMatthias Ringwald } 171*4cedf01cSMatthias Ringwald 172*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, ValidSBCFrameAfter2){ 173*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_invalid_frame, 2); 174*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_valid_sbc_frame, sizeof(test_valid_sbc_frame)); 175*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_good_frames); 176*4cedf01cSMatthias Ringwald CHECK_EQUAL(2, test_hfp_h2_sync.dropped_bytes); 177*4cedf01cSMatthias Ringwald } 178*4cedf01cSMatthias Ringwald 179*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, BadAndGoodFrame){ 180*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_invalid_frame, sizeof(test_invalid_frame)); 181*4cedf01cSMatthias Ringwald CHECK_EQUAL(0, test_num_good_frames); 182*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_valid_sbc_frame, sizeof(test_valid_sbc_frame)); 183*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_bad_frames); 184*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_good_frames); 185*4cedf01cSMatthias Ringwald } 186*4cedf01cSMatthias Ringwald 187*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, BadFrameFlagA){ 188*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_valid_sbc_frame, sizeof(test_data) - 1); 189*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, true, test_valid_sbc_frame, 1); 190*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_bad_frames); 191*4cedf01cSMatthias Ringwald } 192*4cedf01cSMatthias Ringwald 193*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, BadFrameFlagB){ 194*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, true, test_valid_sbc_frame, sizeof(test_valid_sbc_frame)); 195*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_bad_frames); 196*4cedf01cSMatthias Ringwald } 197*4cedf01cSMatthias Ringwald 198*4cedf01cSMatthias Ringwald TEST(HFP_H2_SYNC, InvalidSBCFrame){ 199*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_invalid_sbc_frame, sizeof(test_invalid_sbc_frame)); 200*4cedf01cSMatthias Ringwald hfp_h2_sync_process(&test_hfp_h2_sync, false, test_invalid_frame, 2); 201*4cedf01cSMatthias Ringwald CHECK_EQUAL(1, test_num_bad_frames); 202*4cedf01cSMatthias Ringwald CHECK_EQUAL(0, test_num_good_frames); 203*4cedf01cSMatthias Ringwald } 204*4cedf01cSMatthias Ringwald 205*4cedf01cSMatthias Ringwald int main (int argc, const char * argv[]){ 206*4cedf01cSMatthias Ringwald return CommandLineTestRunner::RunAllTests(argc, argv); 207*4cedf01cSMatthias Ringwald } 208