/ EyeLights_Bluetooth_Scroller / packetParser.cpp
packetParser.cpp
1 // SPDX-FileCopyrightText: 2021 Phillip Burgess for Adafruit Industries 2 // 3 // SPDX-License-Identifier: MIT 4 5 #include <bluefruit.h> 6 7 // packetbuffer holds inbound data 8 #define READ_BUFSIZE 20 9 uint8_t packetbuffer[READ_BUFSIZE + 1]; // +1 is for NUL string terminator 10 11 /**************************************************************************/ 12 /*! 13 @brief Casts the four bytes at the specified address to a float. 14 @param ptr Pointer into packet buffer. 15 @returns Floating-point value. 16 */ 17 /**************************************************************************/ 18 float parsefloat(uint8_t *ptr) { 19 float f; // Make a suitably-aligned float variable, 20 memcpy(&f, ptr, 4); // because in-buffer instance might be misaligned! 21 return f; // (You can't always safely parse in-place) 22 } 23 24 /**************************************************************************/ 25 /*! 26 @brief Prints a series of bytes in 0xNN hexadecimal notation. 27 @param buf Pointer to array of byte data. 28 @param len Data length in bytes. 29 */ 30 /**************************************************************************/ 31 void printHex(const uint8_t *buf, const uint32_t len) { 32 for (uint32_t i=0; i < len; i++) { 33 Serial.print(F("0x")); 34 if (buf[i] <= 0xF) Serial.write('0'); // Zero-pad small values 35 Serial.print(buf[i], HEX); 36 if (i < (len - 1)) Serial.write(' '); // Space between bytes 37 } 38 Serial.println(); 39 } 40 41 static const struct { // Special payloads from Bluefruit Connect app... 42 char id; // Packet type identifier 43 uint8_t len; // Size of complete, well-formed packet of this type 44 } _app_packet[] = { 45 {'A', 15}, // Accelerometer 46 {'G', 15}, // Gyro 47 {'M', 15}, // Magnetometer 48 {'Q', 19}, // Quaterion 49 {'B', 5}, // Button 50 {'C', 6}, // Color 51 {'L', 15}, // Location 52 }; 53 #define NUM_PACKET_TYPES (sizeof _app_packet / sizeof _app_packet[0]) 54 #define SHORTEST_PACKET_LEN 5 // Button, for now 55 56 /**************************************************************************/ 57 /*! 58 @brief Given packet data, identify if it's one of the known 59 Bluefruit Connect app packet types. 60 @param buf Pointer to packet data. 61 @param len Size of packet in bytes. 62 @returns Packet type index (0 to NUM_PACKET_TYPES-1) if recognized, 63 -1 if unrecognized. 64 */ 65 /**************************************************************************/ 66 int8_t packetType(uint8_t *buf, uint8_t len) { 67 if ((len >= SHORTEST_PACKET_LEN) && (buf[0] == '!')) { 68 for (int8_t type=0; type<NUM_PACKET_TYPES; type++) { 69 if ((buf[1] == _app_packet[type].id) && 70 (len == _app_packet[type].len)) { 71 return type; 72 } 73 } 74 } 75 return -1; // Length too short for a packet, or not a recognized type 76 } 77 78 /**************************************************************************/ 79 /*! 80 @brief Wait for incoming data and determine if it's one of the 81 special Bluefruit Connect app packet types. 82 @param ble Pointer to BLE UART object. 83 timeout Character read timeout in milliseconds. 84 @returns Length of data, or 0 if checksum is invalid for the type of 85 packet detected. 86 @note Packet buffer is not cleared. Calling function is expected 87 to check return value before deciding whether to act on the 88 data. 89 */ 90 /**************************************************************************/ 91 uint8_t readPacket(BLEUart *ble, uint16_t timeout) { 92 int8_t type = -1; // App packet type, -1 if unknown or freeform string 93 uint8_t len = 0, xsum = 255; // Packet length and ~checksum so far 94 uint32_t now, start_time = millis(); 95 do { 96 now = millis(); 97 if (ble->available()) { 98 char c = ble->read(); 99 if (c == '!') { // '!' resets buffer to start 100 len = 0; 101 xsum = 255; 102 } 103 packetbuffer[len++] = c; 104 // Stop when buffer's full or packet type recognized 105 if ((len >= READ_BUFSIZE) || 106 ((type = packetType(packetbuffer, len)) >= 0)) break; 107 start_time = now; // Reset timeout on char received 108 xsum -= c; // Not last char, do checksum math 109 type = -1; // Reset packet type finder 110 } 111 } while((now - start_time) < timeout); 112 113 // If packet type recognized, verify checksum (else freeform string) 114 if ((type >= 0) && (xsum != packetbuffer[len-1])) { // Last byte = checksum 115 Serial.print("Packet checksum mismatch: "); 116 printHex(packetbuffer, len); 117 return 0; 118 } 119 120 packetbuffer[len] = 0; // Terminate packet string 121 122 return len; // Checksum is valid for packet, or it's a freeform string 123 }