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