diff --git a/comm/event_reports.c b/comm/event_reports.c new file mode 100644 index 0000000..15c423a --- /dev/null +++ b/comm/event_reports.c @@ -0,0 +1,53 @@ +// +// Created by MightyPork on 2018/01/27. +// + +#include "platform.h" +#include "messages.h" +#include "event_reports.h" + +static uint8_t evt_buf[10]; + +bool EventReport_Start(EventReport *report) +{ + assert_param(report->timestamp != 0); + + TF_Msg msg; + TF_ClearMsg(&msg); + msg.len = (TF_LEN) (report->length + 1 /*callsign*/ + 1 /*type*/ + 8 /*checksum*/); + msg.type = MSG_UNIT_REPORT; + if (!TF_Send_Multipart(comm, &msg)) { + dbg("!! Err sending event"); + return false; + } + + PayloadBuilder pb = pb_start(evt_buf, 10, NULL); + pb_u8(&pb, report->unit->callsign); + pb_u8(&pb, report->type); + pb_u64(&pb, report->timestamp); + assert_param(pb.ok); + TF_Multipart_Payload(comm, evt_buf, 10); + + return true; +} + +void EventReport_Data(const uint8_t *buff, uint16_t len) +{ + TF_Multipart_Payload(comm, buff, len); +} + +void EventReport_End(void) +{ + TF_Multipart_Close(comm); +} + +bool EventReport_Send(EventReport *report) +{ + assert_param(report->data != NULL); + + if (!EventReport_Start(report)) return false; + EventReport_Data(report->data, report->length); + EventReport_End(); + + return true; +} diff --git a/comm/event_reports.h b/comm/event_reports.h new file mode 100644 index 0000000..56223ca --- /dev/null +++ b/comm/event_reports.h @@ -0,0 +1,32 @@ +// +// Created by MightyPork on 2018/01/27. +// + +#ifndef GEX_F072_EVENT_REPORTS_H +#define GEX_F072_EVENT_REPORTS_H + +#ifndef GEX_MESSAGES_H +#error "Include messages.h instead!" +#endif + +#include +#include "framework/unit.h" + +/** + * Event report object + */ +typedef struct event_report_ { + Unit *unit; //!< Reporting unit + uint8_t type; //!< Report type (if unit has multiple reports, otherwise 0) + uint64_t timestamp; //!< Microsecond timestamp of the event, captured as close as possible to the IRQ + uint16_t length; //!< Payload length + uint8_t *data; //!< Data if using the EventReport_Send() function, otherwise NULL and data is sent using EventReport_Data() +} EventReport; + +bool EventReport_Send(EventReport *report); + +bool EventReport_Start(EventReport *report); +void EventReport_Data(const uint8_t *buff, uint16_t len); +void EventReport_End(void); + +#endif //GEX_F072_EVENT_REPORTS_H diff --git a/comm/messages.h b/comm/messages.h index 5331baa..00ccff2 100644 --- a/comm/messages.h +++ b/comm/messages.h @@ -49,6 +49,7 @@ extern TinyFrame *comm; #include "msg_responses.h" #include "msg_bulkread.h" #include "msg_bulkwrite.h" +#include "event_reports.h" /** * Initialize TinyFrame and set up listeners diff --git a/framework/unit_base.h b/framework/unit_base.h index 5bf2a57..6ad667b 100644 --- a/framework/unit_base.h +++ b/framework/unit_base.h @@ -13,3 +13,8 @@ #include "utils/malloc_safe.h" #include "payload_builder.h" #include "payload_parser.h" +#include "utils/avrlibc.h" +#include "tasks/task_msg.h" +#include "platform/timebase.h" +#include "platform/irq_dispatcher.h" +#include "comm/messages.h" diff --git a/platform/status_led.c b/platform/status_led.c index 668a56b..dc50d26 100644 --- a/platform/status_led.c +++ b/platform/status_led.c @@ -16,7 +16,7 @@ static uint32_t effect_time = 0; // counter of idle ticks since last indicator // used to allow or disallow heartbeat blink (to avoid interference) static uint32_t indicator_idle_ms = 0; -#define IDLE_FOR_HEARTBEAT_MS 3000 +#define IDLE_FOR_HEARTBEAT_MS (3000-60) #define HB_MAX_SAFE_IVAL 500 static uint32_t hb_elapsed = 0; @@ -86,8 +86,7 @@ void Indicator_Tick(void) if (active_effect == STATUS_NONE) { indicator_idle_ms++; - if (hb_elapsed < HB_MAX_SAFE_IVAL && indicator_idle_ms > IDLE_FOR_HEARTBEAT_MS && - (indicator_idle_ms % 10 == 0)) { + if (hb_elapsed < HB_MAX_SAFE_IVAL && indicator_idle_ms > IDLE_FOR_HEARTBEAT_MS && (indicator_idle_ms % 10 == 0)) { Indicator_Effect(STATUS_HEARTBEAT); } } diff --git a/platform/timebase.h b/platform/timebase.h index 0989d3a..d7e1b2c 100644 --- a/platform/timebase.h +++ b/platform/timebase.h @@ -11,6 +11,8 @@ #ifndef GEX_F072_TIMEBASE_H #define GEX_F072_TIMEBASE_H +#include "platform.h" + /** * Precision timer: get microtime as uint64_t * This timestamp should be monotonously increasing with a precision of ±0.5µs diff --git a/tasks/sched_queue.h b/tasks/sched_queue.h index ec4ebdd..9807843 100644 --- a/tasks/sched_queue.h +++ b/tasks/sched_queue.h @@ -9,6 +9,7 @@ #include "platform.h" #include +#include "framework/unit.h" /** * Queued job typedef @@ -26,27 +27,13 @@ typedef void (*ScheduledJobCb) (Job *job); struct sched_que_item { /** The callback */ ScheduledJobCb cb; - /** Data word 1 */ - union { - TF_ID frame_id; // typically used to pass frame id to the callback - void *data1; // arbitrary pointer or int - uint32_t d32_1; // passing a number - }; - /** Data word 2 */ - union { - uint32_t d32; // passing a number - uint32_t d32_2; // passing a number - uint8_t *buf; // uchar buffer - const uint8_t *cbuf; // const uchar buffer - const char *str; // string - void *data2; // arbitrary pointer - }; - /** Data word 3 */ - union { - uint32_t len; // typically length of the buffer - void *data3; // arbitrary pointer - uint32_t d32_3; // passing a number - }; + + // Fields for data + Unit *unit; + uint64_t timestamp; + uint32_t data1; + uint32_t data2; + uint32_t data3; }; /** diff --git a/units/digital_in/unit_din.c b/units/digital_in/unit_din.c index 621a4df..fe18232 100644 --- a/units/digital_in/unit_din.c +++ b/units/digital_in/unit_din.c @@ -3,11 +3,7 @@ // #include "unit_base.h" -#include "platform/irq_dispatcher.h" -#include "comm/messages.h" #include "unit_din.h" -#include "tasks/task_msg.h" -#include "utils/avrlibc.h" /** Private data structure */ struct priv { @@ -168,18 +164,19 @@ static error_t DI_preInit(Unit *unit) */ static void ID_SendTriggerReportToMaster(Job *job) { - Unit *unit = job->data1; - PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); - pb_u8(&pb, unit->callsign); - pb_u8(&pb, 0x00); // report type "Trigger" - { - pb_u16(&pb, (uint16_t) job->d32_2); // packed, 1 on the triggering pin - pb_u16(&pb, (uint16_t) job->d32_3); // packed, snapshot - // the snapshot can be used to capture the other input pins - } + pb_u16(&pb, (uint16_t) job->data1); // packed, 1 on the triggering pin + pb_u16(&pb, (uint16_t) job->data2); // packed, snapshot assert_param(pb.ok); - com_send_pb(MSG_UNIT_REPORT, &pb); + + EventReport event = { + .unit = job->unit, + .timestamp = job->timestamp, + .data = pb.start, + .length = (uint16_t) pb_length(&pb), + }; + + EventReport_Send(&event); } /** @@ -189,6 +186,8 @@ static void ID_SendTriggerReportToMaster(Job *job) */ static void DI_handleExti(void *arg) { + const uint64_t ts = PTIM_GetMicrotime(); + Unit *unit = arg; struct priv *priv = unit->data; const uint16_t snapshot = (uint16_t) priv->port->IDR; @@ -215,9 +214,10 @@ static void DI_handleExti(void *arg) if (trigger_map != 0) { Job j = { - .data1 = unit, - .d32_2 = pinmask_pack(trigger_map, priv->pins), - .d32_3 = pinmask_pack(snapshot, priv->pins), + .unit = unit, + .timestamp = ts, + .data1 = pinmask_pack(trigger_map, priv->pins), + .data2 = pinmask_pack(snapshot, priv->pins), .cb = ID_SendTriggerReportToMaster }; scheduleJob(&j); diff --git a/units/usart/unit_usart.c b/units/usart/unit_usart.c index f5f2d00..09dcc63 100644 --- a/units/usart/unit_usart.c +++ b/units/usart/unit_usart.c @@ -2,31 +2,28 @@ // Created by MightyPork on 2018/01/02. // -#include "platform.h" -#include "comm/messages.h" #include "unit_base.h" #include "unit_usart.h" -#include "tasks/task_msg.h" #define UUSART_INTERNAL #include "_internal.h" static void UUSART_SendReceivedDataToMaster(Job *job) { - Unit *unit = job->data1; + Unit *unit = job->unit; struct priv *priv = unit->data; - uint32_t readpos = job->d32; - uint32_t count = job->len; - - // TODO use TF's Multipart sending - // TODO add API for building reports - PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL); - pb_u8(&pb, unit->callsign); - pb_u8(&pb, 0x00); // report type "Data received" - pb_buf(&pb, (uint8_t *) (priv->rx_buffer + readpos), count); - assert_param(pb.ok); - com_send_pb(MSG_UNIT_REPORT, &pb); + uint16_t readpos = (uint16_t) job->data1; + uint16_t count = (uint16_t) job->data2; + + EventReport event = { + .unit = job->unit, + .timestamp = job->timestamp, + .data = (uint8_t *) (priv->rx_buffer + readpos), + .length = count, + }; + + EventReport_Send(&event); } /** @@ -37,6 +34,8 @@ static void UUSART_SendReceivedDataToMaster(Job *job) */ void UUSART_DMA_HandleRxFromIRQ(Unit *unit, uint16_t endpos) { + const uint64_t ts = PTIM_GetMicrotime(); + assert_param(unit); struct priv *priv = unit->data; assert_param(priv); @@ -47,11 +46,11 @@ void UUSART_DMA_HandleRxFromIRQ(Unit *unit, uint16_t endpos) uint16_t count = (endpos - readpos); // We defer it to the job queue - // FIXME this can starve the shared queue if full duplex is used, we need a second higher priority queue for those report jobs Job j = { - .data1 = unit, - .d32 = priv->rx_buf_readpos, - .len = count, + .unit = unit, + .timestamp = ts, + .data1 = priv->rx_buf_readpos, + .data2 = count, .cb = UUSART_SendReceivedDataToMaster }; scheduleJob(&j); diff --git a/utils/payload_builder.c b/utils/payload_builder.c index a90e5ab..f4544f4 100644 --- a/utils/payload_builder.c +++ b/utils/payload_builder.c @@ -86,6 +86,36 @@ bool pb_u32(PayloadBuilder *pb, uint32_t word) return true; } +/** Write uint64_t to the buffer. */ +bool pb_u64(PayloadBuilder *pb, uint64_t word) +{ + pb_check_capacity(pb, 4); + if (!pb->ok) return false; + + if (pb->bigendian) { + *pb->current++ = (uint8_t) ((word >> 56) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 48) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 40) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 32) & 0xFF); + + *pb->current++ = (uint8_t) ((word >> 24) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 16) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 8) & 0xFF); + *pb->current++ = (uint8_t) (word & 0xFF); + } else { + *pb->current++ = (uint8_t) (word & 0xFF); + *pb->current++ = (uint8_t) ((word >> 8) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 16) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 24) & 0xFF); + + *pb->current++ = (uint8_t) ((word >> 32) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 40) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 48) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 56) & 0xFF); + } + return true; +} + /** Write int8_t to the buffer. */ bool pb_i8(PayloadBuilder *pb, int8_t byte) { @@ -104,8 +134,20 @@ bool pb_i32(PayloadBuilder *pb, int32_t word) return pb_u32(pb, ((union conv32){.i32 = word}).u32); } +/** Write int64_t to the buffer. */ +bool pb_i64(PayloadBuilder *pb, int64_t word) +{ + return pb_u64(pb, ((union conv64){.i64 = word}).u64); +} + /** Write 4-byte float to the buffer. */ bool pb_float(PayloadBuilder *pb, float f) { return pb_u32(pb, ((union conv32){.f32 = f}).u32); } + +/** Write 8-byte float to the buffer. */ +bool pb_double(PayloadBuilder *pb, double f) +{ + return pb_u64(pb, ((union conv64){.f64 = f}).u64); +} diff --git a/utils/payload_builder.h b/utils/payload_builder.h index cd34b91..3dd844c 100644 --- a/utils/payload_builder.h +++ b/utils/payload_builder.h @@ -98,6 +98,9 @@ bool pb_u16(PayloadBuilder *pb, uint16_t word); /** Write uint32_t to the buffer. */ bool pb_u32(PayloadBuilder *pb, uint32_t word); +/** Write uint64_t to the buffer */ +bool pb_u64(PayloadBuilder *pb, uint64_t word); + /** Write int8_t to the buffer. */ bool pb_i8(PayloadBuilder *pb, int8_t byte); @@ -113,7 +116,13 @@ bool pb_i16(PayloadBuilder *pb, int16_t word); /** Write int32_t to the buffer. */ bool pb_i32(PayloadBuilder *pb, int32_t word); +/** Write int64_t to the buffer. */ +bool pb_i64(PayloadBuilder *pb, int64_t word); + /** Write 4-byte float to the buffer. */ bool pb_float(PayloadBuilder *pb, float f); +/** Write 8-byte float to the buffer. */ +bool pb_double(PayloadBuilder *pb, double f); + #endif // PAYLOAD_BUILDER_H diff --git a/utils/payload_parser.c b/utils/payload_parser.c index ca80605..274bd20 100644 --- a/utils/payload_parser.c +++ b/utils/payload_parser.c @@ -56,6 +56,37 @@ uint32_t pp_u32(PayloadParser *pp) return x; } +uint64_t pp_u64(PayloadParser *pp) +{ + pp_check_capacity(pp, 4); + if (!pp->ok) return 0; + + uint64_t x = 0; + + if (pp->bigendian) { + x |= (uint64_t) ((uint64_t) *pp->current++ << 56); + x |= (uint64_t) ((uint64_t) *pp->current++ << 48); + x |= (uint64_t) ((uint64_t) *pp->current++ << 40); + x |= (uint64_t) ((uint64_t) *pp->current++ << 32); + + x |= (uint64_t) (*pp->current++ << 24); + x |= (uint64_t) (*pp->current++ << 16); + x |= (uint64_t) (*pp->current++ << 8); + x |= *pp->current++; + } else { + x |= *pp->current++; + x |= (uint64_t) (*pp->current++ << 8); + x |= (uint64_t) (*pp->current++ << 16); + x |= (uint64_t) (*pp->current++ << 24); + + x |= (uint64_t) ((uint64_t) *pp->current++ << 32); + x |= (uint64_t) ((uint64_t) *pp->current++ << 40); + x |= (uint64_t) ((uint64_t) *pp->current++ << 48); + x |= (uint64_t) ((uint64_t) *pp->current++ << 56); + } + return x; +} + const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length) { int32_t len = (int) (pp->end - pp->current); @@ -89,12 +120,24 @@ int32_t pp_i32(PayloadParser *pp) return ((union conv32) {.u32 = pp_u32(pp)}).i32; } +/** Read int364_t from the payload. */ +int64_t pp_i64(PayloadParser *pp) +{ + return ((union conv64) {.u64 = pp_u64(pp)}).i64; +} + /** Read 4-byte float from the payload. */ float pp_float(PayloadParser *pp) { return ((union conv32) {.u32 = pp_u32(pp)}).f32; } +/** Read 8-byte float from the payload. */ +double pp_double(PayloadParser *pp) +{ + return ((union conv64) {.u64 = pp_u64(pp)}).f64; +} + /** Read a zstring */ uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen) { diff --git a/utils/payload_parser.h b/utils/payload_parser.h index e9cc431..9a4a258 100644 --- a/utils/payload_parser.h +++ b/utils/payload_parser.h @@ -101,6 +101,9 @@ uint16_t pp_u16(PayloadParser *pp); /** Read uint32_t from the payload. */ uint32_t pp_u32(PayloadParser *pp); +/** Read uint64_t from the payload. */ +uint64_t pp_u64(PayloadParser *pp); + /** Read int8_t from the payload. */ int8_t pp_i8(PayloadParser *pp); @@ -116,9 +119,15 @@ int16_t pp_i16(PayloadParser *pp); /** Read int32_t from the payload. */ int32_t pp_i32(PayloadParser *pp); +/** Read int64_t from the payload. */ +int64_t pp_i64(PayloadParser *pp); + /** Read 4-byte float from the payload. */ float pp_float(PayloadParser *pp); +/** Read 8-byte float from the payload. */ +double pp_double(PayloadParser *pp); + /** * Parse a zero-terminated string * diff --git a/utils/type_coerce.h b/utils/type_coerce.h index 2e4d0c6..0afce93 100644 --- a/utils/type_coerce.h +++ b/utils/type_coerce.h @@ -29,4 +29,10 @@ union conv32 { float f32; }; +union conv64 { + uint64_t u64; + int64_t i64; + double f64; +}; + #endif // TYPE_COERCE_H