ducky's telemetry library
telemetry.cpp
- Committer:
- dnleek
- Date:
- 2015-03-18
- Revision:
- 0:80dd1516ad46
File content as of revision 0:80dd1516ad46:
/* * telemetry.cpp * * Created on: Mar 2, 2015 * Author: Ducky * * Implementation for the base Telemetry class. */ #include <telemetry.h> namespace telemetry { size_t Telemetry::add_data(Data& new_data) { if (data_count >= MAX_DATA_PER_TELEMETRY) { do_error("MAX_DATA_PER_TELEMETRY limit reached."); return 0; } if (header_transmitted) { do_error("Cannot add new data after header transmitted."); return 0; } data[data_count] = &new_data; data_updated[data_count] = true; data_count++; return data_count - 1; } void Telemetry::mark_data_updated(size_t data_id) { data_updated[data_id] = true; } void Telemetry::transmit_header() { if (header_transmitted) { do_error("Cannot retransmit header."); return; } size_t packet_legnth = 2; // opcode + sequence for (int data_idx = 0; data_idx < data_count; data_idx++) { packet_legnth += 2; // data ID, data type packet_legnth += data[data_idx]->get_header_kvrs_length(); packet_legnth += 1; // terminator record id } packet_legnth++; // terminator "record" FixedLengthTransmitPacket packet(hal, packet_legnth); packet.write_uint8(OPCODE_HEADER); packet.write_uint8(packet_tx_sequence); for (int data_idx = 0; data_idx < data_count; data_idx++) { packet.write_uint8(data_idx+1); packet.write_uint8(data[data_idx]->get_data_type()); data[data_idx]->write_header_kvrs(packet); packet.write_uint8(RECORDID_TERMINATOR); } packet.write_uint8(DATAID_TERMINATOR); packet.finish(); packet_tx_sequence++; header_transmitted = true; } void Telemetry::do_io() { transmit_data(); process_received_data(); } void Telemetry::transmit_data() { if (!header_transmitted) { do_error("Must transmit header before transmitting data."); return; } // Keep a local copy to make it more thread-safe bool data_updated_local[MAX_DATA_PER_TELEMETRY]; size_t packet_legnth = 2; // opcode + sequence for (int data_idx = 0; data_idx < data_count; data_idx++) { data_updated_local[data_idx] = data_updated[data_idx]; data_updated[data_idx] = 0; if (data_updated_local[data_idx]) { packet_legnth += 1; // data ID packet_legnth += data[data_idx]->get_payload_length(); } } packet_legnth++; // terminator "record" FixedLengthTransmitPacket packet(hal, packet_legnth); packet.write_uint8(OPCODE_DATA); packet.write_uint8(packet_tx_sequence); for (int data_idx = 0; data_idx < data_count; data_idx++) { if (data_updated_local[data_idx]) { packet.write_uint8(data_idx+1); data[data_idx]->write_payload(packet); } } packet.write_uint8(DATAID_TERMINATOR); packet.finish(); packet_tx_sequence++; } void Telemetry::process_received_data() { uint32_t current_time = hal.get_time_ms(); if (decoder_last_receive_ms <= current_time) { if (!decoder_last_received && decoder_state != SOF && decoder_pos != 0 && (decoder_last_receive_ms - current_time > DECODER_TIMEOUT_MS)) { decoder_pos = 0; packet_length = 0; decoder_state = SOF; hal.do_error("RX timeout"); } } else { // timer overflowed, do nothing } decoder_last_receive_ms = current_time; decoder_last_received = false; while (hal.rx_available()) { decoder_last_received = true; uint8_t rx_byte = hal.receive_byte(); if (decoder_state == SOF) { if (rx_byte == SOF_SEQ[decoder_pos]) { decoder_pos++; if (decoder_pos >= (sizeof(SOF_SEQ) / sizeof(SOF_SEQ[0]))) { decoder_pos = 0; packet_length = 0; decoder_state = LENGTH; } } else { decoder_pos = 0; // TODO: pass rest of data through } } else if (decoder_state == LENGTH) { packet_length = (packet_length << 8) | rx_byte; decoder_pos++; if (decoder_pos >= LENGTH_SIZE) { decoder_pos = 0; decoder_state = DATA; } } else if (decoder_state == DATA) { received_packet.add_byte(rx_byte); decoder_pos++; if (decoder_pos >= packet_length) { process_received_packet(); decoder_pos = 0; if (rx_byte == SOF_SEQ[0]) { decoder_state = DATA_DESTUFF_END; } else { decoder_state = SOF; } } else { if (rx_byte == SOF_SEQ[0]) { decoder_state = DATA_DESTUFF; } } } else if (decoder_state == DATA_DESTUFF) { decoder_state = DATA; } else if (decoder_state == DATA_DESTUFF_END) { decoder_state = SOF; } } } void Telemetry::process_received_packet() { uint8_t opcode = received_packet.read_uint8(); if (opcode == OPCODE_DATA) { uint8_t data_id = received_packet.read_uint8(); while (data_id != DATAID_TERMINATOR) { if (data_id < data_count + 1) { data[data_id - 1]->set_from_packet(received_packet); } else { hal.do_error("Unknown data ID"); } data_id = received_packet.read_uint8(); } } else { hal.do_error("Unknown opcode"); } } size_t Telemetry::receive_available() { // TODO: implement me return 0; } uint8_t read_receive() { // TODO: implement me return 0; } FixedLengthTransmitPacket::FixedLengthTransmitPacket(HalInterface& hal, size_t length) : hal(hal), length(length), count(0) { hal.transmit_byte(SOF1); hal.transmit_byte(SOF2); hal.transmit_byte((length >> 8) & 0xff); hal.transmit_byte((length >> 0) & 0xff); valid = true; } void FixedLengthTransmitPacket::write_byte(uint8_t data) { if (!valid) { hal.do_error("Writing to invalid packet"); return; } else if (count + 1 > length) { hal.do_error("Writing over packet length"); return; } hal.transmit_byte(data); if (data == SOF1) { hal.transmit_byte(0x00); // TODO: proper abstraction and magic numbers } count++; } void FixedLengthTransmitPacket::write_uint8(uint8_t data) { write_byte(data); } void FixedLengthTransmitPacket::write_uint16(uint16_t data) { write_byte((data >> 8) & 0xff); write_byte((data >> 0) & 0xff); } void FixedLengthTransmitPacket::write_uint32(uint32_t data) { write_byte((data >> 24) & 0xff); write_byte((data >> 16) & 0xff); write_byte((data >> 8) & 0xff); write_byte((data >> 0) & 0xff); } void FixedLengthTransmitPacket::write_float(float data) { // TODO: THIS IS ENDIANNESS DEPENDENT, ABSTRACT INTO HAL? uint8_t *float_array = (uint8_t*) &data; write_byte(float_array[3]); write_byte(float_array[2]); write_byte(float_array[1]); write_byte(float_array[0]); } void FixedLengthTransmitPacket::finish() { if (!valid) { hal.do_error("Finish invalid packet"); return; } else if (count != length) { hal.do_error("TX packet under length"); return; } // TODO: add CRC check here } ReceivePacketBuffer::ReceivePacketBuffer(HalInterface& hal) : hal(hal) { new_packet(); } void ReceivePacketBuffer::new_packet() { packet_length = 0; read_loc = 0; } void ReceivePacketBuffer::add_byte(uint8_t byte) { if (packet_length >= MAX_RECEIVE_PACKET_LENGTH) { hal.do_error("RX packet over length"); return; } data[packet_length] = byte; packet_length++; } uint8_t ReceivePacketBuffer::read_uint8() { if (read_loc + 1 > packet_length) { hal.do_error("Read uint8 over length"); return 0; } read_loc += 1; return data[read_loc - 1]; } uint16_t ReceivePacketBuffer::read_uint16() { if (read_loc + 2 > packet_length) { hal.do_error("Read uint16 over length"); return 0; } read_loc += 2; return ((uint16_t)data[read_loc - 2] << 8) | ((uint16_t)data[read_loc - 1] << 0); } uint32_t ReceivePacketBuffer::read_uint32() { if (read_loc + 4 > packet_length) { hal.do_error("Read uint32 over length"); return 0; } read_loc += 4; return ((uint32_t)data[read_loc - 4] << 24) | ((uint32_t)data[read_loc - 3] << 16) | ((uint32_t)data[read_loc - 2] << 8) | ((uint32_t)data[read_loc - 1] << 0); } float ReceivePacketBuffer::read_float() { if (read_loc + 4 > packet_length) { hal.do_error("Read float over length"); return 0; } read_loc += 4; float out = 0; uint8_t* out_array = (uint8_t*)&out; out_array[0] = data[read_loc - 1]; out_array[1] = data[read_loc - 2]; out_array[2] = data[read_loc - 3]; out_array[3] = data[read_loc - 4]; return out; } }