ducky's telemetry library

Committer:
ikrase
Date:
Tue Mar 31 19:56:00 2015 +0000
Revision:
0:aaa75ea6d346
imported telemetry, added include guard to telemetry-mbed.h

Who changed what in which revision?

UserRevisionLine numberNew contents of line
ikrase 0:aaa75ea6d346 1 #ifndef _TELEMETRY_H_
ikrase 0:aaa75ea6d346 2 #define _TELEMETRY_H_
ikrase 0:aaa75ea6d346 3
ikrase 0:aaa75ea6d346 4 #include <stddef.h>
ikrase 0:aaa75ea6d346 5 #include <stdint.h>
ikrase 0:aaa75ea6d346 6
ikrase 0:aaa75ea6d346 7 namespace telemetry {
ikrase 0:aaa75ea6d346 8
ikrase 0:aaa75ea6d346 9 #ifndef TELEMETRY_DATA_LIMIT
ikrase 0:aaa75ea6d346 10 #define TELEMETRY_DATA_LIMIT 16
ikrase 0:aaa75ea6d346 11 #endif
ikrase 0:aaa75ea6d346 12
ikrase 0:aaa75ea6d346 13 // Maximum number of DataInterface objects a Telemetry object can hold.
ikrase 0:aaa75ea6d346 14 // Used for array sizing.
ikrase 0:aaa75ea6d346 15 const size_t MAX_DATA_PER_TELEMETRY = TELEMETRY_DATA_LIMIT;
ikrase 0:aaa75ea6d346 16
ikrase 0:aaa75ea6d346 17 // Maximum payload size for a received telemetry packet.
ikrase 0:aaa75ea6d346 18 const size_t MAX_RECEIVE_PACKET_LENGTH = 255;
ikrase 0:aaa75ea6d346 19
ikrase 0:aaa75ea6d346 20 // Various wire protocol constants.
ikrase 0:aaa75ea6d346 21 const uint8_t SOF1 = 0x05; // start of frame byte 1
ikrase 0:aaa75ea6d346 22 const uint8_t SOF2 = 0x39; // start of frame byte 2
ikrase 0:aaa75ea6d346 23 const uint8_t SOF_SEQ[] = {0x05, 0x39};
ikrase 0:aaa75ea6d346 24
ikrase 0:aaa75ea6d346 25 const size_t LENGTH_SIZE = 2;
ikrase 0:aaa75ea6d346 26
ikrase 0:aaa75ea6d346 27 // TODO: make these length independent
ikrase 0:aaa75ea6d346 28
ikrase 0:aaa75ea6d346 29 const uint8_t OPCODE_HEADER = 0x81;
ikrase 0:aaa75ea6d346 30 const uint8_t OPCODE_DATA = 0x01;
ikrase 0:aaa75ea6d346 31
ikrase 0:aaa75ea6d346 32 const uint8_t DATAID_TERMINATOR = 0x00;
ikrase 0:aaa75ea6d346 33
ikrase 0:aaa75ea6d346 34 const uint8_t DATATYPE_NUMERIC = 0x01;
ikrase 0:aaa75ea6d346 35 const uint8_t DATATYPE_NUMERIC_ARRAY = 0x02;
ikrase 0:aaa75ea6d346 36
ikrase 0:aaa75ea6d346 37 const uint8_t RECORDID_TERMINATOR = 0x00;
ikrase 0:aaa75ea6d346 38 const uint8_t RECORDID_INTERNAL_NAME = 0x01;
ikrase 0:aaa75ea6d346 39 const uint8_t RECORDID_DISPLAY_NAME = 0x02;
ikrase 0:aaa75ea6d346 40 const uint8_t RECORDID_UNITS = 0x03;
ikrase 0:aaa75ea6d346 41
ikrase 0:aaa75ea6d346 42 const uint8_t RECORDID_OVERRIDE_CTL = 0x08;
ikrase 0:aaa75ea6d346 43 const uint8_t RECORDID_OVERRIDE_DATA = 0x08;
ikrase 0:aaa75ea6d346 44
ikrase 0:aaa75ea6d346 45 const uint8_t RECORDID_NUMERIC_SUBTYPE = 0x40;
ikrase 0:aaa75ea6d346 46 const uint8_t RECORDID_NUMERIC_LENGTH = 0x41;
ikrase 0:aaa75ea6d346 47 const uint8_t RECORDID_NUMERIC_LIMITS = 0x42;
ikrase 0:aaa75ea6d346 48 const uint8_t RECORDID_ARRAY_COUNT = 0x50;
ikrase 0:aaa75ea6d346 49
ikrase 0:aaa75ea6d346 50 const uint8_t NUMERIC_SUBTYPE_UINT = 0x01;
ikrase 0:aaa75ea6d346 51 const uint8_t NUMERIC_SUBTYPE_SINT = 0x02;
ikrase 0:aaa75ea6d346 52 const uint8_t NUMERIC_SUBTYPE_FLOAT = 0x03;
ikrase 0:aaa75ea6d346 53
ikrase 0:aaa75ea6d346 54 const uint32_t DECODER_TIMEOUT_MS = 100;
ikrase 0:aaa75ea6d346 55
ikrase 0:aaa75ea6d346 56 // Hardware abstraction layer for the telemetry server.
ikrase 0:aaa75ea6d346 57 class HalInterface {
ikrase 0:aaa75ea6d346 58 public:
ikrase 0:aaa75ea6d346 59 virtual ~HalInterface() {}
ikrase 0:aaa75ea6d346 60
ikrase 0:aaa75ea6d346 61 // Write a byte to the transmit buffer.
ikrase 0:aaa75ea6d346 62 virtual void transmit_byte(uint8_t data) = 0;
ikrase 0:aaa75ea6d346 63 // Returns the number of bytes available in the receive buffer.
ikrase 0:aaa75ea6d346 64 virtual size_t rx_available() = 0;
ikrase 0:aaa75ea6d346 65 // Returns the next byte in the receive stream. rx_available must return > 0.
ikrase 0:aaa75ea6d346 66 virtual uint8_t receive_byte() = 0;
ikrase 0:aaa75ea6d346 67
ikrase 0:aaa75ea6d346 68 // TODO: more efficient block transmit operations?
ikrase 0:aaa75ea6d346 69
ikrase 0:aaa75ea6d346 70 // Called on a telemetry error.
ikrase 0:aaa75ea6d346 71 virtual void do_error(const char* message) = 0;
ikrase 0:aaa75ea6d346 72
ikrase 0:aaa75ea6d346 73 // Return the current time in milliseconds. May overflow at any time.
ikrase 0:aaa75ea6d346 74 virtual uint32_t get_time_ms() = 0;
ikrase 0:aaa75ea6d346 75 };
ikrase 0:aaa75ea6d346 76
ikrase 0:aaa75ea6d346 77 // Abstract base class for building a packet to be transmitted.
ikrase 0:aaa75ea6d346 78 // Implementation is unconstrained - writes may either be buffered or passed
ikrase 0:aaa75ea6d346 79 // directly to the hardware transmit buffers.
ikrase 0:aaa75ea6d346 80 class TransmitPacketInterface {
ikrase 0:aaa75ea6d346 81 public:
ikrase 0:aaa75ea6d346 82 virtual ~TransmitPacketInterface() {}
ikrase 0:aaa75ea6d346 83
ikrase 0:aaa75ea6d346 84 // Writes a 8-bit unsigned integer to the packet stream.
ikrase 0:aaa75ea6d346 85 virtual void write_byte(uint8_t data) = 0;
ikrase 0:aaa75ea6d346 86
ikrase 0:aaa75ea6d346 87 // Writes a 8-bit unsigned integer to the packet stream.
ikrase 0:aaa75ea6d346 88 virtual void write_uint8(uint8_t data) = 0;
ikrase 0:aaa75ea6d346 89 // Writes a 16-bit unsigned integer to the packet stream.
ikrase 0:aaa75ea6d346 90 virtual void write_uint16(uint16_t data) = 0;
ikrase 0:aaa75ea6d346 91 // Writes a 32-bit unsigned integer to the packet stream.
ikrase 0:aaa75ea6d346 92 virtual void write_uint32(uint32_t data) = 0;
ikrase 0:aaa75ea6d346 93 // Writes a float to the packet stream.
ikrase 0:aaa75ea6d346 94 virtual void write_float(float data) = 0;
ikrase 0:aaa75ea6d346 95
ikrase 0:aaa75ea6d346 96 // Finish the packet and writes data to the transmit stream (if not already
ikrase 0:aaa75ea6d346 97 // done). No more data may be written afterwards.
ikrase 0:aaa75ea6d346 98 virtual void finish() = 0;
ikrase 0:aaa75ea6d346 99 };
ikrase 0:aaa75ea6d346 100
ikrase 0:aaa75ea6d346 101 class ReceivePacketBuffer {
ikrase 0:aaa75ea6d346 102 public:
ikrase 0:aaa75ea6d346 103 ReceivePacketBuffer(HalInterface& hal);
ikrase 0:aaa75ea6d346 104
ikrase 0:aaa75ea6d346 105 // Starts a new packet, resetting the packet length and read pointer.
ikrase 0:aaa75ea6d346 106 void new_packet();
ikrase 0:aaa75ea6d346 107
ikrase 0:aaa75ea6d346 108 // Appends a new byte onto this packet, advancing the packet length
ikrase 0:aaa75ea6d346 109 void add_byte(uint8_t byte);
ikrase 0:aaa75ea6d346 110
ikrase 0:aaa75ea6d346 111 // Reads a 8-bit unsigned integer from the packet stream, advancing buffer.
ikrase 0:aaa75ea6d346 112 uint8_t read_uint8();
ikrase 0:aaa75ea6d346 113 // Reads a 16-bit unsigned integer from the packet stream, advancing buffer.
ikrase 0:aaa75ea6d346 114 uint16_t read_uint16();
ikrase 0:aaa75ea6d346 115 // Reads a 32-bit unsigned integer from the packet stream, advancing buffer.
ikrase 0:aaa75ea6d346 116 uint32_t read_uint32();
ikrase 0:aaa75ea6d346 117 // Reads a float from the packet stream, advancing buffer.
ikrase 0:aaa75ea6d346 118 float read_float();
ikrase 0:aaa75ea6d346 119
ikrase 0:aaa75ea6d346 120 protected:
ikrase 0:aaa75ea6d346 121 HalInterface& hal;
ikrase 0:aaa75ea6d346 122
ikrase 0:aaa75ea6d346 123 size_t packet_length;
ikrase 0:aaa75ea6d346 124 size_t read_loc;
ikrase 0:aaa75ea6d346 125 uint8_t data[MAX_RECEIVE_PACKET_LENGTH];
ikrase 0:aaa75ea6d346 126 };
ikrase 0:aaa75ea6d346 127
ikrase 0:aaa75ea6d346 128 // Abstract base class for telemetry data objects.
ikrase 0:aaa75ea6d346 129 class Data {
ikrase 0:aaa75ea6d346 130 public:
ikrase 0:aaa75ea6d346 131 Data(const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 132 const char* units):
ikrase 0:aaa75ea6d346 133 internal_name(internal_name),
ikrase 0:aaa75ea6d346 134 display_name(display_name),
ikrase 0:aaa75ea6d346 135 units(units) {};
ikrase 0:aaa75ea6d346 136
ikrase 0:aaa75ea6d346 137 virtual ~Data() {}
ikrase 0:aaa75ea6d346 138
ikrase 0:aaa75ea6d346 139 // Returns the data type code.
ikrase 0:aaa75ea6d346 140 virtual uint8_t get_data_type() = 0;
ikrase 0:aaa75ea6d346 141
ikrase 0:aaa75ea6d346 142 // Returns the length of the header KVRs, in bytes. Does not include the
ikrase 0:aaa75ea6d346 143 // terminator header.
ikrase 0:aaa75ea6d346 144 virtual size_t get_header_kvrs_length();
ikrase 0:aaa75ea6d346 145 // Writes the header KVRs to the transmit packet. Does not write the
ikrase 0:aaa75ea6d346 146 // terminiator header.
ikrase 0:aaa75ea6d346 147 virtual void write_header_kvrs(TransmitPacketInterface& packet);
ikrase 0:aaa75ea6d346 148
ikrase 0:aaa75ea6d346 149 // Returns the length of the payload, in bytes. Should be "fast".
ikrase 0:aaa75ea6d346 150 virtual size_t get_payload_length() = 0;
ikrase 0:aaa75ea6d346 151 // Writes the payload to the transmit packet. Should be "fast".
ikrase 0:aaa75ea6d346 152 virtual void write_payload(TransmitPacketInterface& packet) = 0;
ikrase 0:aaa75ea6d346 153
ikrase 0:aaa75ea6d346 154 // Sets my value from the received packet, interpreting the current packet
ikrase 0:aaa75ea6d346 155 // read position as my data type.
ikrase 0:aaa75ea6d346 156 virtual void set_from_packet(ReceivePacketBuffer& packet) = 0;
ikrase 0:aaa75ea6d346 157
ikrase 0:aaa75ea6d346 158 protected:
ikrase 0:aaa75ea6d346 159 const char* internal_name;
ikrase 0:aaa75ea6d346 160 const char* display_name;
ikrase 0:aaa75ea6d346 161 const char* units;
ikrase 0:aaa75ea6d346 162 };
ikrase 0:aaa75ea6d346 163
ikrase 0:aaa75ea6d346 164 // Telemetry Server object.
ikrase 0:aaa75ea6d346 165 class Telemetry {
ikrase 0:aaa75ea6d346 166 public:
ikrase 0:aaa75ea6d346 167 Telemetry(HalInterface& hal) :
ikrase 0:aaa75ea6d346 168 hal(hal),
ikrase 0:aaa75ea6d346 169 data_count(0),
ikrase 0:aaa75ea6d346 170 received_packet(ReceivePacketBuffer(hal)),
ikrase 0:aaa75ea6d346 171 decoder_state(SOF),
ikrase 0:aaa75ea6d346 172 decoder_pos(0),
ikrase 0:aaa75ea6d346 173 packet_length(0),
ikrase 0:aaa75ea6d346 174 decoder_last_received(false),
ikrase 0:aaa75ea6d346 175 decoder_last_receive_ms(0),
ikrase 0:aaa75ea6d346 176 header_transmitted(false),
ikrase 0:aaa75ea6d346 177 packet_tx_sequence(0),
ikrase 0:aaa75ea6d346 178 packet_rx_sequence(0) {};
ikrase 0:aaa75ea6d346 179
ikrase 0:aaa75ea6d346 180 // Associates a DataInterface with this object, returning the data ID.
ikrase 0:aaa75ea6d346 181 size_t add_data(Data& new_data);
ikrase 0:aaa75ea6d346 182
ikrase 0:aaa75ea6d346 183 // Marks a data ID as updated, to be transmitted in the next packet.
ikrase 0:aaa75ea6d346 184 void mark_data_updated(size_t data_id);
ikrase 0:aaa75ea6d346 185
ikrase 0:aaa75ea6d346 186 // Transmits header data. Must be called after all add_data calls are done
ikrase 0:aaa75ea6d346 187 // and before and IO is done.
ikrase 0:aaa75ea6d346 188 void transmit_header();
ikrase 0:aaa75ea6d346 189
ikrase 0:aaa75ea6d346 190 // Does IO, including transmitting telemetry packets. Should be called on
ikrase 0:aaa75ea6d346 191 // a regular basis. Since this does IO, this may block depending on the HAL
ikrase 0:aaa75ea6d346 192 // semantics.
ikrase 0:aaa75ea6d346 193 void do_io();
ikrase 0:aaa75ea6d346 194
ikrase 0:aaa75ea6d346 195 // TODO: better docs defining in-band receive.
ikrase 0:aaa75ea6d346 196 // Returns the number of bytes available in the receive stream.
ikrase 0:aaa75ea6d346 197 size_t receive_available();
ikrase 0:aaa75ea6d346 198 // Returns the next byte in the receive stream.
ikrase 0:aaa75ea6d346 199 uint8_t read_receive();
ikrase 0:aaa75ea6d346 200
ikrase 0:aaa75ea6d346 201 // Calls the HAL's error function if some condition is false.
ikrase 0:aaa75ea6d346 202 void do_error(const char* message) {
ikrase 0:aaa75ea6d346 203 hal.do_error(message);
ikrase 0:aaa75ea6d346 204 }
ikrase 0:aaa75ea6d346 205
ikrase 0:aaa75ea6d346 206 protected:
ikrase 0:aaa75ea6d346 207 // Transmits any updated data.
ikrase 0:aaa75ea6d346 208 void transmit_data();
ikrase 0:aaa75ea6d346 209
ikrase 0:aaa75ea6d346 210 // Handles received data, splitting regular UART data from in-band packet
ikrase 0:aaa75ea6d346 211 // data and processing received telemetry packets.
ikrase 0:aaa75ea6d346 212 void process_received_data();
ikrase 0:aaa75ea6d346 213
ikrase 0:aaa75ea6d346 214 // Handles a received packet in received_packet.
ikrase 0:aaa75ea6d346 215 void process_received_packet();
ikrase 0:aaa75ea6d346 216
ikrase 0:aaa75ea6d346 217 HalInterface& hal;
ikrase 0:aaa75ea6d346 218
ikrase 0:aaa75ea6d346 219 // Array of associated DataInterface objects. The index+1 is the
ikrase 0:aaa75ea6d346 220 // DataInterface's data ID field.
ikrase 0:aaa75ea6d346 221 Data* data[MAX_DATA_PER_TELEMETRY];
ikrase 0:aaa75ea6d346 222 // Whether each data has been updated or not.
ikrase 0:aaa75ea6d346 223 bool data_updated[MAX_DATA_PER_TELEMETRY];
ikrase 0:aaa75ea6d346 224 // Count of associated DataInterface objects.
ikrase 0:aaa75ea6d346 225 size_t data_count;
ikrase 0:aaa75ea6d346 226
ikrase 0:aaa75ea6d346 227 // Buffer holding the receive packet being assembled / parsed.
ikrase 0:aaa75ea6d346 228 ReceivePacketBuffer received_packet;
ikrase 0:aaa75ea6d346 229
ikrase 0:aaa75ea6d346 230 enum DecoderState {
ikrase 0:aaa75ea6d346 231 SOF, // reading start-of-frame sequence (or just non-telemetry data)
ikrase 0:aaa75ea6d346 232 LENGTH, // reading packet length
ikrase 0:aaa75ea6d346 233 DATA, // reading telemetry packet data
ikrase 0:aaa75ea6d346 234 DATA_DESTUFF, // reading a stuffed byte
ikrase 0:aaa75ea6d346 235 DATA_DESTUFF_END // last stuffed byte in a packet
ikrase 0:aaa75ea6d346 236 } decoder_state;
ikrase 0:aaa75ea6d346 237
ikrase 0:aaa75ea6d346 238 size_t decoder_pos;
ikrase 0:aaa75ea6d346 239 size_t packet_length;
ikrase 0:aaa75ea6d346 240 bool decoder_last_received;
ikrase 0:aaa75ea6d346 241 uint32_t decoder_last_receive_ms;
ikrase 0:aaa75ea6d346 242
ikrase 0:aaa75ea6d346 243 bool header_transmitted;
ikrase 0:aaa75ea6d346 244
ikrase 0:aaa75ea6d346 245 // Sequence number of the next packet to be transmitted.
ikrase 0:aaa75ea6d346 246 uint8_t packet_tx_sequence;
ikrase 0:aaa75ea6d346 247 uint8_t packet_rx_sequence; // TODO use this somewhere
ikrase 0:aaa75ea6d346 248 };
ikrase 0:aaa75ea6d346 249
ikrase 0:aaa75ea6d346 250 // A telemetry packet with a length known before data is written to it.
ikrase 0:aaa75ea6d346 251 // Data is written directly to the hardware transmit buffers without packet
ikrase 0:aaa75ea6d346 252 // buffering. Assumes transmit buffers won't fill up.
ikrase 0:aaa75ea6d346 253 class FixedLengthTransmitPacket : public TransmitPacketInterface {
ikrase 0:aaa75ea6d346 254 public:
ikrase 0:aaa75ea6d346 255 FixedLengthTransmitPacket(HalInterface& hal, size_t length);
ikrase 0:aaa75ea6d346 256
ikrase 0:aaa75ea6d346 257 virtual void write_byte(uint8_t data);
ikrase 0:aaa75ea6d346 258
ikrase 0:aaa75ea6d346 259 virtual void write_uint8(uint8_t data);
ikrase 0:aaa75ea6d346 260 virtual void write_uint16(uint16_t data);
ikrase 0:aaa75ea6d346 261 virtual void write_uint32(uint32_t data);
ikrase 0:aaa75ea6d346 262 virtual void write_float(float data);
ikrase 0:aaa75ea6d346 263
ikrase 0:aaa75ea6d346 264 virtual void finish();
ikrase 0:aaa75ea6d346 265
ikrase 0:aaa75ea6d346 266 protected:
ikrase 0:aaa75ea6d346 267 HalInterface& hal;
ikrase 0:aaa75ea6d346 268
ikrase 0:aaa75ea6d346 269 // Predetermined length, in bytes, of this packet's payload, for sanity check.
ikrase 0:aaa75ea6d346 270 size_t length;
ikrase 0:aaa75ea6d346 271
ikrase 0:aaa75ea6d346 272 // Current length, in bytes, of this packet's payload.
ikrase 0:aaa75ea6d346 273 size_t count;
ikrase 0:aaa75ea6d346 274
ikrase 0:aaa75ea6d346 275 // Is the packet valid?
ikrase 0:aaa75ea6d346 276 bool valid;
ikrase 0:aaa75ea6d346 277 };
ikrase 0:aaa75ea6d346 278
ikrase 0:aaa75ea6d346 279 template <typename T>
ikrase 0:aaa75ea6d346 280 class Numeric : public Data {
ikrase 0:aaa75ea6d346 281 public:
ikrase 0:aaa75ea6d346 282 Numeric(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 283 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 284 const char* units, T init_value):
ikrase 0:aaa75ea6d346 285 Data(internal_name, display_name, units),
ikrase 0:aaa75ea6d346 286 telemetry_container(telemetry_container),
ikrase 0:aaa75ea6d346 287 value(init_value), min_val(init_value), max_val(init_value),
ikrase 0:aaa75ea6d346 288 frozen(false) {
ikrase 0:aaa75ea6d346 289 data_id = telemetry_container.add_data(*this);
ikrase 0:aaa75ea6d346 290 }
ikrase 0:aaa75ea6d346 291
ikrase 0:aaa75ea6d346 292 T operator = (T b) {
ikrase 0:aaa75ea6d346 293 if (!frozen) {
ikrase 0:aaa75ea6d346 294 value = b;
ikrase 0:aaa75ea6d346 295 telemetry_container.mark_data_updated(data_id);
ikrase 0:aaa75ea6d346 296 }
ikrase 0:aaa75ea6d346 297 return value;
ikrase 0:aaa75ea6d346 298 }
ikrase 0:aaa75ea6d346 299
ikrase 0:aaa75ea6d346 300 operator T() {
ikrase 0:aaa75ea6d346 301 return value;
ikrase 0:aaa75ea6d346 302 }
ikrase 0:aaa75ea6d346 303
ikrase 0:aaa75ea6d346 304 Numeric<T>& set_limits(T min, T max) {
ikrase 0:aaa75ea6d346 305 min_val = min;
ikrase 0:aaa75ea6d346 306 max_val = max;
ikrase 0:aaa75ea6d346 307 return *this;
ikrase 0:aaa75ea6d346 308 }
ikrase 0:aaa75ea6d346 309
ikrase 0:aaa75ea6d346 310 virtual uint8_t get_data_type() { return DATATYPE_NUMERIC; }
ikrase 0:aaa75ea6d346 311
ikrase 0:aaa75ea6d346 312 virtual size_t get_header_kvrs_length() {
ikrase 0:aaa75ea6d346 313 return Data::get_header_kvrs_length()
ikrase 0:aaa75ea6d346 314 + 1 + 1 // subtype
ikrase 0:aaa75ea6d346 315 + 1 + 1 // data length
ikrase 0:aaa75ea6d346 316 + 1 + sizeof(value) + sizeof(value); // limits
ikrase 0:aaa75ea6d346 317 }
ikrase 0:aaa75ea6d346 318
ikrase 0:aaa75ea6d346 319 virtual void write_header_kvrs(TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 320 Data::write_header_kvrs(packet);
ikrase 0:aaa75ea6d346 321 packet.write_uint8(RECORDID_NUMERIC_SUBTYPE);
ikrase 0:aaa75ea6d346 322 packet.write_uint8(get_subtype());
ikrase 0:aaa75ea6d346 323 packet.write_uint8(RECORDID_NUMERIC_LENGTH);
ikrase 0:aaa75ea6d346 324 packet.write_uint8(sizeof(value));
ikrase 0:aaa75ea6d346 325 packet.write_uint8(RECORDID_NUMERIC_LIMITS);
ikrase 0:aaa75ea6d346 326 serialize_data(min_val, packet);
ikrase 0:aaa75ea6d346 327 serialize_data(max_val, packet);
ikrase 0:aaa75ea6d346 328 }
ikrase 0:aaa75ea6d346 329
ikrase 0:aaa75ea6d346 330 uint8_t get_subtype();
ikrase 0:aaa75ea6d346 331
ikrase 0:aaa75ea6d346 332 virtual size_t get_payload_length() { return sizeof(value); }
ikrase 0:aaa75ea6d346 333 virtual void write_payload(TransmitPacketInterface& packet) { serialize_data(value, packet); }
ikrase 0:aaa75ea6d346 334 virtual void set_from_packet(ReceivePacketBuffer& packet) {
ikrase 0:aaa75ea6d346 335 value = deserialize_data(packet);
ikrase 0:aaa75ea6d346 336 telemetry_container.mark_data_updated(data_id); }
ikrase 0:aaa75ea6d346 337
ikrase 0:aaa75ea6d346 338 void serialize_data(T data, TransmitPacketInterface& packet);
ikrase 0:aaa75ea6d346 339 T deserialize_data(ReceivePacketBuffer& packet);
ikrase 0:aaa75ea6d346 340
ikrase 0:aaa75ea6d346 341 protected:
ikrase 0:aaa75ea6d346 342 Telemetry& telemetry_container;
ikrase 0:aaa75ea6d346 343 size_t data_id;
ikrase 0:aaa75ea6d346 344 T value;
ikrase 0:aaa75ea6d346 345 T min_val, max_val;
ikrase 0:aaa75ea6d346 346 bool frozen;
ikrase 0:aaa75ea6d346 347 };
ikrase 0:aaa75ea6d346 348
ikrase 0:aaa75ea6d346 349 template <typename T, uint32_t array_count>
ikrase 0:aaa75ea6d346 350 class NumericArrayAccessor;
ikrase 0:aaa75ea6d346 351
ikrase 0:aaa75ea6d346 352 // TODO: fix this partial specialization inheritance nightmare
ikrase 0:aaa75ea6d346 353 template <typename T, uint32_t array_count>
ikrase 0:aaa75ea6d346 354 class NumericArrayBase : public Data {
ikrase 0:aaa75ea6d346 355 friend class NumericArrayAccessor<T, array_count>;
ikrase 0:aaa75ea6d346 356 public:
ikrase 0:aaa75ea6d346 357 NumericArrayBase(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 358 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 359 const char* units, T elem_init_value):
ikrase 0:aaa75ea6d346 360 Data(internal_name, display_name, units),
ikrase 0:aaa75ea6d346 361 telemetry_container(telemetry_container),
ikrase 0:aaa75ea6d346 362 min_val(elem_init_value), max_val(elem_init_value),
ikrase 0:aaa75ea6d346 363 frozen(false) {
ikrase 0:aaa75ea6d346 364 for (size_t i=0; i<array_count; i++) {
ikrase 0:aaa75ea6d346 365 value[i] = elem_init_value;
ikrase 0:aaa75ea6d346 366 }
ikrase 0:aaa75ea6d346 367 data_id = telemetry_container.add_data(*this);
ikrase 0:aaa75ea6d346 368 }
ikrase 0:aaa75ea6d346 369
ikrase 0:aaa75ea6d346 370 NumericArrayAccessor<T, array_count> operator[] (const int index) {
ikrase 0:aaa75ea6d346 371 // TODO: add bounds checking here
ikrase 0:aaa75ea6d346 372 // TODO: add "frozen" check
ikrase 0:aaa75ea6d346 373 return NumericArrayAccessor<T, array_count>(*this, index);
ikrase 0:aaa75ea6d346 374 }
ikrase 0:aaa75ea6d346 375
ikrase 0:aaa75ea6d346 376 NumericArrayBase<T, array_count>& set_limits(T min, T max) {
ikrase 0:aaa75ea6d346 377 min_val = min;
ikrase 0:aaa75ea6d346 378 max_val = max;
ikrase 0:aaa75ea6d346 379 return *this;
ikrase 0:aaa75ea6d346 380 }
ikrase 0:aaa75ea6d346 381
ikrase 0:aaa75ea6d346 382 virtual uint8_t get_data_type() { return DATATYPE_NUMERIC_ARRAY; }
ikrase 0:aaa75ea6d346 383
ikrase 0:aaa75ea6d346 384 virtual size_t get_header_kvrs_length() {
ikrase 0:aaa75ea6d346 385 return Data::get_header_kvrs_length()
ikrase 0:aaa75ea6d346 386 + 1 + 1 // subtype
ikrase 0:aaa75ea6d346 387 + 1 + 1 // data length
ikrase 0:aaa75ea6d346 388 + 1 + 4 // array length
ikrase 0:aaa75ea6d346 389 + 1 + sizeof(value[0]) + sizeof(value[0]); // limits
ikrase 0:aaa75ea6d346 390 }
ikrase 0:aaa75ea6d346 391
ikrase 0:aaa75ea6d346 392 virtual void write_header_kvrs(TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 393 Data::write_header_kvrs(packet);
ikrase 0:aaa75ea6d346 394 packet.write_uint8(RECORDID_NUMERIC_SUBTYPE);
ikrase 0:aaa75ea6d346 395 packet.write_uint8(get_subtype());
ikrase 0:aaa75ea6d346 396 packet.write_uint8(RECORDID_NUMERIC_LENGTH);
ikrase 0:aaa75ea6d346 397 packet.write_uint8(sizeof(value[0]));
ikrase 0:aaa75ea6d346 398 packet.write_uint8(RECORDID_ARRAY_COUNT);
ikrase 0:aaa75ea6d346 399 packet.write_uint32(array_count);
ikrase 0:aaa75ea6d346 400 packet.write_uint8(RECORDID_NUMERIC_LIMITS);
ikrase 0:aaa75ea6d346 401 serialize_data(min_val, packet);
ikrase 0:aaa75ea6d346 402 serialize_data(max_val, packet);
ikrase 0:aaa75ea6d346 403 }
ikrase 0:aaa75ea6d346 404
ikrase 0:aaa75ea6d346 405 virtual uint8_t get_subtype() = 0;
ikrase 0:aaa75ea6d346 406
ikrase 0:aaa75ea6d346 407 virtual size_t get_payload_length() { return sizeof(value); }
ikrase 0:aaa75ea6d346 408 virtual void write_payload(TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 409 for (size_t i=0; i<array_count; i++) { serialize_data(this->value[i], packet); } }
ikrase 0:aaa75ea6d346 410 virtual void set_from_packet(ReceivePacketBuffer& packet) {
ikrase 0:aaa75ea6d346 411 for (size_t i=0; i<array_count; i++) { value[i] = deserialize_data(packet); }
ikrase 0:aaa75ea6d346 412 telemetry_container.mark_data_updated(data_id); }
ikrase 0:aaa75ea6d346 413
ikrase 0:aaa75ea6d346 414 virtual void serialize_data(T data, TransmitPacketInterface& packet) = 0;
ikrase 0:aaa75ea6d346 415 virtual T deserialize_data(ReceivePacketBuffer& packet) = 0;
ikrase 0:aaa75ea6d346 416
ikrase 0:aaa75ea6d346 417 protected:
ikrase 0:aaa75ea6d346 418 Telemetry& telemetry_container;
ikrase 0:aaa75ea6d346 419 size_t data_id;
ikrase 0:aaa75ea6d346 420 T value[array_count];
ikrase 0:aaa75ea6d346 421 T min_val, max_val;
ikrase 0:aaa75ea6d346 422 bool frozen;
ikrase 0:aaa75ea6d346 423 };
ikrase 0:aaa75ea6d346 424
ikrase 0:aaa75ea6d346 425 template <typename T, uint32_t array_count>
ikrase 0:aaa75ea6d346 426 class NumericArrayAccessor {
ikrase 0:aaa75ea6d346 427 public:
ikrase 0:aaa75ea6d346 428 NumericArrayAccessor(NumericArrayBase<T, array_count>& container, size_t index) :
ikrase 0:aaa75ea6d346 429 container(container), index(index) { }
ikrase 0:aaa75ea6d346 430
ikrase 0:aaa75ea6d346 431 T operator = (T b) {
ikrase 0:aaa75ea6d346 432 if (!container.frozen) {
ikrase 0:aaa75ea6d346 433 container.value[index] = b;
ikrase 0:aaa75ea6d346 434 container.telemetry_container.mark_data_updated(container.data_id);
ikrase 0:aaa75ea6d346 435 }
ikrase 0:aaa75ea6d346 436 return container.value[index];
ikrase 0:aaa75ea6d346 437 }
ikrase 0:aaa75ea6d346 438
ikrase 0:aaa75ea6d346 439 operator T() {
ikrase 0:aaa75ea6d346 440 return container.value[index];
ikrase 0:aaa75ea6d346 441 }
ikrase 0:aaa75ea6d346 442
ikrase 0:aaa75ea6d346 443 protected:
ikrase 0:aaa75ea6d346 444 NumericArrayBase<T, array_count>& container;
ikrase 0:aaa75ea6d346 445 size_t index;
ikrase 0:aaa75ea6d346 446 };
ikrase 0:aaa75ea6d346 447
ikrase 0:aaa75ea6d346 448 template <typename T, uint32_t array_count>
ikrase 0:aaa75ea6d346 449 class NumericArray : public NumericArrayBase<T, array_count> {
ikrase 0:aaa75ea6d346 450 NumericArray(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 451 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 452 const char* units, T elem_init_value);
ikrase 0:aaa75ea6d346 453 virtual uint8_t get_subtype();
ikrase 0:aaa75ea6d346 454 virtual void write_payload(TransmitPacketInterface& packet);
ikrase 0:aaa75ea6d346 455 virtual T deserialize_data(ReceivePacketBuffer& packet);
ikrase 0:aaa75ea6d346 456 };
ikrase 0:aaa75ea6d346 457
ikrase 0:aaa75ea6d346 458 template <uint32_t array_count>
ikrase 0:aaa75ea6d346 459 class NumericArray<uint8_t, array_count> : public NumericArrayBase<uint8_t, array_count> {
ikrase 0:aaa75ea6d346 460 public:
ikrase 0:aaa75ea6d346 461 NumericArray(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 462 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 463 const char* units, uint8_t elem_init_value):
ikrase 0:aaa75ea6d346 464 NumericArrayBase<uint8_t, array_count>(
ikrase 0:aaa75ea6d346 465 telemetry_container, internal_name, display_name,
ikrase 0:aaa75ea6d346 466 units, elem_init_value) {};
ikrase 0:aaa75ea6d346 467 virtual uint8_t get_subtype() {return NUMERIC_SUBTYPE_UINT; }
ikrase 0:aaa75ea6d346 468 virtual void serialize_data(uint8_t data, TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 469 packet.write_uint8(data); }
ikrase 0:aaa75ea6d346 470 virtual uint8_t deserialize_data(ReceivePacketBuffer& packet) {
ikrase 0:aaa75ea6d346 471 return packet.read_uint8(); }
ikrase 0:aaa75ea6d346 472 };
ikrase 0:aaa75ea6d346 473
ikrase 0:aaa75ea6d346 474 template <uint32_t array_count>
ikrase 0:aaa75ea6d346 475 class NumericArray<uint16_t, array_count> : public NumericArrayBase<uint16_t, array_count> {
ikrase 0:aaa75ea6d346 476 public:
ikrase 0:aaa75ea6d346 477 NumericArray(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 478 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 479 const char* units, uint16_t elem_init_value):
ikrase 0:aaa75ea6d346 480 NumericArrayBase<uint16_t, array_count>(
ikrase 0:aaa75ea6d346 481 telemetry_container, internal_name, display_name,
ikrase 0:aaa75ea6d346 482 units, elem_init_value) {};
ikrase 0:aaa75ea6d346 483 virtual uint8_t get_subtype() {return NUMERIC_SUBTYPE_UINT; }
ikrase 0:aaa75ea6d346 484 virtual void serialize_data(uint16_t data, TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 485 packet.write_uint16(data); }
ikrase 0:aaa75ea6d346 486 virtual uint16_t deserialize_data(ReceivePacketBuffer& packet) {
ikrase 0:aaa75ea6d346 487 return packet.read_uint16(); }
ikrase 0:aaa75ea6d346 488 };
ikrase 0:aaa75ea6d346 489
ikrase 0:aaa75ea6d346 490 template <uint32_t array_count>
ikrase 0:aaa75ea6d346 491 class NumericArray<uint32_t, array_count> : public NumericArrayBase<uint32_t, array_count> {
ikrase 0:aaa75ea6d346 492 public:
ikrase 0:aaa75ea6d346 493 NumericArray(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 494 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 495 const char* units, uint32_t elem_init_value):
ikrase 0:aaa75ea6d346 496 NumericArrayBase<uint32_t, array_count>(
ikrase 0:aaa75ea6d346 497 telemetry_container, internal_name, display_name,
ikrase 0:aaa75ea6d346 498 units, elem_init_value) {};
ikrase 0:aaa75ea6d346 499 virtual uint8_t get_subtype() {return NUMERIC_SUBTYPE_UINT; }
ikrase 0:aaa75ea6d346 500 virtual void serialize_data(uint32_t data, TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 501 packet.write_uint32(data); }
ikrase 0:aaa75ea6d346 502 virtual uint32_t deserialize_data(ReceivePacketBuffer& packet) {
ikrase 0:aaa75ea6d346 503 return packet.read_uint32(); }
ikrase 0:aaa75ea6d346 504 };
ikrase 0:aaa75ea6d346 505
ikrase 0:aaa75ea6d346 506 template <uint32_t array_count>
ikrase 0:aaa75ea6d346 507 class NumericArray<float, array_count> : public NumericArrayBase<float, array_count> {
ikrase 0:aaa75ea6d346 508 public:
ikrase 0:aaa75ea6d346 509 NumericArray(Telemetry& telemetry_container,
ikrase 0:aaa75ea6d346 510 const char* internal_name, const char* display_name,
ikrase 0:aaa75ea6d346 511 const char* units, float elem_init_value):
ikrase 0:aaa75ea6d346 512 NumericArrayBase<float, array_count>(
ikrase 0:aaa75ea6d346 513 telemetry_container, internal_name, display_name,
ikrase 0:aaa75ea6d346 514 units, elem_init_value) {};
ikrase 0:aaa75ea6d346 515 virtual uint8_t get_subtype() {return NUMERIC_SUBTYPE_FLOAT; }
ikrase 0:aaa75ea6d346 516 virtual void serialize_data(float data, TransmitPacketInterface& packet) {
ikrase 0:aaa75ea6d346 517 packet.write_float(data); }
ikrase 0:aaa75ea6d346 518 virtual float deserialize_data(ReceivePacketBuffer& packet) {
ikrase 0:aaa75ea6d346 519 return packet.read_float(); }
ikrase 0:aaa75ea6d346 520 };
ikrase 0:aaa75ea6d346 521
ikrase 0:aaa75ea6d346 522 }
ikrase 0:aaa75ea6d346 523
ikrase 0:aaa75ea6d346 524 #endif