From 40479a0b24e23f7e5d54370c6fd662173a4a39eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Thu, 21 Dec 2017 01:08:35 +0100 Subject: [PATCH 01/17] work on bulk, not finished --- comm/messages.h | 9 ++ gex.mk | 5 +- platform/platform.c | 4 +- units/test/unit_test.c | 245 +++++++++++++++++++++++++++++++++++++++++ units/test/unit_test.h | 13 +++ 5 files changed, 271 insertions(+), 5 deletions(-) create mode 100644 units/test/unit_test.c create mode 100644 units/test/unit_test.h diff --git a/comm/messages.h b/comm/messages.h index 3aae72f..963b7fc 100644 --- a/comm/messages.h +++ b/comm/messages.h @@ -24,9 +24,18 @@ enum TF_Types_ { MSG_SUCCESS = 0x00, //!< Generic success response; used by default in all responses; payload is transaction-specific MSG_PING = 0x01, //!< Ping request (or response), used to test connection MSG_ERROR = 0x02, //!< Generic failure response (when a request fails to execute) + + MSG_BULK_READ_OFFER = 0x03, //!< Offer of data to read. Payload: u32 total len + MSG_BULK_READ_POLL = 0x04, //!< Request to read a previously announced chunk. + MSG_BULK_WRITE_OFFER = 0x05, //!< Offer to receive data in a write transaction. Payload: u32 max size, u32 max chunk + MSG_BULK_DATA = 0x06, //!< Writing a chunk, or sending a chunk to master. + MSG_BULK_END = 0x07, //!< Bulk transfer is done, no more data to read or write. Recipient shall check total len and discard it on mismatch. There could be a checksum ... + MSG_BULK_ABORT = 0x08, //!< Discard the ongoing transfer + // Unit messages MSG_UNIT_REQUEST = 0x10, //!< Command addressed to a particular unit MSG_UNIT_REPORT = 0x11, //!< Spontaneous report from a unit + // System messages MSG_LIST_UNITS = 0x20, //!< Get all unit call-signs and names }; diff --git a/gex.mk b/gex.mk index a5df107..f28cd8a 100644 --- a/gex.mk +++ b/gex.mk @@ -7,6 +7,7 @@ GEX_SRC_DIR = \ User/units \ User/units/system \ User/units/neopixel \ + User/units/test \ User/units/pin \ User/TinyFrame \ User/CWPack \ @@ -36,10 +37,6 @@ GEX_INCLUDES = \ -IUser/TinyFrame \ -IUser/vfs \ -IUser/utils \ - -IUser/units \ - -IUser/units/system \ - -IUser/units/neopixel \ - -IUser/units/pin \ -IUser/framework \ -IUser/platform \ -IUser/tasks \ diff --git a/platform/platform.c b/platform/platform.c index d798e21..f042292 100644 --- a/platform/platform.c +++ b/platform/platform.c @@ -6,11 +6,11 @@ #include "usbd_core.h" #include "USB/usb_device.h" #include "framework/resources.h" - #include "framework/unit_registry.h" #include "units/pin/unit_pin.h" #include "units/neopixel/unit_neopixel.h" +#include "units/test/unit_test.h" // ----- SUPPORTED UNITS ----- @@ -20,6 +20,8 @@ void plat_register_units(void) ureg_add_type(&UNIT_PIN); ureg_add_type(&UNIT_NEOPIXEL); + ureg_add_type(&UNIT_TEST); + // Platform-specific units could be added here } diff --git a/units/test/unit_test.c b/units/test/unit_test.c new file mode 100644 index 0000000..ca48b29 --- /dev/null +++ b/units/test/unit_test.c @@ -0,0 +1,245 @@ +// +// Created by MightyPork on 2017/11/25. +// + +#include "comm/messages.h" +#include "unit_base.h" +#include "unit_test.h" + +/** Private data structure */ +struct priv { + uint32_t unused; +}; + +// ------------------------------------------------------------------------ + +/** Load from a binary buffer stored in Flash */ +static void Tst_loadBinary(Unit *unit, PayloadParser *pp) +{ + struct priv *priv = unit->data; + + // +} + +/** Write to a binary buffer for storing in Flash */ +static void Tst_writeBinary(Unit *unit, PayloadBuilder *pb) +{ + struct priv *priv = unit->data; + + // +} + +// ------------------------------------------------------------------------ + +/** Parse a key-value pair from the INI file */ +static bool Tst_loadIni(Unit *unit, const char *key, const char *value) +{ + bool suc = true; + struct priv *priv = unit->data; + + // + + return suc; +} + +/** Generate INI file section for the unit */ +static void Tst_writeIni(Unit *unit, IniWriter *iw) +{ + struct priv *priv = unit->data; + + // +} + +// ------------------------------------------------------------------------ + +/** Allocate data structure and set defaults */ +static bool Tst_preInit(Unit *unit) +{ + bool suc = true; + struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); + CHECK_SUC(); + + // + + return true; +} + +/** Finalize unit set-up */ +static bool Tst_init(Unit *unit) +{ + bool suc = true; + struct priv *priv = unit->data; + + // + + return true; +} + +/** Tear down the unit */ +static void Tst_deInit(Unit *unit) +{ + struct priv *priv = unit->data; + + // + + // Free memory + free(unit->data); + unit->data = NULL; +} + +// ------------------------------------------------------------------------ + +enum PinCmd_ { + CMD_PING = 0, + CMD_ECHO = 1, + CMD_BULKREAD = 2, +}; + +static void job_echo(Job *job) +{ + tf_respond_buf(MSG_SUCCESS, job->frame_id, job->buf, job->len); + free(job->buf); +} + +const char *longtext = "The history of all hitherto existing societies is the history of class struggles.\n\nFreeman and slave, patrician and plebeian, lord and serf, guild-master and journeyman, in a word, oppressor and oppressed, stood in constant opposition to one another, carried on an uninterrupted, now hidden, now open fight, a fight that each time ended, either in a revolutionary re-constitution of society at large, or in the common ruin of the contending classes.\n\nIn the earlier epochs of history, we find almost everywhere a complicated arrangement of society into various orders, a manifold gradation of social rank. In ancient Rome we have patricians, knights, plebeians, slaves; in the Middle Ages, feudal lords, vassals, guild-masters, journeymen, apprentices, serfs; in almost all of these classes, again, subordinate gradations.\n\nThe modern bourgeois society that has sprouted from the ruins of feudal society has not done away with class antagonisms. It has but established new classes, new conditions of oppression, new forms of struggle in place of the old ones. Our epoch, the epoch of the bourgeoisie, possesses, however, this distinctive feature: it has simplified the class antagonisms. Society as a whole is more and more splitting up into two great hostile camps, into two great classes, directly facing each other: Bourgeoisie and Proletariat.\n\nFrom the serfs of the Middle Ages sprang the chartered burghers of the earliest towns. From these burgesses the first elements of the bourgeoisie were developed.\n\nThe discovery of America, the rounding of the Cape, opened up fresh ground for the rising bourgeoisie. The East-Indian and Chinese markets, the colonisation of America, trade with the colonies, the increase in the means of exchange and in commodities generally, gave to commerce, to navigation, to industry, an impulse never before known, and thereby, to the revolutionary element in the tottering feudal society, a rapid development.\n\nThe feudal system of industry, under which industrial production was monopolised by closed guilds, now no longer sufficed for the growing wants of the new markets. The manufacturing system took its place. The guild-masters were pushed on one side by the manufacturing middle class; division of labour between the different corporate guilds vanished in the face of division of labour in each single workshop.\n\nMeantime the markets kept ever growing, the demand ever rising. Even manufacture no longer sufficed. Thereupon, steam and machinery revolutionised industrial production. The place of manufacture was taken by the giant, Modern Industry, the place of the industrial middle class, by industrial millionaires, the leaders of whole industrial armies, the modern bourgeois.\n\nModern industry has established the world-market, for which the discovery of America paved the way. This market has given an immense development to commerce, to navigation, to communication by land. This development has, in its time, reacted on the extension of industry; and in proportion as industry, commerce, navigation, railways extended, in the same proportion the bourgeoisie developed, increased its capital, and pushed into the background every class handed down from the Middle Ages.\n\nWe see, therefore, how the modern bourgeoisie is itself the product of a long course of development, of a series of revolutions in the modes of production and of exchange.\n\nEach step in the development of the bourgeoisie was accompanied by a corresponding political advance of that class. An oppressed class under the sway of the feudal nobility, an armed and self-governing association in the mediaeval commune; here independent urban republic (as in Italy and Germany), there taxable \"third estate\" of the monarchy (as in France), afterwards, in the period of manufacture proper, serving either the semi-feudal or the absolute monarchy as a counterpoise against the nobility, and, in fact, corner-stone of the great monarchies in general, the bourgeoisie has at last, since the establishment of Modern Industry and of the world-market, conquered for itself, in the modern representative State, exclusive political sway. The executive of the modern State is but a committee for managing the common affairs of the whole bourgeoisie."; + +static void job_bulkread_chunk(Job *job) +{ + dbg("Tx a chunk"); + tf_respond_buf(MSG_BULK_DATA, job->frame_id, job->buf, job->len); +} + +static void job_bulkread_close(Job *job) +{ + dbg("Bulk read close."); + tf_respond_buf(MSG_BULK_END, job->frame_id, NULL, 0); +} + +static void job_bulkread_offer(Job *job) +{ + uint8_t buf[10]; + PayloadBuilder pb = pb_start(buf, 10, NULL); + pb_u32(&pb, job->d32); + + dbg("Offer bulk xfer of %d bytes", job->d32); + + tf_respond_buf(MSG_BULK_READ_OFFER, job->frame_id, buf, (uint32_t) pb_length(&pb)); +} + +static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) +{ + if (msg->data == NULL) { + dbg("Bulk rx lst cleanup\r\n"); + return TF_CLOSE; + } // this is a final call before timeout, to clean up + + if (msg->type == MSG_BULK_READ_POLL) { + uint32_t pos = (uint32_t) msg->userdata2; + uint32_t total = (uint32_t) strlen(longtext); // normally we'd not calculate it here + + dbg("BR poll, at %d", pos); + + // Say we're done and close if it's over + if (pos >= total) { + Job job = { + .cb = job_bulkread_close, + .frame_id = msg->frame_id + }; + scheduleJob(&job, TSK_SCHED_HIGH); + return TF_CLOSE; + } + + PayloadParser pp = pp_start(msg->data, msg->len, NULL); + uint32_t chunk = pp_u32(&pp); + chunk = MIN(chunk, total - pos); + + // this isn't at all resistant to error, we expect the communication to be lossless + Job job = { + .cb = job_bulkread_chunk, + .frame_id = msg->frame_id, + .buf = (uint8_t *) (longtext + pos), + .len = chunk, + }; + scheduleJob(&job, TSK_SCHED_HIGH); + + // advance the position pointer + pos += chunk; + msg->userdata2 = (void *) pos; + } + + if (msg->type == MSG_BULK_ABORT) { + return TF_CLOSE; + } + + return TF_STAY; +} + +/** Handle a request message */ +static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) +{ + (void)pp; + + struct priv *priv = unit->data; + + switch (command) { + case CMD_PING: + sched_respond_suc(frame_id); + break; + + case CMD_ECHO:; + uint32_t len = (uint32_t) pp_length(pp); + uint8_t *cpy = malloc(len); + memcpy(cpy, pp_tail(pp, NULL), len); + Job job = { + .cb = job_echo, + .frame_id = frame_id, + .buf = cpy, + .len = len, + }; + dbg("Rx len %d, %.*s\r\n", len, len, cpy); + scheduleJob(&job, TSK_SCHED_HIGH); + break; + + case CMD_BULKREAD:; + TF_Msg msg = { + .frame_id = frame_id, + .userdata = unit, // we'll keep a reference to the unit here + .userdata2 = 0 // and current position here. + }; + // in a real scenario, we'd put a malloc'd struct here. + TF_AddIdListener(comm, &msg, bulkread_lst, 200); + + Job job2 = { + .cb = job_bulkread_offer, + .frame_id = frame_id, + .d32 = (uint32_t) strlen(longtext), + }; + scheduleJob(&job2, TSK_SCHED_HIGH); + break; + + default: + sched_respond_bad_cmd(frame_id); + return false; + } + + return true; +} + +// ------------------------------------------------------------------------ + +/** Unit template */ +const UnitDriver UNIT_TEST = { + .name = "TEST", + .description = "Test unit", + // Settings + .preInit = Tst_preInit, + .cfgLoadBinary = Tst_loadBinary, + .cfgWriteBinary = Tst_writeBinary, + .cfgLoadIni = Tst_loadIni, + .cfgWriteIni = Tst_writeIni, + // Init + .init = Tst_init, + .deInit = Tst_deInit, + // Function + .handleRequest = Tst_handleRequest, +}; diff --git a/units/test/unit_test.h b/units/test/unit_test.h new file mode 100644 index 0000000..9feb5ba --- /dev/null +++ b/units/test/unit_test.h @@ -0,0 +1,13 @@ +// +// Created by MightyPork on 2017/11/25. +// Testing unit that uses most of the protocol to verify the core functionality +// + +#ifndef U_TEST_H +#define U_TEST_H + +#include "unit.h" + +extern const UnitDriver UNIT_TEST; + +#endif //U_TEST_H From 5135aedc5bb9c7d483bd9ed0940c6e50a399a6d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Dec 2017 00:26:27 +0100 Subject: [PATCH 02/17] bulk now works, but has some excessive comments and need to be abstracted out --- comm/messages.c | 1 + units/test/unit_test.c | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/comm/messages.c b/comm/messages.c index 57c367c..e21d5cf 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -181,6 +181,7 @@ static void job_unhandled_resp(Job *job) static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg) { + dbg("!! Unhandled msg type %d, frame_id %d", (int)msg->type, (int)msg->frame_id); Job job = { .cb = job_unhandled_resp, .frame_id = msg->frame_id, diff --git a/units/test/unit_test.c b/units/test/unit_test.c index ca48b29..66b9cfe 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -105,7 +105,7 @@ const char *longtext = "The history of all hitherto existing societies is the hi static void job_bulkread_chunk(Job *job) { - dbg("Tx a chunk"); + dbg("Tx a chunk of size %d", (int)job->len); tf_respond_buf(MSG_BULK_DATA, job->frame_id, job->buf, job->len); } @@ -121,7 +121,7 @@ static void job_bulkread_offer(Job *job) PayloadBuilder pb = pb_start(buf, 10, NULL); pb_u32(&pb, job->d32); - dbg("Offer bulk xfer of %d bytes", job->d32); + dbg("Offer bulk xfer of %d bytes", (int)job->d32); tf_respond_buf(MSG_BULK_READ_OFFER, job->frame_id, buf, (uint32_t) pb_length(&pb)); } @@ -137,7 +137,7 @@ static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) uint32_t pos = (uint32_t) msg->userdata2; uint32_t total = (uint32_t) strlen(longtext); // normally we'd not calculate it here - dbg("BR poll, at %d", pos); + dbg("BR poll, at %d", (int)pos); // Say we're done and close if it's over if (pos >= total) { @@ -171,7 +171,7 @@ static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) return TF_CLOSE; } - return TF_STAY; + return TF_RENEW; } /** Handle a request message */ @@ -196,7 +196,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo .buf = cpy, .len = len, }; - dbg("Rx len %d, %.*s\r\n", len, len, cpy); + dbg("Rx len %d, %.*s\r\n", (int)len, (int)len, cpy); scheduleJob(&job, TSK_SCHED_HIGH); break; @@ -207,7 +207,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo .userdata2 = 0 // and current position here. }; // in a real scenario, we'd put a malloc'd struct here. - TF_AddIdListener(comm, &msg, bulkread_lst, 200); + TF_AddIdListener(comm, &msg, bulkread_lst, 500); Job job2 = { .cb = job_bulkread_offer, From 5db77649ffd88ea7c69d4e6e82fa662b45f0042e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Dec 2017 01:02:45 +0100 Subject: [PATCH 03/17] fuxes for build without serial --- gex.mk | 16 +++++++++++++++- platform/debug_uart.c | 1 + 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/gex.mk b/gex.mk index f28cd8a..b42f206 100644 --- a/gex.mk +++ b/gex.mk @@ -62,10 +62,14 @@ GEX_CFLAGS = \ -fmerge-constants -fmerge-all-constants \ -fno-exceptions -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast -finline-small-functions -findirect-inlining \ -GEX_CDEFS = \ +GEX_CDEFS_BASE = \ -D__weak="__attribute__((weak))" \ -D__packed="__attribute__((__packed__))" \ -DUSE_FULL_LL_DRIVER \ + +# TODO implement debug build choice +ifeq '1' '1' +GEX_CDEFS = $(GEX_CDEFS_BASE) \ -DUSE_FULL_ASSERT=1 \ -DVERBOSE_ASSERT=1 \ -DDEBUG_VFS=0 \ @@ -73,3 +77,13 @@ GEX_CDEFS = \ -DVERBOSE_HARDFAULT=1 \ -DUSE_STACK_MONITOR=1 \ -DUSE_DEBUG_UART=1 +else +GEX_CDEFS = $(GEX_CDEFS_BASE) \ + -DUSE_FULL_ASSERT=0 \ + -DVERBOSE_ASSERT=0 \ + -DDEBUG_VFS=0 \ + -DDEBUG_FLASH_WRITE=0 \ + -DVERBOSE_HARDFAULT=0 \ + -DUSE_STACK_MONITOR=0 \ + -DUSE_DEBUG_UART=0 +endif diff --git a/platform/debug_uart.c b/platform/debug_uart.c index a9f91d6..cc371b9 100644 --- a/platform/debug_uart.c +++ b/platform/debug_uart.c @@ -79,6 +79,7 @@ ssize_t _write_r(struct _reent *rptr, int fd, const void *buf, size_t len) #else // No-uart variant +void DebugUart_PreInit(void) {} void DebugUart_Init(void) {} ssize_t _write_r(struct _reent *rptr, int fd, const void *buf, size_t len) { return len; From fa5261b65a696c343e24879601c8dbc82850aa2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Dec 2017 19:17:57 +0100 Subject: [PATCH 04/17] some cleaning --- comm/messages.c | 124 -------------------------------- comm/messages.h | 144 +++++--------------------------------- comm/msg_responses.c | 138 ++++++++++++++++++++++++++++++++++++ comm/msg_responses.h | 128 +++++++++++++++++++++++++++++++++ framework/unit_registry.c | 14 ++-- utils/build_parser.sh | 0 6 files changed, 289 insertions(+), 259 deletions(-) create mode 100644 comm/msg_responses.c create mode 100644 comm/msg_responses.h mode change 100755 => 100644 utils/build_parser.sh diff --git a/comm/messages.c b/comm/messages.c index e21d5cf..25fb1aa 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -32,130 +32,6 @@ void comm_init(void) // --------------------------------------------------------------------------- -void tf_respond_snprintf(TF_TYPE type, TF_ID id, const char *format, ...) -{ -#define ERR_STR_LEN 64 - char buf[ERR_STR_LEN]; - va_list args; - va_start(args, format); - uint32_t len = (uint32_t) fixup_vsnprintf(&buf[0], ERR_STR_LEN, format, args); - va_end(args); - - tf_respond_buf(type, id, (const uint8_t *) buf, len); -} - -void tf_respond_buf(TF_TYPE type, TF_ID id, const uint8_t *buf, uint32_t len) -{ - TF_Msg msg; - TF_ClearMsg(&msg); - { - msg.type = type; - msg.frame_id = id; - msg.data = buf; - msg.len = (TF_LEN) len; - } - TF_Respond(comm, &msg); -} - -void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) -{ - TF_Msg msg; - TF_ClearMsg(&msg); - { - msg.type = MSG_UNIT_REPORT; - msg.data = buf; - msg.len = (TF_LEN) len; - msg.type = type; - } - TF_Send(comm, &msg); // no listener -} - -// --------------------------------------------------------------------------- - -static void job_respond_err(Job *job) -{ - tf_respond_str(MSG_ERROR, job->frame_id, job->str); -} - -void sched_respond_err(TF_ID frame_id, const char *message) -{ - dbg("ERR: %s", message); - Job job = { - .cb = job_respond_err, - .frame_id = frame_id, - .str = message - }; - scheduleJob(&job, TSK_SCHED_LOW); -} - -void sched_respond_bad_cmd(TF_ID frame_id) -{ - sched_respond_err(frame_id, "BAD COMMAND"); -} - -void sched_respond_malformed_cmd(TF_ID frame_id) -{ - sched_respond_err(frame_id, "MALFORMED PAYLOAD"); -} - -// --------------------------------------------------------------------------- - -static void job_respond_suc(Job *job) -{ - tf_respond_ok(job->frame_id); -} - -void sched_respond_suc(TF_ID frame_id) -{ - Job job = { - .cb = job_respond_suc, - .frame_id = frame_id - }; - scheduleJob(&job, TSK_SCHED_LOW); -} - -// --------------------------------------------------------------------------- - -static void job_respond_uX(Job *job) -{ - tf_respond_buf(MSG_SUCCESS, job->frame_id, (const uint8_t *) &job->d32, job->len); -} - -void sched_respond_u8(TF_ID frame_id, uint8_t d) -{ - Job job = { - .cb = job_respond_uX, - .frame_id = frame_id, - .d32 = d, - .len = 1 - }; - scheduleJob(&job, TSK_SCHED_HIGH); -} - -void sched_respond_u16(TF_ID frame_id, uint16_t d) -{ - Job job = { - .cb = job_respond_uX, - .frame_id = frame_id, - .d32 = d, - .len = 2 - }; - scheduleJob(&job, TSK_SCHED_HIGH); -} - -void sched_respond_u32(TF_ID frame_id, uint32_t d) -{ - Job job = { - .cb = job_respond_uX, - .frame_id = frame_id, - .d32 = d, - .len = 4 - }; - scheduleJob(&job, TSK_SCHED_HIGH); -} - -// --------------------------------------------------------------------------- - static void job_ping_reply(Job *job) { tf_respond_snprintf(MSG_SUCCESS, job->frame_id, "%s/%s", GEX_VERSION, GEX_PLATFORM); diff --git a/comm/messages.h b/comm/messages.h index 963b7fc..355e8aa 100644 --- a/comm/messages.h +++ b/comm/messages.h @@ -9,151 +9,39 @@ #include "task_sched.h" #include "TinyFrame.h" -extern TinyFrame *comm; - -/** - * Initialize TinyFrame and set up listeners - */ -void comm_init(void); - /** * Supported message types (TF_TYPE) */ enum TF_Types_ { // General, low level - MSG_SUCCESS = 0x00, //!< Generic success response; used by default in all responses; payload is transaction-specific - MSG_PING = 0x01, //!< Ping request (or response), used to test connection - MSG_ERROR = 0x02, //!< Generic failure response (when a request fails to execute) + MSG_SUCCESS = 0x00, //!< Generic success response; used by default in all responses; payload is transaction-specific + MSG_PING = 0x01, //!< Ping request (or response), used to test connection + MSG_ERROR = 0x02, //!< Generic failure response (when a request fails to execute) - MSG_BULK_READ_OFFER = 0x03, //!< Offer of data to read. Payload: u32 total len - MSG_BULK_READ_POLL = 0x04, //!< Request to read a previously announced chunk. + MSG_BULK_READ_OFFER = 0x03, //!< Offer of data to read. Payload: u32 total len + MSG_BULK_READ_POLL = 0x04, //!< Request to read a previously announced chunk. MSG_BULK_WRITE_OFFER = 0x05, //!< Offer to receive data in a write transaction. Payload: u32 max size, u32 max chunk - MSG_BULK_DATA = 0x06, //!< Writing a chunk, or sending a chunk to master. - MSG_BULK_END = 0x07, //!< Bulk transfer is done, no more data to read or write. Recipient shall check total len and discard it on mismatch. There could be a checksum ... - MSG_BULK_ABORT = 0x08, //!< Discard the ongoing transfer + MSG_BULK_DATA = 0x06, //!< Writing a chunk, or sending a chunk to master. + MSG_BULK_END = 0x07, //!< Bulk transfer is done, no more data to read or write. Recipient shall check total len and discard it on mismatch. There could be a checksum ... + MSG_BULK_ABORT = 0x08, //!< Discard the ongoing transfer // Unit messages - MSG_UNIT_REQUEST = 0x10, //!< Command addressed to a particular unit - MSG_UNIT_REPORT = 0x11, //!< Spontaneous report from a unit + MSG_UNIT_REQUEST = 0x10, //!< Command addressed to a particular unit + MSG_UNIT_REPORT = 0x11, //!< Spontaneous report from a unit // System messages - MSG_LIST_UNITS = 0x20, //!< Get all unit call-signs and names + MSG_LIST_UNITS = 0x20, //!< Get all unit call-signs and names }; -/** - * Respond to a TF message using printf-like formatting. - * Works synchronously, must be called on a job queue. - * - * @param type - response type byte - * @param frame_id - ID of the original msg - * @param format - printf format - * @param ... - replacements - */ -void __attribute__((format(printf,3,4))) -tf_respond_snprintf(TF_TYPE type, TF_ID frame_id, const char *format, ...); - -/** - * Respond to a TF message with a buffer of fixed length and custom type. - * Works synchronously, must be called on a job queue. - * - * @param type - response type byte - * @param frame_id - ID of the original msg - * @param buf - byte buffer - * @param len - buffer size - */ -void tf_respond_buf(TF_TYPE type, TF_ID frame_id, const uint8_t *buf, uint32_t len); - -/** - * Respond to a TF message with empty body and MSG_SUCCESS type. - * Works synchronously, must be called on a job queue. - * - * @param frame_id - ID of the original msg - */ -static inline void tf_respond_ok(TF_ID frame_id) -{ - tf_respond_buf(MSG_SUCCESS, frame_id, NULL, 0); -} - -/** - * Same like tf_respond_buf(), but used for sending spontaneous reports. - * Works synchronously, must be called on a job queue / timer task etc. - * - * @param type - response type byte - * @param buf - byte buffer - * @param len - buffer size - */ -void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); - -/** - * Same like tf_respond_buf(), but the buffer length is measured with strlen. - * Used to sending ASCII string responses. - * Works synchronously, must be called on a job queue. - * - * @param type - response type byte - * @param frame_id - ID of the original msg - * @param str - character buffer, zero terminated - */ -static inline void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) -{ - tf_respond_buf(type, frame_id, (const uint8_t *) str, (uint32_t) strlen(str)); -} - -/** - * Schedule sending an ASCII string error response. - * Schedules a low priority job. - * - * @param frame_id - ID of the original msg - * @param str - character buffer, zero terminated - */ -void sched_respond_err(TF_ID frame_id, const char *str); - -/** - * Variant of sched_respond_err() for reporting bad received command code - * - * @param msg_id - ID of the original msg - */ -void sched_respond_bad_cmd(TF_ID frame_id); - -/** - * Variant of sched_respond_err() for reporting malformed commands (e.g. too short payload) - * - * @param msg_id - ID of the original msg - */ -void sched_respond_malformed_cmd(TF_ID frame_id); - -/** - * Schedule sending an empty response with MSG_SUCCESS type. - * Schedules a low priority job. - * - * @param frame_id - ID of the original msg - */ -void sched_respond_suc(TF_ID frame_id); +// Must be after the enum because it's used in the header file. +#include "msg_responses.h" -/** - * Schedule sending a one-byte response with MSG_SUCCESS type. - * Schedules a high priority job. - * - * @param frame_id - ID of the original msg - * @param d - data - */ -void sched_respond_u8(TF_ID frame_id, uint8_t d); -/** - * Schedule sending a two-byte response with MSG_SUCCESS type. - * Schedules a high priority job. - * - * @param frame_id - ID of the original msg - * @param d - data - */ -void sched_respond_u16(TF_ID frame_id, uint16_t d); +extern TinyFrame *comm; /** - * Schedule sending a 4-byte response with MSG_SUCCESS type. - * Schedules a high priority job. - * - * @param frame_id - ID of the original msg - * @param d - data + * Initialize TinyFrame and set up listeners */ -void sched_respond_u32(TF_ID frame_id, uint32_t d); +void comm_init(void); #endif //GEX_MESSAGES_H diff --git a/comm/msg_responses.c b/comm/msg_responses.c new file mode 100644 index 0000000..fdcbff7 --- /dev/null +++ b/comm/msg_responses.c @@ -0,0 +1,138 @@ +// +// Created by MightyPork on 2017/12/22. +// + +#include "messages.h" +#include "msg_responses.h" + +void tf_respond_snprintf(TF_TYPE type, TF_ID id, const char *format, ...) +{ +#define ERR_STR_LEN 64 + char buf[ERR_STR_LEN]; + va_list args; + va_start(args, format); + uint32_t len = (uint32_t) fixup_vsnprintf(&buf[0], ERR_STR_LEN, format, args); + va_end(args); + + tf_respond_buf(type, id, (const uint8_t *) buf, len); +} + + +void tf_respond_buf(TF_TYPE type, TF_ID id, const uint8_t *buf, uint32_t len) +{ + TF_Msg msg; + TF_ClearMsg(&msg); + { + msg.type = type; + msg.frame_id = id; + msg.data = buf; + msg.len = (TF_LEN) len; + } + TF_Respond(comm, &msg); +} + + +void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) +{ + TF_Msg msg; + TF_ClearMsg(&msg); + { + msg.type = MSG_UNIT_REPORT; + msg.data = buf; + msg.len = (TF_LEN) len; + msg.type = type; + } + TF_Send(comm, &msg); // no listener +} + + +// --------------------------------------------------------------------------- + +static void job_respond_err(Job *job) +{ + tf_respond_str(MSG_ERROR, job->frame_id, job->str); +} + + +void sched_respond_err(TF_ID frame_id, const char *message) +{ + dbg("ERR: %s", message); + Job job = { + .cb = job_respond_err, + .frame_id = frame_id, + .str = message + }; + scheduleJob(&job, TSK_SCHED_LOW); +} + + +void sched_respond_bad_cmd(TF_ID frame_id) +{ + sched_respond_err(frame_id, "BAD COMMAND"); +} + + +void sched_respond_malformed_cmd(TF_ID frame_id) +{ + sched_respond_err(frame_id, "MALFORMED PAYLOAD"); +} + +// --------------------------------------------------------------------------- + +static void job_respond_suc(Job *job) +{ + tf_respond_ok(job->frame_id); +} + + +void sched_respond_suc(TF_ID frame_id) +{ + Job job = { + .cb = job_respond_suc, + .frame_id = frame_id + }; + scheduleJob(&job, TSK_SCHED_LOW); +} + +// --------------------------------------------------------------------------- + +static void job_respond_uX(Job *job) +{ + tf_respond_buf(MSG_SUCCESS, job->frame_id, (const uint8_t *) &job->d32, job->len); +} + + +void sched_respond_u8(TF_ID frame_id, uint8_t d) +{ + Job job = { + .cb = job_respond_uX, + .frame_id = frame_id, + .d32 = d, + .len = 1 + }; + scheduleJob(&job, TSK_SCHED_HIGH); +} + + +void sched_respond_u16(TF_ID frame_id, uint16_t d) +{ + Job job = { + .cb = job_respond_uX, + .frame_id = frame_id, + .d32 = d, + .len = 2 + }; + scheduleJob(&job, TSK_SCHED_HIGH); +} + + +void sched_respond_u32(TF_ID frame_id, uint32_t d) +{ + Job job = { + .cb = job_respond_uX, + .frame_id = frame_id, + .d32 = d, + .len = 4 + }; + scheduleJob(&job, TSK_SCHED_HIGH); +} diff --git a/comm/msg_responses.h b/comm/msg_responses.h new file mode 100644 index 0000000..e1bd35e --- /dev/null +++ b/comm/msg_responses.h @@ -0,0 +1,128 @@ +// +// Created by MightyPork on 2017/12/22. +// + +#ifndef GEX_F072_MSG_RESPONSES_H +#define GEX_F072_MSG_RESPONSES_H + +#ifndef GEX_MESSAGES_H +#error "Include messages.h instead!" +#endif + +/** + * Respond to a TF message using printf-like formatting. + * Works synchronously, must be called on a job queue. + * + * @param type - response type byte + * @param frame_id - ID of the original msg + * @param format - printf format + * @param ... - replacements + */ +void __attribute__((format(printf,3,4))) +tf_respond_snprintf(TF_TYPE type, TF_ID frame_id, const char *format, ...); + +/** + * Respond to a TF message with a buffer of fixed length and custom type. + * Works synchronously, must be called on a job queue. + * + * @param type - response type byte + * @param frame_id - ID of the original msg + * @param buf - byte buffer + * @param len - buffer size + */ +void tf_respond_buf(TF_TYPE type, TF_ID frame_id, const uint8_t *buf, uint32_t len); + +/** + * Respond to a TF message with empty body and MSG_SUCCESS type. + * Works synchronously, must be called on a job queue. + * + * @param frame_id - ID of the original msg + */ +static inline void tf_respond_ok(TF_ID frame_id) +{ + tf_respond_buf(MSG_SUCCESS, frame_id, NULL, 0); +} + +/** + * Same like tf_respond_buf(), but used for sending spontaneous reports. + * Works synchronously, must be called on a job queue / timer task etc. + * + * @param type - response type byte + * @param buf - byte buffer + * @param len - buffer size + */ +void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); + +/** + * Same like tf_respond_buf(), but the buffer length is measured with strlen. + * Used to sending ASCII string responses. + * Works synchronously, must be called on a job queue. + * + * @param type - response type byte + * @param frame_id - ID of the original msg + * @param str - character buffer, zero terminated + */ +static inline void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) +{ + tf_respond_buf(type, frame_id, (const uint8_t *) str, (uint32_t) strlen(str)); +} + +/** + * Schedule sending an ASCII string error response. + * Schedules a low priority job. + * + * @param frame_id - ID of the original msg + * @param str - character buffer, zero terminated + */ +void sched_respond_err(TF_ID frame_id, const char *str); + +/** + * Variant of sched_respond_err() for reporting bad received command code + * + * @param msg_id - ID of the original msg + */ +void sched_respond_bad_cmd(TF_ID frame_id); + +/** + * Variant of sched_respond_err() for reporting malformed commands (e.g. too short payload) + * + * @param msg_id - ID of the original msg + */ +void sched_respond_malformed_cmd(TF_ID frame_id); + +/** + * Schedule sending an empty response with MSG_SUCCESS type. + * Schedules a low priority job. + * + * @param frame_id - ID of the original msg + */ +void sched_respond_suc(TF_ID frame_id); + +/** + * Schedule sending a one-byte response with MSG_SUCCESS type. + * Schedules a high priority job. + * + * @param frame_id - ID of the original msg + * @param d - data + */ +void sched_respond_u8(TF_ID frame_id, uint8_t d); + +/** + * Schedule sending a two-byte response with MSG_SUCCESS type. + * Schedules a high priority job. + * + * @param frame_id - ID of the original msg + * @param d - data + */ +void sched_respond_u16(TF_ID frame_id, uint16_t d); + +/** + * Schedule sending a 4-byte response with MSG_SUCCESS type. + * Schedules a high priority job. + * + * @param frame_id - ID of the original msg + * @param d - data + */ +void sched_respond_u32(TF_ID frame_id, uint32_t d); + +#endif //GEX_F072_MSG_RESPONSES_H diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 5940c01..7b2b123 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -543,24 +543,24 @@ void ureg_deliver_unit_request(TF_Msg *msg) void ureg_report_active_units(TF_ID frame_id) { // count bytes needed - uint32_t needed = 1; // + uint32_t msglen = 1; // for the count byte UlistEntry *li = ulist_head; uint32_t count = 0; while (li != NULL) { count++; - needed += strlen(li->unit.name)+1; + msglen += strlen(li->unit.name)+1; li = li->next; } - needed += count; + msglen += count; bool suc = true; - uint8_t *buff = malloc_ck(needed, &suc); + uint8_t *buff = malloc_ck(msglen, &suc); if (!suc) { tf_respond_str(MSG_ERROR, frame_id, "OUT OF MEMORY"); return; } { - PayloadBuilder pb = pb_start(buff, needed, NULL); - pb_u8(&pb, (uint8_t) count); // assume we don't have more than 255 + PayloadBuilder pb = pb_start(buff, msglen, NULL); + pb_u8(&pb, (uint8_t) count); // assume we don't have more than 255 units li = ulist_head; while (li != NULL) { @@ -571,7 +571,7 @@ void ureg_report_active_units(TF_ID frame_id) assert_param(pb.ok); - tf_respond_buf(MSG_SUCCESS, frame_id, buff, needed); + tf_respond_buf(MSG_SUCCESS, frame_id, buff, msglen); } free(buff); diff --git a/utils/build_parser.sh b/utils/build_parser.sh old mode 100755 new mode 100644 From 5ca7ab1db0b5d9646eb60d7d5f218c93921504a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Dec 2017 23:10:14 +0100 Subject: [PATCH 05/17] implement a message processing queue that will hopefully aleviate the pain in working with tinyframe. this should make it possible to almost entirely get rid of async jobs for simple replies --- USB/usbd_cdc_if.c | 8 ++++++- cortex_handlers.c | 3 +++ freertos.c | 50 +++++++++++++++++++++++++++++++++--------- tasks/sched_queue.h | 10 +++++++++ tasks/task_main.c | 2 +- tasks/task_msg.c | 20 +++++++++++++++++ tasks/task_msg.h | 12 ++++++++++ units/test/unit_test.c | 6 ++++- 8 files changed, 98 insertions(+), 13 deletions(-) create mode 100644 tasks/task_msg.c create mode 100644 tasks/task_msg.h diff --git a/USB/usbd_cdc_if.c b/USB/usbd_cdc_if.c index 52d4ce1..736aa62 100644 --- a/USB/usbd_cdc_if.c +++ b/USB/usbd_cdc_if.c @@ -48,6 +48,7 @@ /* Includes ------------------------------------------------------------------*/ #include "platform.h" +#include "tasks/task_msg.h" #include "usbd_cdc_if.h" /* USER CODE BEGIN INCLUDE */ #include "task_main.h" @@ -265,6 +266,7 @@ static int8_t CDC_Control_FS (uint8_t cmd, uint8_t* pbuf, uint16_t length) */ static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) { + static struct rx_que_item rxitem; /* USER CODE BEGIN 6 */ // this does nothing?! // the buffer was already assigned in the init function and we got it as argument here?! @@ -272,7 +274,11 @@ static int8_t CDC_Receive_FS (uint8_t* Buf, uint32_t *Len) assert_param(*Len <= APP_RX_DATA_SIZE); USBD_CDC_ReceivePacket(&hUsbDeviceFS); - TF_Accept(comm, Buf, *Len); + + // Post the data chunk on the RX queue to be handled asynchronously. + rxitem.len = *Len; + memcpy(rxitem.data, Buf, rxitem.len); + assert_param(pdPASS == xQueueSend(queRxDataHandle, &rxitem, 100)); return (USBD_OK); /* USER CODE END 6 */ diff --git a/cortex_handlers.c b/cortex_handlers.c index a0d36e7..752dcb4 100644 --- a/cortex_handlers.c +++ b/cortex_handlers.c @@ -4,6 +4,7 @@ #include #include "platform/debug_uart.h" #include "platform/status_led.h" +#include "utils/stacksmon.h" /* External variables --------------------------------------------------------*/ @@ -29,6 +30,8 @@ void vApplicationStackOverflowHook(TaskHandle_t xTask, signed char *pcTaskName) called if a stack overflow is detected. */ PRINTF(tFAULT" RTOS stack overflow! tsk: %s\r\n", (char *) pcTaskName); StatusLed_On(STATUS_FAULT); + + stackmon_dump(); while (1); } diff --git a/freertos.c b/freertos.c index f4fc74b..d042d19 100644 --- a/freertos.c +++ b/freertos.c @@ -57,23 +57,43 @@ /* USER CODE END Includes */ /* Variables -----------------------------------------------------------------*/ + +#define STACK_MAIN 160 +#define STACK_MSG 170 +#define STACK_LP 128 +#define STACK_HP 128 + osThreadId tskMainHandle; -uint32_t mainTaskBuffer[ 160 ]; +uint32_t mainTaskBuffer[ STACK_MAIN ]; osStaticThreadDef_t mainTaskControlBlock; + +osThreadId tskMsgHandle; +uint32_t msgTaskBuffer[ STACK_MSG ]; +osStaticThreadDef_t msgTaskControlBlock; + osThreadId tskSchedLPHandle; -uint32_t schedLowBuffer[ 128 ]; +uint32_t schedLowBuffer[ STACK_LP ]; osStaticThreadDef_t schedLowControlBlock; + osThreadId tskSchedHPHandle; -uint32_t schedHighBuffer[ 128 ]; +uint32_t schedHighBuffer[ STACK_HP ]; osStaticThreadDef_t schedHighControlBlock; + osMessageQId queSchedLPHandle; -uint8_t myQueue01Buffer[ 5 * sizeof( struct sched_que_item ) ]; +uint8_t myQueue01Buffer[ LP_SCHED_CAPACITY * sizeof( struct sched_que_item ) ]; osStaticMessageQDef_t myQueue01ControlBlock; + osMessageQId queSchedHPHandle; -uint8_t myQueue02Buffer[ 5 * sizeof( struct sched_que_item ) ]; +uint8_t myQueue02Buffer[ HP_SCHED_CAPACITY * sizeof( struct sched_que_item ) ]; osStaticMessageQDef_t myQueue02ControlBlock; + +osMessageQId queRxDataHandle; +uint8_t myQueue03Buffer[ RX_QUE_CAPACITY * sizeof( struct rx_que_item ) ]; +osStaticMessageQDef_t myQueue03ControlBlock; + osMutexId mutTinyFrameTxHandle; osStaticMutexDef_t myMutex01ControlBlock; + osSemaphoreId semVcomTxReadyHandle; osStaticSemaphoreDef_t myBinarySem01ControlBlock; @@ -85,6 +105,7 @@ osStaticSemaphoreDef_t myBinarySem01ControlBlock; void TaskMain(void const * argument); extern void TaskSchedLP(void const * argument); extern void TaskSchedHP(void const * argument); +extern void TaskMessaging(void const * argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ @@ -127,6 +148,7 @@ void MX_FREERTOS_Init(void) { stackmon_register("Main", mainTaskBuffer, sizeof(mainTaskBuffer)); stackmon_register("Job Queue Low", schedLowBuffer, sizeof(schedLowBuffer)); stackmon_register("Job Queue High", schedHighBuffer, sizeof(schedHighBuffer)); + stackmon_register("Messaging", msgTaskBuffer, sizeof(msgTaskBuffer)); /* USER CODE END Init */ /* Create the mutex(es) */ @@ -154,30 +176,38 @@ void MX_FREERTOS_Init(void) { /* Create the thread(s) */ /* definition and creation of tskMain */ - osThreadStaticDef(tskMain, TaskMain, osPriorityHigh, 0, 160, mainTaskBuffer, &mainTaskControlBlock); + osThreadStaticDef(tskMain, TaskMain, osPriorityHigh, 0, STACK_MAIN, mainTaskBuffer, &mainTaskControlBlock); tskMainHandle = osThreadCreate(osThread(tskMain), NULL); /* definition and creation of tskSchedLP */ - osThreadStaticDef(tskSchedLP, TaskSchedLP, osPriorityLow, 0, 128, schedLowBuffer, &schedLowControlBlock); + osThreadStaticDef(tskSchedLP, TaskSchedLP, osPriorityLow, 0, STACK_LP, schedLowBuffer, &schedLowControlBlock); tskSchedLPHandle = osThreadCreate(osThread(tskSchedLP), NULL); /* definition and creation of tskSchedHP */ - osThreadStaticDef(tskSchedHP, TaskSchedHP, osPriorityAboveNormal, 0, 128, schedHighBuffer, &schedHighControlBlock); + osThreadStaticDef(tskSchedHP, TaskSchedHP, osPriorityAboveNormal, 0, STACK_HP, schedHighBuffer, &schedHighControlBlock); tskSchedHPHandle = osThreadCreate(osThread(tskSchedHP), NULL); + /* definition and creation of TaskMessaging */ + osThreadStaticDef(tskMsg, TaskMessaging, osPriorityNormal, 0, STACK_MSG, msgTaskBuffer, &msgTaskControlBlock); + tskMsgHandle = osThreadCreate(osThread(tskMsg), NULL); + /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */ /* Create the queue(s) */ /* definition and creation of queSchedLP */ - osMessageQStaticDef(queSchedLP, 5, struct sched_que_item, myQueue01Buffer, &myQueue01ControlBlock); + osMessageQStaticDef(queSchedLP, LP_SCHED_CAPACITY, struct sched_que_item, myQueue01Buffer, &myQueue01ControlBlock); queSchedLPHandle = osMessageCreate(osMessageQ(queSchedLP), NULL); /* definition and creation of queSchedHP */ - osMessageQStaticDef(queSchedHP, 5, struct sched_que_item, myQueue02Buffer, &myQueue02ControlBlock); + osMessageQStaticDef(queSchedHP, HP_SCHED_CAPACITY, struct sched_que_item, myQueue02Buffer, &myQueue02ControlBlock); queSchedHPHandle = osMessageCreate(osMessageQ(queSchedHP), NULL); + /* definition and creation of queRxData */ + osMessageQStaticDef(queRxData, RX_QUE_CAPACITY, struct rx_que_item, myQueue03Buffer, &myQueue03ControlBlock); + queRxDataHandle = osMessageCreate(osMessageQ(queRxData), NULL); + /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ diff --git a/tasks/sched_queue.h b/tasks/sched_queue.h index 4239ede..dcae182 100644 --- a/tasks/sched_queue.h +++ b/tasks/sched_queue.h @@ -29,4 +29,14 @@ struct sched_que_item { }; }; +// This que is used to stash frames received from TinyFrame for later evaluation on the application thread +struct rx_que_item { + uint32_t len; + uint8_t data[64]; +}; + +#define LP_SCHED_CAPACITY 5 +#define HP_SCHED_CAPACITY 5 +#define RX_QUE_CAPACITY 8 + #endif //GEX_SCHED_QUEUE_H diff --git a/tasks/task_main.c b/tasks/task_main.c index 60b9e1a..3c148da 100644 --- a/tasks/task_main.c +++ b/tasks/task_main.c @@ -48,7 +48,7 @@ void TaskMain(void const * argument) // Periodically check stacks for overrun stackmon_check_canaries(); // Periodically dump all stacks - for checking levels before critical (to reduce size if not needed) -// if ((cnt%50)==0) stackmon_dump(); + if ((cnt%75)==0) stackmon_dump(); continue; } diff --git a/tasks/task_msg.c b/tasks/task_msg.c new file mode 100644 index 0000000..8c2db78 --- /dev/null +++ b/tasks/task_msg.c @@ -0,0 +1,20 @@ +// +// Created by MightyPork on 2017/12/22. +// + +#include +#include "platform.h" +#include "task_msg.h" +#include "sched_queue.h" + +void TaskMessaging(const void * argument) +{ + dbg("> Message queue task started!"); + + struct rx_que_item slot; + while (1) { + xQueueReceive(queRxDataHandle, &slot, osWaitForever); + assert_param(slot.len>0 && slot.len<=64); // check the len is within bounds + TF_Accept(comm, slot.data, slot.len); + } +} \ No newline at end of file diff --git a/tasks/task_msg.h b/tasks/task_msg.h new file mode 100644 index 0000000..ef3ffa6 --- /dev/null +++ b/tasks/task_msg.h @@ -0,0 +1,12 @@ +// +// Created by MightyPork on 2017/12/22. +// + +#ifndef GEX_F072_TASK_MSG_H +#define GEX_F072_TASK_MSG_H + +extern osMessageQId queRxDataHandle; +extern osThreadId tskMsgHandle; +void TaskMessaging(const void * argument); + +#endif //GEX_F072_TASK_MSG_H diff --git a/units/test/unit_test.c b/units/test/unit_test.c index 66b9cfe..aa1b6ce 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -196,7 +196,11 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo .buf = cpy, .len = len, }; - dbg("Rx len %d, %.*s\r\n", (int)len, (int)len, cpy); + + PRINTF("Rx len %d: ", (int)len); + PUTSN((char *) cpy, len); + PUTS("\r\n"); + scheduleJob(&job, TSK_SCHED_HIGH); break; From d6c437275513c96fce7657063ba8da4121d5be5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 10:03:37 +0100 Subject: [PATCH 06/17] updated tinyframe --- TinyFrame/TinyFrame.c | 116 ++++++++++++++++++++++++----------------- tasks/sched_queue.h | 2 +- units/test/unit_test.c | 3 +- 3 files changed, 72 insertions(+), 49 deletions(-) diff --git a/TinyFrame/TinyFrame.c b/TinyFrame/TinyFrame.c index 4ad41e7..f7d5dcb 100644 --- a/TinyFrame/TinyFrame.c +++ b/TinyFrame/TinyFrame.c @@ -1,6 +1,8 @@ //--------------------------------------------------------------------------- #include "TinyFrame.h" #include +#include +#include //--------------------------------------------------------------------------- // Compatibility with ESP8266 SDK @@ -243,6 +245,7 @@ bool _TF_FN TF_AddIdListener(TinyFrame *tf, TF_Msg *msg, TF_Listener cb, TF_TICK return true; } } + fprintf(stderr,"TF failed to add ID listener\n"); return false; } @@ -372,6 +375,13 @@ static void _TF_FN TF_HandleReceivedMessage(TinyFrame *tf) if (res == TF_RENEW) { renew_id_listener(ilst); } + + if (res == TF_CLOSE) { + // Set userdata to NULL to avoid calling user for cleanup + ilst->userdata = NULL; + ilst->userdata2 = NULL; + cleanup_id_listener(tf, i, ilst); + } return; } } @@ -389,8 +399,12 @@ static void _TF_FN TF_HandleReceivedMessage(TinyFrame *tf) res = tlst->fn(tf, &msg); if (res != TF_NEXT) { - // if it's TF_CLOSE, we assume user already cleaned up userdata - // TF_RENEW doesn't make sense here because type listeners don't expire + // type listeners don't have userdata. + // TF_RENEW doesn't make sense here because type listeners don't expire = same as TF_STAY + + if (res == TF_CLOSE) { + cleanup_type_listener(tf, i, tlst); + } return; } } @@ -404,8 +418,16 @@ static void _TF_FN TF_HandleReceivedMessage(TinyFrame *tf) res = glst->fn(tf, &msg); if (res != TF_NEXT) { - // if it's TF_CLOSE, we assume user already cleaned up userdata - // TF_RENEW doesn't make sense here because generic listeners don't expire + // generic listeners don't have userdata. + // TF_RENEW doesn't make sense here because generic listeners don't expire = same as TF_STAY + + // note: It's not expected that user will have multiple generic listeners, or + // ever actually remove them. They're most useful as default callbacks if no other listener + // handled the message. + + if (res == TF_CLOSE) { + cleanup_generic_listener(tf, i, glst); + } return; } } @@ -477,63 +499,63 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c) case TFState_ID: CKSUM_ADD(tf->cksum, c); COLLECT_NUMBER(tf->id, TF_ID) { - // Enter LEN state - tf->state = TFState_LEN; - tf->rxi = 0; - } + // Enter LEN state + tf->state = TFState_LEN; + tf->rxi = 0; + } break; case TFState_LEN: CKSUM_ADD(tf->cksum, c); COLLECT_NUMBER(tf->len, TF_LEN) { - // Enter TYPE state - tf->state = TFState_TYPE; - tf->rxi = 0; - } + // Enter TYPE state + tf->state = TFState_TYPE; + tf->rxi = 0; + } break; case TFState_TYPE: CKSUM_ADD(tf->cksum, c); COLLECT_NUMBER(tf->type, TF_TYPE) { #if TF_CKSUM_TYPE == TF_CKSUM_NONE - tf->state = TFState_DATA; + tf->state = TFState_DATA; tf->rxi = 0; #else - // enter HEAD_CKSUM state - tf->state = TFState_HEAD_CKSUM; - tf->rxi = 0; - tf->ref_cksum = 0; + // enter HEAD_CKSUM state + tf->state = TFState_HEAD_CKSUM; + tf->rxi = 0; + tf->ref_cksum = 0; #endif - } + } break; case TFState_HEAD_CKSUM: - COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { - // Check the header checksum against the computed value - CKSUM_FINALIZE(tf->cksum); + COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { + // Check the header checksum against the computed value + CKSUM_FINALIZE(tf->cksum); - if (tf->cksum != tf->ref_cksum) { - TF_ResetParser(tf); - break; - } + if (tf->cksum != tf->ref_cksum) { + TF_ResetParser(tf); + break; + } - if (tf->len == 0) { - TF_HandleReceivedMessage(tf); - TF_ResetParser(tf); - break; - } + if (tf->len == 0) { + TF_HandleReceivedMessage(tf); + TF_ResetParser(tf); + break; + } - // Enter DATA state - tf->state = TFState_DATA; - tf->rxi = 0; + // Enter DATA state + tf->state = TFState_DATA; + tf->rxi = 0; - CKSUM_RESET(tf->cksum); // Start collecting the payload + CKSUM_RESET(tf->cksum); // Start collecting the payload - if (tf->len >= TF_MAX_PAYLOAD_RX) { - // ERROR - frame too long. Consume, but do not store. - tf->discard_data = true; - } - } + if (tf->len >= TF_MAX_PAYLOAD_RX) { + // ERROR - frame too long. Consume, but do not store. + tf->discard_data = true; + } + } break; case TFState_DATA: @@ -559,15 +581,15 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c) break; case TFState_DATA_CKSUM: - COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { - // Check the header checksum against the computed value - CKSUM_FINALIZE(tf->cksum); - if (!tf->discard_data && tf->cksum == tf->ref_cksum) { - TF_HandleReceivedMessage(tf); - } + COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { + // Check the header checksum against the computed value + CKSUM_FINALIZE(tf->cksum); + if (!tf->discard_data && tf->cksum == tf->ref_cksum) { + TF_HandleReceivedMessage(tf); + } - TF_ResetParser(tf); - } + TF_ResetParser(tf); + } break; } diff --git a/tasks/sched_queue.h b/tasks/sched_queue.h index dcae182..f192eb1 100644 --- a/tasks/sched_queue.h +++ b/tasks/sched_queue.h @@ -37,6 +37,6 @@ struct rx_que_item { #define LP_SCHED_CAPACITY 5 #define HP_SCHED_CAPACITY 5 -#define RX_QUE_CAPACITY 8 +#define RX_QUE_CAPACITY 16 #endif //GEX_SCHED_QUEUE_H diff --git a/units/test/unit_test.c b/units/test/unit_test.c index aa1b6ce..8e78730 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -183,7 +183,8 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo switch (command) { case CMD_PING: - sched_respond_suc(frame_id); + tf_respond_ok(frame_id); + //sched_respond_suc(frame_id); break; case CMD_ECHO:; From ccbff578b36745a81daf1700ec6c1a1cf97863e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 12:36:16 +0100 Subject: [PATCH 07/17] tf update and some progress --- TinyFrame/TF_Config.h | 3 +- TinyFrame/TF_Integration.c | 8 ++- TinyFrame/TinyFrame.c | 126 ++++++++++++++++++------------------- comm/messages.c | 2 +- framework/unit_registry.c | 1 + freertos.c | 6 +- tasks/task_msg.c | 7 ++- units/test/unit_test.c | 3 +- 8 files changed, 82 insertions(+), 74 deletions(-) diff --git a/TinyFrame/TF_Config.h b/TinyFrame/TF_Config.h index fb9f757..f66d408 100644 --- a/TinyFrame/TF_Config.h +++ b/TinyFrame/TF_Config.h @@ -5,6 +5,7 @@ #ifndef TF_CONFIG_H #define TF_CONFIG_H +#include "platform.h" #include //#include // when using with esphttpd @@ -65,7 +66,7 @@ typedef uint8_t TF_COUNT; // Timeout for receiving & parsing a frame // ticks = number of calls to TF_Tick() -#define TF_PARSER_TIMEOUT_TICKS 10 +#define TF_PARSER_TIMEOUT_TICKS 250 //------------------------- End of user config ------------------------------ diff --git a/TinyFrame/TF_Integration.c b/TinyFrame/TF_Integration.c index c858097..de2cf0a 100644 --- a/TinyFrame/TF_Integration.c +++ b/TinyFrame/TF_Integration.c @@ -7,6 +7,7 @@ #include "platform.h" #include "task_main.h" +#include "utils/hexdump.h" #include "USB/usbd_cdc_if.h" #include "TinyFrame.h" @@ -20,9 +21,10 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len) int32_t total = (int32_t) len; while (total > 0) { assert_param(osOK == osSemaphoreWait(semVcomTxReadyHandle, 5000)); - assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, (uint16_t) MIN(total, CHUNK))); - buff += CHUNK; - total -= CHUNK; + uint16_t chunksize = (uint16_t) MIN(total, CHUNK); + assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize)); + buff += chunksize; + total -= chunksize; } } diff --git a/TinyFrame/TinyFrame.c b/TinyFrame/TinyFrame.c index f7d5dcb..07d4cf8 100644 --- a/TinyFrame/TinyFrame.c +++ b/TinyFrame/TinyFrame.c @@ -1,8 +1,6 @@ //--------------------------------------------------------------------------- #include "TinyFrame.h" #include -#include -#include //--------------------------------------------------------------------------- // Compatibility with ESP8266 SDK @@ -245,7 +243,6 @@ bool _TF_FN TF_AddIdListener(TinyFrame *tf, TF_Msg *msg, TF_Listener cb, TF_TICK return true; } } - fprintf(stderr,"TF failed to add ID listener\n"); return false; } @@ -375,8 +372,7 @@ static void _TF_FN TF_HandleReceivedMessage(TinyFrame *tf) if (res == TF_RENEW) { renew_id_listener(ilst); } - - if (res == TF_CLOSE) { + else if (res == TF_CLOSE) { // Set userdata to NULL to avoid calling user for cleanup ilst->userdata = NULL; ilst->userdata2 = NULL; @@ -485,10 +481,11 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c) #if !TF_USE_SOF_BYTE if (tf->state == TFState_SOF) { - TF_ParsBeginFrame(); - } + TF_ParsBeginFrame(); + } #endif + //@formatter:off switch (tf->state) { case TFState_SOF: if (c == TF_SOF_BYTE) { @@ -499,63 +496,63 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c) case TFState_ID: CKSUM_ADD(tf->cksum, c); COLLECT_NUMBER(tf->id, TF_ID) { - // Enter LEN state - tf->state = TFState_LEN; - tf->rxi = 0; - } + // Enter LEN state + tf->state = TFState_LEN; + tf->rxi = 0; + } break; case TFState_LEN: CKSUM_ADD(tf->cksum, c); COLLECT_NUMBER(tf->len, TF_LEN) { - // Enter TYPE state - tf->state = TFState_TYPE; - tf->rxi = 0; - } + // Enter TYPE state + tf->state = TFState_TYPE; + tf->rxi = 0; + } break; case TFState_TYPE: CKSUM_ADD(tf->cksum, c); COLLECT_NUMBER(tf->type, TF_TYPE) { -#if TF_CKSUM_TYPE == TF_CKSUM_NONE - tf->state = TFState_DATA; - tf->rxi = 0; -#else - // enter HEAD_CKSUM state - tf->state = TFState_HEAD_CKSUM; - tf->rxi = 0; - tf->ref_cksum = 0; -#endif - } + #if TF_CKSUM_TYPE == TF_CKSUM_NONE + tf->state = TFState_DATA; + tf->rxi = 0; + #else + // enter HEAD_CKSUM state + tf->state = TFState_HEAD_CKSUM; + tf->rxi = 0; + tf->ref_cksum = 0; + #endif + } break; case TFState_HEAD_CKSUM: - COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { - // Check the header checksum against the computed value - CKSUM_FINALIZE(tf->cksum); + COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { + // Check the header checksum against the computed value + CKSUM_FINALIZE(tf->cksum); - if (tf->cksum != tf->ref_cksum) { - TF_ResetParser(tf); - break; - } + if (tf->cksum != tf->ref_cksum) { + TF_ResetParser(tf); + break; + } - if (tf->len == 0) { - TF_HandleReceivedMessage(tf); - TF_ResetParser(tf); - break; - } + if (tf->len == 0) { + TF_HandleReceivedMessage(tf); + TF_ResetParser(tf); + break; + } - // Enter DATA state - tf->state = TFState_DATA; - tf->rxi = 0; + // Enter DATA state + tf->state = TFState_DATA; + tf->rxi = 0; - CKSUM_RESET(tf->cksum); // Start collecting the payload + CKSUM_RESET(tf->cksum); // Start collecting the payload - if (tf->len >= TF_MAX_PAYLOAD_RX) { - // ERROR - frame too long. Consume, but do not store. - tf->discard_data = true; - } - } + if (tf->len >= TF_MAX_PAYLOAD_RX) { + // ERROR - frame too long. Consume, but do not store. + tf->discard_data = true; + } + } break; case TFState_DATA: @@ -567,31 +564,32 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c) } if (tf->rxi == tf->len) { -#if TF_CKSUM_TYPE == TF_CKSUM_NONE - // All done - TF_HandleReceivedMessage(); - TF_ResetParser(); -#else - // Enter DATA_CKSUM state - tf->state = TFState_DATA_CKSUM; - tf->rxi = 0; - tf->ref_cksum = 0; -#endif + #if TF_CKSUM_TYPE == TF_CKSUM_NONE + // All done + TF_HandleReceivedMessage(); + TF_ResetParser(); + #else + // Enter DATA_CKSUM state + tf->state = TFState_DATA_CKSUM; + tf->rxi = 0; + tf->ref_cksum = 0; + #endif } break; case TFState_DATA_CKSUM: - COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { - // Check the header checksum against the computed value - CKSUM_FINALIZE(tf->cksum); - if (!tf->discard_data && tf->cksum == tf->ref_cksum) { - TF_HandleReceivedMessage(tf); - } + COLLECT_NUMBER(tf->ref_cksum, TF_CKSUM) { + // Check the header checksum against the computed value + CKSUM_FINALIZE(tf->cksum); + if (!tf->discard_data && tf->cksum == tf->ref_cksum) { + TF_HandleReceivedMessage(tf); + } - TF_ResetParser(tf); - } + TF_ResetParser(tf); + } break; } + //@formatter:on // we get here after finishing HEAD, if no data are to be received - handle and clear if (tf->len == 0 && tf->state == TFState_DATA) { diff --git a/comm/messages.c b/comm/messages.c index 25fb1aa..8714d2e 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -57,7 +57,7 @@ static void job_unhandled_resp(Job *job) static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg) { - dbg("!! Unhandled msg type %d, frame_id %d", (int)msg->type, (int)msg->frame_id); + dbg("!! Unhandled msg type %02"PRIx8", frame_id 0x%04"PRIx16, msg->type, msg->frame_id); Job job = { .cb = job_unhandled_resp, .frame_id = msg->frame_id, diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 7b2b123..e933253 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -2,6 +2,7 @@ // Created by MightyPork on 2017/11/26. // +#include #include "platform.h" #include "utils/avrlibc.h" #include "comm/messages.h" diff --git a/freertos.c b/freertos.c index d042d19..7cd05f5 100644 --- a/freertos.c +++ b/freertos.c @@ -59,9 +59,9 @@ /* Variables -----------------------------------------------------------------*/ #define STACK_MAIN 160 -#define STACK_MSG 170 -#define STACK_LP 128 -#define STACK_HP 128 +#define STACK_MSG 230 +#define STACK_LP 180 +#define STACK_HP 150 osThreadId tskMainHandle; uint32_t mainTaskBuffer[ STACK_MAIN ]; diff --git a/tasks/task_msg.c b/tasks/task_msg.c index 8c2db78..da7b415 100644 --- a/tasks/task_msg.c +++ b/tasks/task_msg.c @@ -2,8 +2,9 @@ // Created by MightyPork on 2017/12/22. // -#include #include "platform.h" +#include "comm/messages.h" +#include "utils/hexdump.h" #include "task_msg.h" #include "sched_queue.h" @@ -15,6 +16,10 @@ void TaskMessaging(const void * argument) while (1) { xQueueReceive(queRxDataHandle, &slot, osWaitForever); assert_param(slot.len>0 && slot.len<=64); // check the len is within bounds + + + hexDump("MSG", slot.data, slot.len); + TF_Accept(comm, slot.data, slot.len); } } \ No newline at end of file diff --git a/units/test/unit_test.c b/units/test/unit_test.c index 8e78730..f310064 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -183,6 +183,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo switch (command) { case CMD_PING: + dbg("Ping msg!"); tf_respond_ok(frame_id); //sched_respond_suc(frame_id); break; @@ -198,7 +199,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo .len = len, }; - PRINTF("Rx len %d: ", (int)len); + PRINTF("ECHO, len %d: ", (int)len); PUTSN((char *) cpy, len); PUTS("\r\n"); From eb58fce25a42c0695eef72bada29c9ace66dad41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 16:31:52 +0100 Subject: [PATCH 08/17] updated tf --- TinyFrame/TF_Integration.c | 7 +++++++ TinyFrame/TinyFrame.c | 18 +++++++++++------- TinyFrame/TinyFrame.h | 8 ++++---- 3 files changed, 22 insertions(+), 11 deletions(-) diff --git a/TinyFrame/TF_Integration.c b/TinyFrame/TF_Integration.c index de2cf0a..5ddae3d 100644 --- a/TinyFrame/TF_Integration.c +++ b/TinyFrame/TF_Integration.c @@ -23,6 +23,13 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len) assert_param(osOK == osSemaphoreWait(semVcomTxReadyHandle, 5000)); uint16_t chunksize = (uint16_t) MIN(total, CHUNK); assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize)); + + PUTS("Tx: "); + for(int i=0;ilen == 0) { + // if the message has no body, we're done. TF_HandleReceivedMessage(tf); TF_ResetParser(tf); break; @@ -773,16 +774,19 @@ static bool _TF_FN TF_SendFrame(TinyFrame *tf, TF_Msg *msg, TF_Listener listener } } - // Flush if checksum wouldn't fit in the buffer - if (TF_SENDBUF_LEN - len < sizeof(TF_CKSUM)) { - TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, len); - len = 0; + // Checksum only if message had a body + if (msg->len > 0) { + // Flush if checksum wouldn't fit in the buffer + if (TF_SENDBUF_LEN - len < sizeof(TF_CKSUM)) { + TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, len); + len = 0; + } + + // Add checksum, flush what remains to be sent + len += TF_ComposeTail(tf->sendbuf + len, &cksum); } - // Add checksum, flush what remains to be sent - len += TF_ComposeTail(tf->sendbuf+len, &cksum); TF_WriteImpl(tf, (const uint8_t *) tf->sendbuf, len); - TF_ReleaseTx(tf); return true; diff --git a/TinyFrame/TinyFrame.h b/TinyFrame/TinyFrame.h index a4d92df..a588309 100644 --- a/TinyFrame/TinyFrame.h +++ b/TinyFrame/TinyFrame.h @@ -3,14 +3,14 @@ /** * TinyFrame protocol library - * - * (c) Ondřej Hruška 2017, MIT License + * + * (c) Ondřej Hruška 2017, MIT License * no liability/warranty, free for any use, must retain this notice & license - * + * * Upstream URL: https://github.com/MightyPork/TinyFrame */ -#define TF_VERSION "2.0.1" +#define TF_VERSION "2.0.3" //--------------------------------------------------------------------------- #include // for uint8_t etc From d8e2d016d20e067574663cf5662951b6d0d9bf7f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 18:36:44 +0100 Subject: [PATCH 09/17] modularized bulk read --- TinyFrame/TF_Integration.c | 6 -- comm/messages.h | 6 +- comm/msg_bulkread.c | 94 +++++++++++++++++++++++++++++ comm/msg_bulkread.h | 32 ++++++++++ tasks/task_msg.c | 12 +++- units/test/unit_test.c | 120 +++++-------------------------------- utils/macro.h | 4 +- 7 files changed, 154 insertions(+), 120 deletions(-) create mode 100644 comm/msg_bulkread.c create mode 100644 comm/msg_bulkread.h diff --git a/TinyFrame/TF_Integration.c b/TinyFrame/TF_Integration.c index 5ddae3d..4f38df7 100644 --- a/TinyFrame/TF_Integration.c +++ b/TinyFrame/TF_Integration.c @@ -24,12 +24,6 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len) uint16_t chunksize = (uint16_t) MIN(total, CHUNK); assert_param(USBD_OK == CDC_Transmit_FS((uint8_t *) buff, chunksize)); - PUTS("Tx: "); - for(int i=0;i + +#include "messages.h" +#include "utils/payload_parser.h" +#include "utils/payload_builder.h" + +static uint8_t bulkread_buffer[BULKREAD_MAX_CHUNK]; + +TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) +{ + // this is a final call before timeout, to clean up + if (msg->data == NULL) { + dbg("Bulk rx lst cleanup\r\n"); + goto close; + } + + struct bulk_read *bulk = msg->userdata; + assert_param(NULL != bulk); + + if (msg->type == MSG_BULK_ABORT) { + goto close; + } else if (msg->type == MSG_BULK_READ_POLL) { + PayloadParser pp = pp_start(msg->data, msg->len, NULL); + uint32_t chunk = pp_u32(&pp); + + // if past len, say we're done and close + if (bulk->offset >= bulk->len) { + TF_ClearMsg(msg); + msg->frame_id = bulk->frame_id; + msg->type = MSG_BULK_END; + TF_Respond(tf, msg); + goto close; + } + + chunk = MIN(chunk, bulk->len - bulk->offset); + chunk = MIN(chunk, BULKREAD_MAX_CHUNK); + + bulk->read(bulk->offset, chunk, bulkread_buffer); + + TF_ClearMsg(msg); + msg->frame_id = bulk->frame_id; + msg->type = MSG_BULK_DATA; + msg->data = bulkread_buffer; + msg->len = (TF_LEN) chunk; + TF_Respond(tf, msg); + + // advance the position pointer + bulk->offset += chunk; + } + + msg->userdata = bulk; // We must put it back + return TF_RENEW; + + close: + if (msg->userdata) { + free(msg->userdata); + msg->userdata = NULL; + } + return TF_CLOSE; +} + +void bulkread_start(TinyFrame *tf, struct bulk_read *bulk) +{ + assert_param(bulk); + assert_param(bulk->len); + assert_param(bulk->read); + + bulk->offset = 0; + + { + uint8_t buf[8]; + PayloadBuilder pb = pb_start(buf, 4, NULL); + pb_u32(&pb, bulk->len); + pb_u32(&pb, BULKREAD_MAX_CHUNK); + + // We use userdata1 to hold a reference to the bulk transfer + TF_Msg msg = { + .type = MSG_BULK_READ_OFFER, + .frame_id = bulk->frame_id, + .is_response = true, // this ensures the frame_id is not re-generated + .data = buf, + .len = (TF_LEN) pb_length(&pb), + .userdata = bulk, + }; + + TF_Query(tf, &msg, bulkread_lst, BULK_LST_TIMEOUT_MS); + } +} diff --git a/comm/msg_bulkread.h b/comm/msg_bulkread.h new file mode 100644 index 0000000..8a23c4d --- /dev/null +++ b/comm/msg_bulkread.h @@ -0,0 +1,32 @@ +// +// Created by MightyPork on 2017/12/23. +// + +#ifndef GEX_F072_MSG_BULKREAD_H +#define GEX_F072_MSG_BULKREAD_H + +#ifndef GEX_MESSAGES_H +#error "Include messages.h instead!" +#endif + +#include + + +#define BULK_LST_TIMEOUT_MS 200 + +#define BULKREAD_MAX_CHUNK 512 // this is a static buffer + + +typedef void (*bulkread_data_cb)(uint32_t offset, uint32_t len, uint8_t *buffer); + +struct bulk_read { + TF_ID frame_id; + bulkread_data_cb read; + uint32_t len; + uint32_t offset; +}; + +void bulkread_start(TinyFrame *tf, struct bulk_read *bulk); + + +#endif //GEX_F072_MSG_BULKREAD_H diff --git a/tasks/task_msg.c b/tasks/task_msg.c index da7b415..b4bcc35 100644 --- a/tasks/task_msg.c +++ b/tasks/task_msg.c @@ -8,6 +8,15 @@ #include "task_msg.h" #include "sched_queue.h" +/** + * Process data received from TinyFrame. + * The queue holds received messages or parts of messages, + * copied there by the USB thread. + * + * Since this is a separate thread that handles TF input and runs the listeners, + * TF functions (send, respond) can be called immediately without the need for an + * intermediate queued job. + */ void TaskMessaging(const void * argument) { dbg("> Message queue task started!"); @@ -17,9 +26,6 @@ void TaskMessaging(const void * argument) xQueueReceive(queRxDataHandle, &slot, osWaitForever); assert_param(slot.len>0 && slot.len<=64); // check the len is within bounds - - hexDump("MSG", slot.data, slot.len); - TF_Accept(comm, slot.data, slot.len); } } \ No newline at end of file diff --git a/units/test/unit_test.c b/units/test/unit_test.c index f310064..20bf153 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -95,83 +95,11 @@ enum PinCmd_ { CMD_BULKREAD = 2, }; -static void job_echo(Job *job) -{ - tf_respond_buf(MSG_SUCCESS, job->frame_id, job->buf, job->len); - free(job->buf); -} - -const char *longtext = "The history of all hitherto existing societies is the history of class struggles.\n\nFreeman and slave, patrician and plebeian, lord and serf, guild-master and journeyman, in a word, oppressor and oppressed, stood in constant opposition to one another, carried on an uninterrupted, now hidden, now open fight, a fight that each time ended, either in a revolutionary re-constitution of society at large, or in the common ruin of the contending classes.\n\nIn the earlier epochs of history, we find almost everywhere a complicated arrangement of society into various orders, a manifold gradation of social rank. In ancient Rome we have patricians, knights, plebeians, slaves; in the Middle Ages, feudal lords, vassals, guild-masters, journeymen, apprentices, serfs; in almost all of these classes, again, subordinate gradations.\n\nThe modern bourgeois society that has sprouted from the ruins of feudal society has not done away with class antagonisms. It has but established new classes, new conditions of oppression, new forms of struggle in place of the old ones. Our epoch, the epoch of the bourgeoisie, possesses, however, this distinctive feature: it has simplified the class antagonisms. Society as a whole is more and more splitting up into two great hostile camps, into two great classes, directly facing each other: Bourgeoisie and Proletariat.\n\nFrom the serfs of the Middle Ages sprang the chartered burghers of the earliest towns. From these burgesses the first elements of the bourgeoisie were developed.\n\nThe discovery of America, the rounding of the Cape, opened up fresh ground for the rising bourgeoisie. The East-Indian and Chinese markets, the colonisation of America, trade with the colonies, the increase in the means of exchange and in commodities generally, gave to commerce, to navigation, to industry, an impulse never before known, and thereby, to the revolutionary element in the tottering feudal society, a rapid development.\n\nThe feudal system of industry, under which industrial production was monopolised by closed guilds, now no longer sufficed for the growing wants of the new markets. The manufacturing system took its place. The guild-masters were pushed on one side by the manufacturing middle class; division of labour between the different corporate guilds vanished in the face of division of labour in each single workshop.\n\nMeantime the markets kept ever growing, the demand ever rising. Even manufacture no longer sufficed. Thereupon, steam and machinery revolutionised industrial production. The place of manufacture was taken by the giant, Modern Industry, the place of the industrial middle class, by industrial millionaires, the leaders of whole industrial armies, the modern bourgeois.\n\nModern industry has established the world-market, for which the discovery of America paved the way. This market has given an immense development to commerce, to navigation, to communication by land. This development has, in its time, reacted on the extension of industry; and in proportion as industry, commerce, navigation, railways extended, in the same proportion the bourgeoisie developed, increased its capital, and pushed into the background every class handed down from the Middle Ages.\n\nWe see, therefore, how the modern bourgeoisie is itself the product of a long course of development, of a series of revolutions in the modes of production and of exchange.\n\nEach step in the development of the bourgeoisie was accompanied by a corresponding political advance of that class. An oppressed class under the sway of the feudal nobility, an armed and self-governing association in the mediaeval commune; here independent urban republic (as in Italy and Germany), there taxable \"third estate\" of the monarchy (as in France), afterwards, in the period of manufacture proper, serving either the semi-feudal or the absolute monarchy as a counterpoise against the nobility, and, in fact, corner-stone of the great monarchies in general, the bourgeoisie has at last, since the establishment of Modern Industry and of the world-market, conquered for itself, in the modern representative State, exclusive political sway. The executive of the modern State is but a committee for managing the common affairs of the whole bourgeoisie."; - -static void job_bulkread_chunk(Job *job) -{ - dbg("Tx a chunk of size %d", (int)job->len); - tf_respond_buf(MSG_BULK_DATA, job->frame_id, job->buf, job->len); -} - -static void job_bulkread_close(Job *job) -{ - dbg("Bulk read close."); - tf_respond_buf(MSG_BULK_END, job->frame_id, NULL, 0); -} - -static void job_bulkread_offer(Job *job) -{ - uint8_t buf[10]; - PayloadBuilder pb = pb_start(buf, 10, NULL); - pb_u32(&pb, job->d32); - - dbg("Offer bulk xfer of %d bytes", (int)job->d32); +static const char *longtext = "The history of all hitherto existing societies is the history of class struggles.\n\nFreeman and slave, patrician and plebeian, lord and serf, guild-master and journeyman, in a word, oppressor and oppressed, stood in constant opposition to one another, carried on an uninterrupted, now hidden, now open fight, a fight that each time ended, either in a revolutionary re-constitution of society at large, or in the common ruin of the contending classes.\n\nIn the earlier epochs of history, we find almost everywhere a complicated arrangement of society into various orders, a manifold gradation of social rank. In ancient Rome we have patricians, knights, plebeians, slaves; in the Middle Ages, feudal lords, vassals, guild-masters, journeymen, apprentices, serfs; in almost all of these classes, again, subordinate gradations.\n\nThe modern bourgeois society that has sprouted from the ruins of feudal society has not done away with class antagonisms. It has but established new classes, new conditions of oppression, new forms of struggle in place of the old ones. Our epoch, the epoch of the bourgeoisie, possesses, however, this distinctive feature: it has simplified the class antagonisms. Society as a whole is more and more splitting up into two great hostile camps, into two great classes, directly facing each other: Bourgeoisie and Proletariat.\n\nFrom the serfs of the Middle Ages sprang the chartered burghers of the earliest towns. From these burgesses the first elements of the bourgeoisie were developed.\n\nThe discovery of America, the rounding of the Cape, opened up fresh ground for the rising bourgeoisie. The East-Indian and Chinese markets, the colonisation of America, trade with the colonies, the increase in the means of exchange and in commodities generally, gave to commerce, to navigation, to industry, an impulse never before known, and thereby, to the revolutionary element in the tottering feudal society, a rapid development.\n\nThe feudal system of industry, under which industrial production was monopolised by closed guilds, now no longer sufficed for the growing wants of the new markets. The manufacturing system took its place. The guild-masters were pushed on one side by the manufacturing middle class; division of labour between the different corporate guilds vanished in the face of division of labour in each single workshop.\n\nMeantime the markets kept ever growing, the demand ever rising. Even manufacture no longer sufficed. Thereupon, steam and machinery revolutionised industrial production. The place of manufacture was taken by the giant, Modern Industry, the place of the industrial middle class, by industrial millionaires, the leaders of whole industrial armies, the modern bourgeois.\n\nModern industry has established the world-market, for which the discovery of America paved the way. This market has given an immense development to commerce, to navigation, to communication by land. This development has, in its time, reacted on the extension of industry; and in proportion as industry, commerce, navigation, railways extended, in the same proportion the bourgeoisie developed, increased its capital, and pushed into the background every class handed down from the Middle Ages.\n\nWe see, therefore, how the modern bourgeoisie is itself the product of a long course of development, of a series of revolutions in the modes of production and of exchange.\n\nEach step in the development of the bourgeoisie was accompanied by a corresponding political advance of that class. An oppressed class under the sway of the feudal nobility, an armed and self-governing association in the mediaeval commune; here independent urban republic (as in Italy and Germany), there taxable \"third estate\" of the monarchy (as in France), afterwards, in the period of manufacture proper, serving either the semi-feudal or the absolute monarchy as a counterpoise against the nobility, and, in fact, corner-stone of the great monarchies in general, the bourgeoisie has at last, since the establishment of Modern Industry and of the world-market, conquered for itself, in the modern representative State, exclusive political sway. The executive of the modern State is but a committee for managing the common affairs of the whole bourgeoisie."; - tf_respond_buf(MSG_BULK_READ_OFFER, job->frame_id, buf, (uint32_t) pb_length(&pb)); -} - -static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) +static void br_longtext(uint32_t offset, uint32_t len, uint8_t *buffer) { - if (msg->data == NULL) { - dbg("Bulk rx lst cleanup\r\n"); - return TF_CLOSE; - } // this is a final call before timeout, to clean up - - if (msg->type == MSG_BULK_READ_POLL) { - uint32_t pos = (uint32_t) msg->userdata2; - uint32_t total = (uint32_t) strlen(longtext); // normally we'd not calculate it here - - dbg("BR poll, at %d", (int)pos); - - // Say we're done and close if it's over - if (pos >= total) { - Job job = { - .cb = job_bulkread_close, - .frame_id = msg->frame_id - }; - scheduleJob(&job, TSK_SCHED_HIGH); - return TF_CLOSE; - } - - PayloadParser pp = pp_start(msg->data, msg->len, NULL); - uint32_t chunk = pp_u32(&pp); - chunk = MIN(chunk, total - pos); - - // this isn't at all resistant to error, we expect the communication to be lossless - Job job = { - .cb = job_bulkread_chunk, - .frame_id = msg->frame_id, - .buf = (uint8_t *) (longtext + pos), - .len = chunk, - }; - scheduleJob(&job, TSK_SCHED_HIGH); - - // advance the position pointer - pos += chunk; - msg->userdata2 = (void *) pos; - } - - if (msg->type == MSG_BULK_ABORT) { - return TF_CLOSE; - } - - return TF_RENEW; + memcpy(buffer, longtext+offset, len); } /** Handle a request message */ @@ -183,44 +111,24 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo switch (command) { case CMD_PING: - dbg("Ping msg!"); tf_respond_ok(frame_id); - //sched_respond_suc(frame_id); break; case CMD_ECHO:; - uint32_t len = (uint32_t) pp_length(pp); - uint8_t *cpy = malloc(len); - memcpy(cpy, pp_tail(pp, NULL), len); - Job job = { - .cb = job_echo, - .frame_id = frame_id, - .buf = cpy, - .len = len, - }; - - PRINTF("ECHO, len %d: ", (int)len); - PUTSN((char *) cpy, len); - PUTS("\r\n"); - - scheduleJob(&job, TSK_SCHED_HIGH); + uint32_t len; + const uint8_t *data = pp_tail(pp, &len); + tf_respond_buf(MSG_SUCCESS, frame_id, data, len); break; case CMD_BULKREAD:; - TF_Msg msg = { - .frame_id = frame_id, - .userdata = unit, // we'll keep a reference to the unit here - .userdata2 = 0 // and current position here. - }; - // in a real scenario, we'd put a malloc'd struct here. - TF_AddIdListener(comm, &msg, bulkread_lst, 500); - - Job job2 = { - .cb = job_bulkread_offer, - .frame_id = frame_id, - .d32 = (uint32_t) strlen(longtext), - }; - scheduleJob(&job2, TSK_SCHED_HIGH); + struct bulk_read *bulk = malloc(sizeof(struct bulk_read)); + assert_param(bulk); + + bulk->len = (uint32_t) strlen(longtext); + bulk->frame_id = frame_id; + bulk->read = br_longtext; + + bulkread_start(comm, bulk); break; default: diff --git a/utils/macro.h b/utils/macro.h index 6057624..924e529 100644 --- a/utils/macro.h +++ b/utils/macro.h @@ -35,11 +35,11 @@ extern "C" { #define KB(size) ((size) * 1024) #ifndef MIN -#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif #ifndef MAX -#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) #endif #define ROUND_UP(value, boundary) ((value) + ((boundary) - (value)) % (boundary)) From 96d06a086f5c7fdc9eb048d14a9f5ed1ce75e5d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 19:10:23 +0100 Subject: [PATCH 10/17] improved bulk read api --- comm/msg_bulkread.c | 15 +++++++++++---- comm/msg_bulkread.h | 32 +++++++++++++++++++++++++------- units/test/unit_test.c | 10 ++++++++-- 3 files changed, 44 insertions(+), 13 deletions(-) diff --git a/comm/msg_bulkread.c b/comm/msg_bulkread.c index 823e293..24fbc47 100644 --- a/comm/msg_bulkread.c +++ b/comm/msg_bulkread.c @@ -10,17 +10,22 @@ #include "utils/payload_parser.h" #include "utils/payload_builder.h" +/** Buffer for preparing bulk chunks */ static uint8_t bulkread_buffer[BULKREAD_MAX_CHUNK]; -TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) +/** + * TF listener for the bulk read transaction + */ +static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) { + struct bulk_read *bulk = msg->userdata; + // this is a final call before timeout, to clean up if (msg->data == NULL) { dbg("Bulk rx lst cleanup\r\n"); goto close; } - struct bulk_read *bulk = msg->userdata; assert_param(NULL != bulk); if (msg->type == MSG_BULK_ABORT) { @@ -41,7 +46,7 @@ TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) chunk = MIN(chunk, bulk->len - bulk->offset); chunk = MIN(chunk, BULKREAD_MAX_CHUNK); - bulk->read(bulk->offset, chunk, bulkread_buffer); + bulk->read(bulk, chunk, bulkread_buffer); TF_ClearMsg(msg); msg->frame_id = bulk->frame_id; @@ -59,12 +64,14 @@ TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) close: if (msg->userdata) { - free(msg->userdata); + // Ask user to free the bulk and userdata + bulk->read(bulk, 0, NULL); msg->userdata = NULL; } return TF_CLOSE; } +/** Start the bulk read flow */ void bulkread_start(TinyFrame *tf, struct bulk_read *bulk) { assert_param(bulk); diff --git a/comm/msg_bulkread.h b/comm/msg_bulkread.h index 8a23c4d..5226d6c 100644 --- a/comm/msg_bulkread.h +++ b/comm/msg_bulkread.h @@ -16,16 +16,34 @@ #define BULKREAD_MAX_CHUNK 512 // this is a static buffer - -typedef void (*bulkread_data_cb)(uint32_t offset, uint32_t len, uint8_t *buffer); - +typedef struct bulk_read BulkRead; + +/** + * Type of the bulk-read listener. Offset within the data can be retrieved from bulk->offset. + * + * If buffer is NULL, this is the last call and the bulk struct must be freed if it was allocated. + * + * @param bulk - a data object passed to the bulkread_start() function. + * @param chunk - size of the chunk to read + * @param buffer - destination buffer to fill with the data. NULL if bulk should be freed. + */ +typedef void (*bulkread_data_cb)(BulkRead *bulk, uint32_t chunk, uint8_t *buffer); + +/** Bulk read structure */ struct bulk_read { - TF_ID frame_id; - bulkread_data_cb read; - uint32_t len; - uint32_t offset; + TF_ID frame_id; //!< ID of the requesting frame, used for the entire bulk read session + bulkread_data_cb read; //!< Read callback + uint32_t len; //!< Total data length + void *userdata; //!< A place for arbitrary userdata + + uint32_t offset; //!< Internal offset counter, will be set to 0 on start. }; +/** + * Start a bulk read session + * @param tf - tinyframe instance + * @param bulk - bulk read config structure (malloc'd or static) + */ void bulkread_start(TinyFrame *tf, struct bulk_read *bulk); diff --git a/units/test/unit_test.c b/units/test/unit_test.c index 20bf153..9251661 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -97,9 +97,15 @@ enum PinCmd_ { static const char *longtext = "The history of all hitherto existing societies is the history of class struggles.\n\nFreeman and slave, patrician and plebeian, lord and serf, guild-master and journeyman, in a word, oppressor and oppressed, stood in constant opposition to one another, carried on an uninterrupted, now hidden, now open fight, a fight that each time ended, either in a revolutionary re-constitution of society at large, or in the common ruin of the contending classes.\n\nIn the earlier epochs of history, we find almost everywhere a complicated arrangement of society into various orders, a manifold gradation of social rank. In ancient Rome we have patricians, knights, plebeians, slaves; in the Middle Ages, feudal lords, vassals, guild-masters, journeymen, apprentices, serfs; in almost all of these classes, again, subordinate gradations.\n\nThe modern bourgeois society that has sprouted from the ruins of feudal society has not done away with class antagonisms. It has but established new classes, new conditions of oppression, new forms of struggle in place of the old ones. Our epoch, the epoch of the bourgeoisie, possesses, however, this distinctive feature: it has simplified the class antagonisms. Society as a whole is more and more splitting up into two great hostile camps, into two great classes, directly facing each other: Bourgeoisie and Proletariat.\n\nFrom the serfs of the Middle Ages sprang the chartered burghers of the earliest towns. From these burgesses the first elements of the bourgeoisie were developed.\n\nThe discovery of America, the rounding of the Cape, opened up fresh ground for the rising bourgeoisie. The East-Indian and Chinese markets, the colonisation of America, trade with the colonies, the increase in the means of exchange and in commodities generally, gave to commerce, to navigation, to industry, an impulse never before known, and thereby, to the revolutionary element in the tottering feudal society, a rapid development.\n\nThe feudal system of industry, under which industrial production was monopolised by closed guilds, now no longer sufficed for the growing wants of the new markets. The manufacturing system took its place. The guild-masters were pushed on one side by the manufacturing middle class; division of labour between the different corporate guilds vanished in the face of division of labour in each single workshop.\n\nMeantime the markets kept ever growing, the demand ever rising. Even manufacture no longer sufficed. Thereupon, steam and machinery revolutionised industrial production. The place of manufacture was taken by the giant, Modern Industry, the place of the industrial middle class, by industrial millionaires, the leaders of whole industrial armies, the modern bourgeois.\n\nModern industry has established the world-market, for which the discovery of America paved the way. This market has given an immense development to commerce, to navigation, to communication by land. This development has, in its time, reacted on the extension of industry; and in proportion as industry, commerce, navigation, railways extended, in the same proportion the bourgeoisie developed, increased its capital, and pushed into the background every class handed down from the Middle Ages.\n\nWe see, therefore, how the modern bourgeoisie is itself the product of a long course of development, of a series of revolutions in the modes of production and of exchange.\n\nEach step in the development of the bourgeoisie was accompanied by a corresponding political advance of that class. An oppressed class under the sway of the feudal nobility, an armed and self-governing association in the mediaeval commune; here independent urban republic (as in Italy and Germany), there taxable \"third estate\" of the monarchy (as in France), afterwards, in the period of manufacture proper, serving either the semi-feudal or the absolute monarchy as a counterpoise against the nobility, and, in fact, corner-stone of the great monarchies in general, the bourgeoisie has at last, since the establishment of Modern Industry and of the world-market, conquered for itself, in the modern representative State, exclusive political sway. The executive of the modern State is but a committee for managing the common affairs of the whole bourgeoisie."; -static void br_longtext(uint32_t offset, uint32_t len, uint8_t *buffer) +static void br_longtext(struct bulk_read *bulk, uint32_t chunk, uint8_t *buffer) { - memcpy(buffer, longtext+offset, len); + // clean-up request + if (buffer == NULL) { + free(bulk); + return; + } + + memcpy(buffer, longtext+bulk->offset, chunk); } /** Handle a request message */ From 97b6fd0028e5c28f158c2d60cbb41af6fcf3d3c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 20:21:52 +0100 Subject: [PATCH 11/17] removed all uses of the jobs queue for TF responses, not needed naymore --- comm/messages.c | 36 ++------------- comm/msg_responses.c | 84 +++++++++------------------------- comm/msg_responses.h | 30 ++++-------- framework/unit_registry.c | 16 ++----- units/neopixel/unit_neopixel.c | 4 +- units/pin/unit_pin.c | 8 ++-- units/test/unit_test.c | 2 +- 7 files changed, 43 insertions(+), 137 deletions(-) diff --git a/comm/messages.c b/comm/messages.c index 8714d2e..2d99935 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -32,39 +32,19 @@ void comm_init(void) // --------------------------------------------------------------------------- -static void job_ping_reply(Job *job) -{ - tf_respond_snprintf(MSG_SUCCESS, job->frame_id, "%s/%s", GEX_VERSION, GEX_PLATFORM); -} - static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg) { - Job job = { - .cb = job_ping_reply, - .frame_id = msg->frame_id - }; - scheduleJob(&job, TSK_SCHED_LOW); - + tf_respond_snprintf(MSG_SUCCESS, msg->frame_id, "%s/%s", GEX_VERSION, GEX_PLATFORM); return TF_STAY; } // ---------------------------------------------------------------------------- -static void job_unhandled_resp(Job *job) -{ - tf_respond_snprintf(MSG_ERROR, job->frame_id, "UNKNOWN MSG %"PRIu32, job->d32); -} - static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg) { dbg("!! Unhandled msg type %02"PRIx8", frame_id 0x%04"PRIx16, msg->type, msg->frame_id); - Job job = { - .cb = job_unhandled_resp, - .frame_id = msg->frame_id, - .d32 = msg->type - }; - scheduleJob(&job, TSK_SCHED_LOW); + tf_respond_snprintf(MSG_ERROR, msg->frame_id, "UNKNOWN MSG %"PRIu8, msg->type); return TF_STAY; } @@ -78,18 +58,8 @@ static TF_Result lst_unit(TinyFrame *tf, TF_Msg *msg) // ---------------------------------------------------------------------------- -static void job_list_units(Job *job) -{ - ureg_report_active_units(job->frame_id); -} - static TF_Result lst_list_units(TinyFrame *tf, TF_Msg *msg) { - Job job = { - .cb = job_list_units, - .frame_id = msg->frame_id, - }; - scheduleJob(&job, TSK_SCHED_LOW); - + ureg_report_active_units(msg->frame_id); return TF_STAY; } diff --git a/comm/msg_responses.c b/comm/msg_responses.c index fdcbff7..5c09325 100644 --- a/comm/msg_responses.c +++ b/comm/msg_responses.c @@ -8,6 +8,7 @@ void tf_respond_snprintf(TF_TYPE type, TF_ID id, const char *format, ...) { #define ERR_STR_LEN 64 + char buf[ERR_STR_LEN]; va_list args; va_start(args, format); @@ -32,6 +33,12 @@ void tf_respond_buf(TF_TYPE type, TF_ID id, const uint8_t *buf, uint32_t len) } +void tf_respond_ok(TF_ID frame_id) +{ + tf_respond_buf(MSG_SUCCESS, frame_id, NULL, 0); +} + + void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) { TF_Msg msg; @@ -46,93 +53,46 @@ void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) } -// --------------------------------------------------------------------------- - -static void job_respond_err(Job *job) -{ - tf_respond_str(MSG_ERROR, job->frame_id, job->str); -} - - -void sched_respond_err(TF_ID frame_id, const char *message) -{ - dbg("ERR: %s", message); - Job job = { - .cb = job_respond_err, - .frame_id = frame_id, - .str = message - }; - scheduleJob(&job, TSK_SCHED_LOW); -} - - -void sched_respond_bad_cmd(TF_ID frame_id) +void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) { - sched_respond_err(frame_id, "BAD COMMAND"); + tf_respond_buf(type, frame_id, (const uint8_t *) str, (uint32_t) strlen(str)); } -void sched_respond_malformed_cmd(TF_ID frame_id) -{ - sched_respond_err(frame_id, "MALFORMED PAYLOAD"); -} - // --------------------------------------------------------------------------- -static void job_respond_suc(Job *job) +void tf_respond_err(TF_ID frame_id, const char *message) { - tf_respond_ok(job->frame_id); + tf_respond_str(MSG_ERROR, frame_id, message); } -void sched_respond_suc(TF_ID frame_id) +void tf_respond_bad_cmd(TF_ID frame_id) { - Job job = { - .cb = job_respond_suc, - .frame_id = frame_id - }; - scheduleJob(&job, TSK_SCHED_LOW); + tf_respond_err(frame_id, "BAD COMMAND"); } -// --------------------------------------------------------------------------- -static void job_respond_uX(Job *job) +void tf_respond_malformed_cmd(TF_ID frame_id) { - tf_respond_buf(MSG_SUCCESS, job->frame_id, (const uint8_t *) &job->d32, job->len); + tf_respond_err(frame_id, "MALFORMED PAYLOAD"); } +// --------------------------------------------------------------------------- -void sched_respond_u8(TF_ID frame_id, uint8_t d) +void tf_respond_u8(TF_ID frame_id, uint8_t d) { - Job job = { - .cb = job_respond_uX, - .frame_id = frame_id, - .d32 = d, - .len = 1 - }; - scheduleJob(&job, TSK_SCHED_HIGH); + tf_respond_buf(MSG_SUCCESS, frame_id, (const uint8_t *) &d, 1); } -void sched_respond_u16(TF_ID frame_id, uint16_t d) +void tf_respond_u16(TF_ID frame_id, uint16_t d) { - Job job = { - .cb = job_respond_uX, - .frame_id = frame_id, - .d32 = d, - .len = 2 - }; - scheduleJob(&job, TSK_SCHED_HIGH); + tf_respond_buf(MSG_SUCCESS, frame_id, (const uint8_t *) &d, 2); } -void sched_respond_u32(TF_ID frame_id, uint32_t d) +void tf_respond_u32(TF_ID frame_id, uint32_t d) { - Job job = { - .cb = job_respond_uX, - .frame_id = frame_id, - .d32 = d, - .len = 4 - }; - scheduleJob(&job, TSK_SCHED_HIGH); + tf_respond_buf(MSG_SUCCESS, frame_id, (const uint8_t *) &d, 4); } diff --git a/comm/msg_responses.h b/comm/msg_responses.h index e1bd35e..9c319ac 100644 --- a/comm/msg_responses.h +++ b/comm/msg_responses.h @@ -38,10 +38,7 @@ void tf_respond_buf(TF_TYPE type, TF_ID frame_id, const uint8_t *buf, uint32_t l * * @param frame_id - ID of the original msg */ -static inline void tf_respond_ok(TF_ID frame_id) -{ - tf_respond_buf(MSG_SUCCESS, frame_id, NULL, 0); -} +void tf_respond_ok(TF_ID frame_id); /** * Same like tf_respond_buf(), but used for sending spontaneous reports. @@ -62,10 +59,7 @@ void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); * @param frame_id - ID of the original msg * @param str - character buffer, zero terminated */ -static inline void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) -{ - tf_respond_buf(type, frame_id, (const uint8_t *) str, (uint32_t) strlen(str)); -} +void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str); /** * Schedule sending an ASCII string error response. @@ -74,29 +68,21 @@ static inline void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) * @param frame_id - ID of the original msg * @param str - character buffer, zero terminated */ -void sched_respond_err(TF_ID frame_id, const char *str); +void tf_respond_err(TF_ID frame_id, const char *str); /** * Variant of sched_respond_err() for reporting bad received command code * * @param msg_id - ID of the original msg */ -void sched_respond_bad_cmd(TF_ID frame_id); +void tf_respond_bad_cmd(TF_ID frame_id); /** * Variant of sched_respond_err() for reporting malformed commands (e.g. too short payload) * * @param msg_id - ID of the original msg */ -void sched_respond_malformed_cmd(TF_ID frame_id); - -/** - * Schedule sending an empty response with MSG_SUCCESS type. - * Schedules a low priority job. - * - * @param frame_id - ID of the original msg - */ -void sched_respond_suc(TF_ID frame_id); +void tf_respond_malformed_cmd(TF_ID frame_id); /** * Schedule sending a one-byte response with MSG_SUCCESS type. @@ -105,7 +91,7 @@ void sched_respond_suc(TF_ID frame_id); * @param frame_id - ID of the original msg * @param d - data */ -void sched_respond_u8(TF_ID frame_id, uint8_t d); +void tf_respond_u8(TF_ID frame_id, uint8_t d); /** * Schedule sending a two-byte response with MSG_SUCCESS type. @@ -114,7 +100,7 @@ void sched_respond_u8(TF_ID frame_id, uint8_t d); * @param frame_id - ID of the original msg * @param d - data */ -void sched_respond_u16(TF_ID frame_id, uint16_t d); +void tf_respond_u16(TF_ID frame_id, uint16_t d); /** * Schedule sending a 4-byte response with MSG_SUCCESS type. @@ -123,6 +109,6 @@ void sched_respond_u16(TF_ID frame_id, uint16_t d); * @param frame_id - ID of the original msg * @param d - data */ -void sched_respond_u32(TF_ID frame_id, uint32_t d); +void tf_respond_u32(TF_ID frame_id, uint32_t d); #endif //GEX_F072_MSG_RESPONSES_H diff --git a/framework/unit_registry.c b/framework/unit_registry.c index e933253..725f2ff 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -495,11 +495,6 @@ uint32_t ureg_get_num_units(void) return count; } -static void job_nosuch_unit(Job *job) -{ - tf_respond_snprintf(MSG_ERROR, job->frame_id, "NO UNIT @ %"PRIu32, job->d32); -} - /** Deliver message to it's destination unit */ void ureg_deliver_unit_request(TF_Msg *msg) { @@ -514,7 +509,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) if (!pp.ok) { dbg("!! pp not OK!"); } if (callsign == 0 || !pp.ok) { - sched_respond_malformed_cmd(msg->frame_id); + tf_respond_malformed_cmd(msg->frame_id); return; } @@ -524,7 +519,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) if (pUnit->callsign == callsign) { bool ok = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); if (ok && confirmed) { - sched_respond_suc(msg->frame_id); + tf_respond_ok(msg->frame_id); } return; } @@ -532,12 +527,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) } // Not found - Job job = { - .cb = job_nosuch_unit, - .frame_id = msg->frame_id, - .d32 = callsign - }; - scheduleJob(&job, TSK_SCHED_LOW); + tf_respond_snprintf(MSG_ERROR, msg->frame_id, "NO UNIT @ %"PRIu8, callsign); } diff --git a/units/neopixel/unit_neopixel.c b/units/neopixel/unit_neopixel.c index 0adc320..5f0f42f 100644 --- a/units/neopixel/unit_neopixel.c +++ b/units/neopixel/unit_neopixel.c @@ -173,14 +173,14 @@ static bool Npx_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo break; default: - sched_respond_bad_cmd(frame_id); + tf_respond_bad_cmd(frame_id); return false; } return true; bad_count: - sched_respond_err(frame_id, "BAD PIXEL COUNT"); + tf_respond_err(frame_id, "BAD PIXEL COUNT"); return false; } diff --git a/units/pin/unit_pin.c b/units/pin/unit_pin.c index 4b56089..b56ff6c 100644 --- a/units/pin/unit_pin.c +++ b/units/pin/unit_pin.c @@ -194,23 +194,23 @@ static bool Pin_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo case CMD_READ: if (!priv->output) { - sched_respond_u8(frame_id, (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin)); + tf_respond_u8(frame_id, (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin)); } else goto must_be_input; break; default: - sched_respond_bad_cmd(frame_id); + tf_respond_bad_cmd(frame_id); return false; } return true; must_be_output: - sched_respond_err(frame_id, "NOT OUTPUT PIN"); + tf_respond_err(frame_id, "NOT OUTPUT PIN"); return false; must_be_input: - sched_respond_err(frame_id, "NOT INPUT PIN"); + tf_respond_err(frame_id, "NOT INPUT PIN"); return false; } diff --git a/units/test/unit_test.c b/units/test/unit_test.c index 9251661..d3d7f87 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -138,7 +138,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo break; default: - sched_respond_bad_cmd(frame_id); + tf_respond_bad_cmd(frame_id); return false; } From 4f92b97305ae7d7d4a58f91c7156e47f384d66c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 20:55:45 +0100 Subject: [PATCH 12/17] removed low prio queue --- freertos.c | 39 +++++++++++---------------------------- tasks/sched_queue.h | 3 +-- tasks/task_sched.c | 43 ++++++++----------------------------------- tasks/task_sched.h | 17 ++++------------- utils/stacksmon.c | 8 ++++---- 5 files changed, 28 insertions(+), 82 deletions(-) diff --git a/freertos.c b/freertos.c index 7cd05f5..1e0e3fd 100644 --- a/freertos.c +++ b/freertos.c @@ -60,8 +60,7 @@ #define STACK_MAIN 160 #define STACK_MSG 230 -#define STACK_LP 180 -#define STACK_HP 150 +#define STACK_JOBRUNNER 150 osThreadId tskMainHandle; uint32_t mainTaskBuffer[ STACK_MAIN ]; @@ -71,19 +70,11 @@ osThreadId tskMsgHandle; uint32_t msgTaskBuffer[ STACK_MSG ]; osStaticThreadDef_t msgTaskControlBlock; -osThreadId tskSchedLPHandle; -uint32_t schedLowBuffer[ STACK_LP ]; -osStaticThreadDef_t schedLowControlBlock; +osThreadId tskJobRunnerHandle; +uint32_t jobRunnerBuffer[ STACK_JOBRUNNER ]; +osStaticThreadDef_t jobRunnerControlBlock; -osThreadId tskSchedHPHandle; -uint32_t schedHighBuffer[ STACK_HP ]; -osStaticThreadDef_t schedHighControlBlock; - -osMessageQId queSchedLPHandle; -uint8_t myQueue01Buffer[ LP_SCHED_CAPACITY * sizeof( struct sched_que_item ) ]; -osStaticMessageQDef_t myQueue01ControlBlock; - -osMessageQId queSchedHPHandle; +osMessageQId queSchedHandle; uint8_t myQueue02Buffer[ HP_SCHED_CAPACITY * sizeof( struct sched_que_item ) ]; osStaticMessageQDef_t myQueue02ControlBlock; @@ -104,7 +95,7 @@ osStaticSemaphoreDef_t myBinarySem01ControlBlock; /* Function prototypes -------------------------------------------------------*/ void TaskMain(void const * argument); extern void TaskSchedLP(void const * argument); -extern void TaskSchedHP(void const * argument); +extern void TaskJobQueue(void const *argument); extern void TaskMessaging(void const * argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ @@ -146,8 +137,7 @@ void vApplicationGetIdleTaskMemory( StaticTask_t **ppxIdleTaskTCBBuffer, StackTy void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ stackmon_register("Main", mainTaskBuffer, sizeof(mainTaskBuffer)); - stackmon_register("Job Queue Low", schedLowBuffer, sizeof(schedLowBuffer)); - stackmon_register("Job Queue High", schedHighBuffer, sizeof(schedHighBuffer)); + stackmon_register("JobRunner", jobRunnerBuffer, sizeof(jobRunnerBuffer)); stackmon_register("Messaging", msgTaskBuffer, sizeof(msgTaskBuffer)); /* USER CODE END Init */ @@ -179,13 +169,9 @@ void MX_FREERTOS_Init(void) { osThreadStaticDef(tskMain, TaskMain, osPriorityHigh, 0, STACK_MAIN, mainTaskBuffer, &mainTaskControlBlock); tskMainHandle = osThreadCreate(osThread(tskMain), NULL); - /* definition and creation of tskSchedLP */ - osThreadStaticDef(tskSchedLP, TaskSchedLP, osPriorityLow, 0, STACK_LP, schedLowBuffer, &schedLowControlBlock); - tskSchedLPHandle = osThreadCreate(osThread(tskSchedLP), NULL); - - /* definition and creation of tskSchedHP */ - osThreadStaticDef(tskSchedHP, TaskSchedHP, osPriorityAboveNormal, 0, STACK_HP, schedHighBuffer, &schedHighControlBlock); - tskSchedHPHandle = osThreadCreate(osThread(tskSchedHP), NULL); + /* definition and creation of tskJobRunner */ + osThreadStaticDef(tskJobRunner, TaskJobQueue, osPriorityAboveNormal, 0, STACK_JOBRUNNER, jobRunnerBuffer, &jobRunnerControlBlock); + tskJobRunnerHandle = osThreadCreate(osThread(tskJobRunner), NULL); /* definition and creation of TaskMessaging */ osThreadStaticDef(tskMsg, TaskMessaging, osPriorityNormal, 0, STACK_MSG, msgTaskBuffer, &msgTaskControlBlock); @@ -196,13 +182,10 @@ void MX_FREERTOS_Init(void) { /* USER CODE END RTOS_THREADS */ /* Create the queue(s) */ - /* definition and creation of queSchedLP */ - osMessageQStaticDef(queSchedLP, LP_SCHED_CAPACITY, struct sched_que_item, myQueue01Buffer, &myQueue01ControlBlock); - queSchedLPHandle = osMessageCreate(osMessageQ(queSchedLP), NULL); /* definition and creation of queSchedHP */ osMessageQStaticDef(queSchedHP, HP_SCHED_CAPACITY, struct sched_que_item, myQueue02Buffer, &myQueue02ControlBlock); - queSchedHPHandle = osMessageCreate(osMessageQ(queSchedHP), NULL); + queSchedHandle = osMessageCreate(osMessageQ(queSchedHP), NULL); /* definition and creation of queRxData */ osMessageQStaticDef(queRxData, RX_QUE_CAPACITY, struct rx_que_item, myQueue03Buffer, &myQueue03ControlBlock); diff --git a/tasks/sched_queue.h b/tasks/sched_queue.h index f192eb1..14662ee 100644 --- a/tasks/sched_queue.h +++ b/tasks/sched_queue.h @@ -5,7 +5,7 @@ #ifndef GEX_SCHED_QUEUE_H #define GEX_SCHED_QUEUE_H -#include +#include typedef struct sched_que_item Job; typedef void (*ScheduledJobCb) (Job *job); @@ -35,7 +35,6 @@ struct rx_que_item { uint8_t data[64]; }; -#define LP_SCHED_CAPACITY 5 #define HP_SCHED_CAPACITY 5 #define RX_QUE_CAPACITY 16 diff --git a/tasks/task_sched.c b/tasks/task_sched.c index ade3b9c..274c6be 100644 --- a/tasks/task_sched.c +++ b/tasks/task_sched.c @@ -5,23 +5,18 @@ #include "platform.h" #include "task_sched.h" -extern osMessageQId queSchedLPHandle; -extern osMessageQId queSchedHPHandle; +extern osMessageQId queSchedHandle; -volatile uint32_t jobQueHighWaterMarkHP = 0; -volatile uint32_t jobQueHighWaterMarkLP = 0; +volatile uint32_t jobQueHighWaterMark = 0; /** * Schedule a function for later execution in the jobs thread * * @param callback - the callback function - * @param prio - priority, selects which job queue to use - * @param data1 - first data object, NULL if not needed; usually context/handle - * @param data2 - second data object, NULL if not needed; usually data/argument */ -void scheduleJob(Job *job, enum task_sched_prio prio) +void scheduleJob(Job *job) { - QueueHandle_t que = (prio == TSK_SCHED_LOW ? queSchedLPHandle : queSchedHPHandle); + QueueHandle_t que = queSchedHandle; assert_param(que != NULL); assert_param(job->cb != NULL); @@ -44,44 +39,22 @@ void scheduleJob(Job *job, enum task_sched_prio prio) } #if USE_STACK_MONITOR - if (prio == TSK_SCHED_LOW) { - jobQueHighWaterMarkLP = MAX(jobQueHighWaterMarkLP, count); - } else { - jobQueHighWaterMarkHP = MAX(jobQueHighWaterMarkHP, count); - } + jobQueHighWaterMark = MAX(jobQueHighWaterMark, count); #endif } /** - * Low priority task queue handler - * - * @param argument - */ -void TaskSchedLP (const void * argument) -{ - dbg("> Low priority queue task started!"); - - struct sched_que_item job; - while (1) { - xQueueReceive(queSchedLPHandle, &job, osWaitForever); - - assert_param(job.cb != NULL); - job.cb(&job); - } -} - -/** - * High priority task queue handler + * job queue handler (for use in interrupts to do longer stuff on a thread) * * @param argument */ -void TaskSchedHP (const void * argument) +void TaskJobQueue(const void *argument) { dbg("> High priority queue task started!"); struct sched_que_item job; while (1) { - xQueueReceive(queSchedHPHandle, &job, osWaitForever); + xQueueReceive(queSchedHandle, &job, osWaitForever); assert_param(job.cb != NULL); job.cb(&job); diff --git a/tasks/task_sched.h b/tasks/task_sched.h index c9c14b0..0841991 100644 --- a/tasks/task_sched.h +++ b/tasks/task_sched.h @@ -8,22 +8,13 @@ #include "platform.h" #include "sched_queue.h" -enum task_sched_prio { - TSK_SCHED_LOW = 0, - TSK_SCHED_HIGH = 1, -}; - #if USE_STACK_MONITOR -extern volatile uint32_t jobQueHighWaterMarkHP; -extern volatile uint32_t jobQueHighWaterMarkLP; +extern volatile uint32_t jobQueHighWaterMark; #endif -extern osThreadId tskSchedLPHandle; -void TaskSchedLP (const void * argument); - -extern osThreadId tskSchedHPHandle; -void TaskSchedHP (const void * argument); +extern osThreadId tskJobRunnerHandle; +void TaskJobQueue(const void *argument); -void scheduleJob(Job *job, enum task_sched_prio prio); +void scheduleJob(Job *job); #endif //GEX_TASK_SCHED_H diff --git a/utils/stacksmon.c b/utils/stacksmon.c index 01498e7..12078d8 100644 --- a/utils/stacksmon.c +++ b/utils/stacksmon.c @@ -14,7 +14,7 @@ struct stackhandle { uint32_t len; }; -#define STACK_NUM 16 +#define STACK_NUM 8 static uint32_t nextidx = 0; static struct stackhandle stacks[STACK_NUM]; @@ -64,9 +64,9 @@ void stackmon_dump(void) ); } - PUTS("\033[36m>> QUEUES\033[m\r\n"); - PRINTF(" Used slots: \033[33mHP %"PRIu32", LP %"PRIu32"\033[m\r\n", - jobQueHighWaterMarkHP, jobQueHighWaterMarkLP); + PUTS("\033[36m>> JOB QUEUE\033[m\r\n"); + PRINTF(" Used slots: \033[33m%"PRIu32"\033[m\r\n", + jobQueHighWaterMark); PRINTF("\033[1m---------------------------\033[m\r\n\r\n"); } From 92c28c5dafc5d92bbe87cee3023e8eaf25074734 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 21:05:28 +0100 Subject: [PATCH 13/17] rename tf response helpers to com_* --- comm/messages.c | 4 ++-- comm/msg_responses.c | 42 +++++++++++++++++----------------- comm/msg_responses.h | 22 +++++++++--------- framework/unit_registry.c | 10 ++++---- units/neopixel/unit_neopixel.c | 4 ++-- units/pin/unit_pin.c | 8 +++---- units/test/unit_test.c | 6 ++--- 7 files changed, 48 insertions(+), 48 deletions(-) diff --git a/comm/messages.c b/comm/messages.c index 2d99935..7ce00ea 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -34,7 +34,7 @@ void comm_init(void) static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg) { - tf_respond_snprintf(MSG_SUCCESS, msg->frame_id, "%s/%s", GEX_VERSION, GEX_PLATFORM); + com_respond_snprintf(msg->frame_id, MSG_SUCCESS, "%s/%s", GEX_VERSION, GEX_PLATFORM); return TF_STAY; } @@ -44,7 +44,7 @@ static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg) { dbg("!! Unhandled msg type %02"PRIx8", frame_id 0x%04"PRIx16, msg->type, msg->frame_id); - tf_respond_snprintf(MSG_ERROR, msg->frame_id, "UNKNOWN MSG %"PRIu8, msg->type); + com_respond_snprintf(msg->frame_id, MSG_ERROR, "UNKNOWN MSG %"PRIu8, msg->type); return TF_STAY; } diff --git a/comm/msg_responses.c b/comm/msg_responses.c index 5c09325..3562b02 100644 --- a/comm/msg_responses.c +++ b/comm/msg_responses.c @@ -5,7 +5,7 @@ #include "messages.h" #include "msg_responses.h" -void tf_respond_snprintf(TF_TYPE type, TF_ID id, const char *format, ...) +void com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...) { #define ERR_STR_LEN 64 @@ -15,17 +15,17 @@ void tf_respond_snprintf(TF_TYPE type, TF_ID id, const char *format, ...) uint32_t len = (uint32_t) fixup_vsnprintf(&buf[0], ERR_STR_LEN, format, args); va_end(args); - tf_respond_buf(type, id, (const uint8_t *) buf, len); + com_respond_buf(frame_id, type, (const uint8_t *) buf, len); } -void tf_respond_buf(TF_TYPE type, TF_ID id, const uint8_t *buf, uint32_t len) +void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t len) { TF_Msg msg; TF_ClearMsg(&msg); { msg.type = type; - msg.frame_id = id; + msg.frame_id = frame_id; msg.data = buf; msg.len = (TF_LEN) len; } @@ -33,13 +33,13 @@ void tf_respond_buf(TF_TYPE type, TF_ID id, const uint8_t *buf, uint32_t len) } -void tf_respond_ok(TF_ID frame_id) +void com_respond_ok(TF_ID frame_id) { - tf_respond_buf(MSG_SUCCESS, frame_id, NULL, 0); + com_respond_buf(frame_id, MSG_SUCCESS, NULL, 0); } -void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) +void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) { TF_Msg msg; TF_ClearMsg(&msg); @@ -53,46 +53,46 @@ void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) } -void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) +void com_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) { - tf_respond_buf(type, frame_id, (const uint8_t *) str, (uint32_t) strlen(str)); + com_respond_buf(frame_id, type, (const uint8_t *) str, (uint32_t) strlen(str)); } // --------------------------------------------------------------------------- -void tf_respond_err(TF_ID frame_id, const char *message) +void com_respond_err(TF_ID frame_id, const char *message) { - tf_respond_str(MSG_ERROR, frame_id, message); + com_respond_str(MSG_ERROR, frame_id, message); } -void tf_respond_bad_cmd(TF_ID frame_id) +void com_respond_bad_cmd(TF_ID frame_id) { - tf_respond_err(frame_id, "BAD COMMAND"); + com_respond_err(frame_id, "BAD COMMAND"); } -void tf_respond_malformed_cmd(TF_ID frame_id) +void com_respond_malformed_cmd(TF_ID frame_id) { - tf_respond_err(frame_id, "MALFORMED PAYLOAD"); + com_respond_err(frame_id, "MALFORMED PAYLOAD"); } // --------------------------------------------------------------------------- -void tf_respond_u8(TF_ID frame_id, uint8_t d) +void com_respond_u8(TF_ID frame_id, uint8_t d) { - tf_respond_buf(MSG_SUCCESS, frame_id, (const uint8_t *) &d, 1); + com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) &d, 1); } -void tf_respond_u16(TF_ID frame_id, uint16_t d) +void com_respond_u16(TF_ID frame_id, uint16_t d) { - tf_respond_buf(MSG_SUCCESS, frame_id, (const uint8_t *) &d, 2); + com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) &d, 2); } -void tf_respond_u32(TF_ID frame_id, uint32_t d) +void com_respond_u32(TF_ID frame_id, uint32_t d) { - tf_respond_buf(MSG_SUCCESS, frame_id, (const uint8_t *) &d, 4); + com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) &d, 4); } diff --git a/comm/msg_responses.h b/comm/msg_responses.h index 9c319ac..8189092 100644 --- a/comm/msg_responses.h +++ b/comm/msg_responses.h @@ -19,7 +19,7 @@ * @param ... - replacements */ void __attribute__((format(printf,3,4))) -tf_respond_snprintf(TF_TYPE type, TF_ID frame_id, const char *format, ...); +com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...); /** * Respond to a TF message with a buffer of fixed length and custom type. @@ -30,7 +30,7 @@ tf_respond_snprintf(TF_TYPE type, TF_ID frame_id, const char *format, ...); * @param buf - byte buffer * @param len - buffer size */ -void tf_respond_buf(TF_TYPE type, TF_ID frame_id, const uint8_t *buf, uint32_t len); +void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t len); /** * Respond to a TF message with empty body and MSG_SUCCESS type. @@ -38,7 +38,7 @@ void tf_respond_buf(TF_TYPE type, TF_ID frame_id, const uint8_t *buf, uint32_t l * * @param frame_id - ID of the original msg */ -void tf_respond_ok(TF_ID frame_id); +void com_respond_ok(TF_ID frame_id); /** * Same like tf_respond_buf(), but used for sending spontaneous reports. @@ -48,7 +48,7 @@ void tf_respond_ok(TF_ID frame_id); * @param buf - byte buffer * @param len - buffer size */ -void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); +void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); /** * Same like tf_respond_buf(), but the buffer length is measured with strlen. @@ -59,7 +59,7 @@ void tf_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); * @param frame_id - ID of the original msg * @param str - character buffer, zero terminated */ -void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str); +void com_respond_str(TF_TYPE type, TF_ID frame_id, const char *str); /** * Schedule sending an ASCII string error response. @@ -68,21 +68,21 @@ void tf_respond_str(TF_TYPE type, TF_ID frame_id, const char *str); * @param frame_id - ID of the original msg * @param str - character buffer, zero terminated */ -void tf_respond_err(TF_ID frame_id, const char *str); +void com_respond_err(TF_ID frame_id, const char *str); /** * Variant of sched_respond_err() for reporting bad received command code * * @param msg_id - ID of the original msg */ -void tf_respond_bad_cmd(TF_ID frame_id); +void com_respond_bad_cmd(TF_ID frame_id); /** * Variant of sched_respond_err() for reporting malformed commands (e.g. too short payload) * * @param msg_id - ID of the original msg */ -void tf_respond_malformed_cmd(TF_ID frame_id); +void com_respond_malformed_cmd(TF_ID frame_id); /** * Schedule sending a one-byte response with MSG_SUCCESS type. @@ -91,7 +91,7 @@ void tf_respond_malformed_cmd(TF_ID frame_id); * @param frame_id - ID of the original msg * @param d - data */ -void tf_respond_u8(TF_ID frame_id, uint8_t d); +void com_respond_u8(TF_ID frame_id, uint8_t d); /** * Schedule sending a two-byte response with MSG_SUCCESS type. @@ -100,7 +100,7 @@ void tf_respond_u8(TF_ID frame_id, uint8_t d); * @param frame_id - ID of the original msg * @param d - data */ -void tf_respond_u16(TF_ID frame_id, uint16_t d); +void com_respond_u16(TF_ID frame_id, uint16_t d); /** * Schedule sending a 4-byte response with MSG_SUCCESS type. @@ -109,6 +109,6 @@ void tf_respond_u16(TF_ID frame_id, uint16_t d); * @param frame_id - ID of the original msg * @param d - data */ -void tf_respond_u32(TF_ID frame_id, uint32_t d); +void com_respond_u32(TF_ID frame_id, uint32_t d); #endif //GEX_F072_MSG_RESPONSES_H diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 725f2ff..524b2f9 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -509,7 +509,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) if (!pp.ok) { dbg("!! pp not OK!"); } if (callsign == 0 || !pp.ok) { - tf_respond_malformed_cmd(msg->frame_id); + com_respond_malformed_cmd(msg->frame_id); return; } @@ -519,7 +519,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) if (pUnit->callsign == callsign) { bool ok = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); if (ok && confirmed) { - tf_respond_ok(msg->frame_id); + com_respond_ok(msg->frame_id); } return; } @@ -527,7 +527,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) } // Not found - tf_respond_snprintf(MSG_ERROR, msg->frame_id, "NO UNIT @ %"PRIu8, callsign); + com_respond_snprintf(msg->frame_id, MSG_ERROR, "NO UNIT @ %"PRIu8, callsign); } @@ -547,7 +547,7 @@ void ureg_report_active_units(TF_ID frame_id) bool suc = true; uint8_t *buff = malloc_ck(msglen, &suc); - if (!suc) { tf_respond_str(MSG_ERROR, frame_id, "OUT OF MEMORY"); return; } + if (!suc) { com_respond_str(MSG_ERROR, frame_id, "OUT OF MEMORY"); return; } { PayloadBuilder pb = pb_start(buff, msglen, NULL); @@ -562,7 +562,7 @@ void ureg_report_active_units(TF_ID frame_id) assert_param(pb.ok); - tf_respond_buf(MSG_SUCCESS, frame_id, buff, msglen); + com_respond_buf(frame_id, MSG_SUCCESS, buff, msglen); } free(buff); diff --git a/units/neopixel/unit_neopixel.c b/units/neopixel/unit_neopixel.c index 5f0f42f..3610590 100644 --- a/units/neopixel/unit_neopixel.c +++ b/units/neopixel/unit_neopixel.c @@ -173,14 +173,14 @@ static bool Npx_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo break; default: - tf_respond_bad_cmd(frame_id); + com_respond_bad_cmd(frame_id); return false; } return true; bad_count: - tf_respond_err(frame_id, "BAD PIXEL COUNT"); + com_respond_err(frame_id, "BAD PIXEL COUNT"); return false; } diff --git a/units/pin/unit_pin.c b/units/pin/unit_pin.c index b56ff6c..fb5a299 100644 --- a/units/pin/unit_pin.c +++ b/units/pin/unit_pin.c @@ -194,23 +194,23 @@ static bool Pin_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo case CMD_READ: if (!priv->output) { - tf_respond_u8(frame_id, (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin)); + com_respond_u8(frame_id, (bool) LL_GPIO_IsInputPinSet(priv->port, priv->ll_pin)); } else goto must_be_input; break; default: - tf_respond_bad_cmd(frame_id); + com_respond_bad_cmd(frame_id); return false; } return true; must_be_output: - tf_respond_err(frame_id, "NOT OUTPUT PIN"); + com_respond_err(frame_id, "NOT OUTPUT PIN"); return false; must_be_input: - tf_respond_err(frame_id, "NOT INPUT PIN"); + com_respond_err(frame_id, "NOT INPUT PIN"); return false; } diff --git a/units/test/unit_test.c b/units/test/unit_test.c index d3d7f87..7490fe1 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -117,13 +117,13 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo switch (command) { case CMD_PING: - tf_respond_ok(frame_id); + com_respond_ok(frame_id); break; case CMD_ECHO:; uint32_t len; const uint8_t *data = pp_tail(pp, &len); - tf_respond_buf(MSG_SUCCESS, frame_id, data, len); + com_respond_buf(frame_id, MSG_SUCCESS, data, len); break; case CMD_BULKREAD:; @@ -138,7 +138,7 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo break; default: - tf_respond_bad_cmd(frame_id); + com_respond_bad_cmd(frame_id); return false; } From 7f682b2dcdf2b823e4cc3a2de4610c0f25f20587 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 21:22:31 +0100 Subject: [PATCH 14/17] some cleaning --- comm/messages.c | 49 ++++++++++++++++++--------------------- framework/unit_registry.c | 25 +++++++++++++------- 2 files changed, 39 insertions(+), 35 deletions(-) diff --git a/comm/messages.c b/comm/messages.c index 7ce00ea..7eda1fa 100644 --- a/comm/messages.c +++ b/comm/messages.c @@ -6,40 +6,24 @@ #include "TinyFrame.h" #include "framework/unit_registry.h" #include "comm/messages.h" -#include "task_sched.h" -TinyFrame tf_; +static TinyFrame tf_; TinyFrame *comm = &tf_; // --------------------------------------------------------------------------- -// Pre-declaring local functions -static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg); -static TF_Result lst_unit(TinyFrame *tf, TF_Msg *msg); -static TF_Result lst_list_units(TinyFrame *tf, TF_Msg *msg); -static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg); - -void comm_init(void) -{ - TF_InitStatic(comm, TF_SLAVE); - TF_AddTypeListener(comm, MSG_PING, lst_ping); - TF_AddTypeListener(comm, MSG_UNIT_REQUEST, lst_unit); - TF_AddTypeListener(comm, MSG_LIST_UNITS, lst_list_units); - - // fall-through - TF_AddGenericListener(comm, lst_default); -} - -// --------------------------------------------------------------------------- - +/** + * Ping request listener - returns version string and other info about the build + */ static TF_Result lst_ping(TinyFrame *tf, TF_Msg *msg) { com_respond_snprintf(msg->frame_id, MSG_SUCCESS, "%s/%s", GEX_VERSION, GEX_PLATFORM); return TF_STAY; } -// ---------------------------------------------------------------------------- - +/** + * Default listener, fallback for unhandled messages + */ static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg) { dbg("!! Unhandled msg type %02"PRIx8", frame_id 0x%04"PRIx16, msg->type, msg->frame_id); @@ -48,18 +32,31 @@ static TF_Result lst_default(TinyFrame *tf, TF_Msg *msg) return TF_STAY; } -// ---------------------------------------------------------------------------- - +/** + * Unit request listener, a message targeted at a particular + */ static TF_Result lst_unit(TinyFrame *tf, TF_Msg *msg) { ureg_deliver_unit_request(msg); return TF_STAY; } -// ---------------------------------------------------------------------------- static TF_Result lst_list_units(TinyFrame *tf, TF_Msg *msg) { ureg_report_active_units(msg->frame_id); return TF_STAY; } + +// --------------------------------------------------------------------------- + +void comm_init(void) +{ + TF_InitStatic(comm, TF_SLAVE); + TF_AddTypeListener(comm, MSG_PING, lst_ping); + TF_AddTypeListener(comm, MSG_UNIT_REQUEST, lst_unit); + TF_AddTypeListener(comm, MSG_LIST_UNITS, lst_list_units); + + // fall-through + TF_AddGenericListener(comm, lst_default); +} diff --git a/framework/unit_registry.c b/framework/unit_registry.c index 524b2f9..d6cf730 100644 --- a/framework/unit_registry.c +++ b/framework/unit_registry.c @@ -516,8 +516,11 @@ void ureg_deliver_unit_request(TF_Msg *msg) UlistEntry *li = ulist_head; while (li != NULL) { Unit *const pUnit = &li->unit; - if (pUnit->callsign == callsign) { + if (pUnit->callsign == callsign && pUnit->status == E_SUCCESS) { bool ok = pUnit->driver->handleRequest(pUnit, msg->frame_id, command, &pp); + + // send extra SUCCESS confirmation message. + // error is expected to have already been reported. if (ok && confirmed) { com_respond_ok(msg->frame_id); } @@ -530,7 +533,7 @@ void ureg_deliver_unit_request(TF_Msg *msg) com_respond_snprintf(msg->frame_id, MSG_ERROR, "NO UNIT @ %"PRIu8, callsign); } - +/** Send a response for a unit-list request */ void ureg_report_active_units(TF_ID frame_id) { // count bytes needed @@ -539,24 +542,29 @@ void ureg_report_active_units(TF_ID frame_id) UlistEntry *li = ulist_head; uint32_t count = 0; while (li != NULL) { - count++; - msglen += strlen(li->unit.name)+1; + if (li->unit.status == E_SUCCESS) { + count++; + msglen += strlen(li->unit.name) + 1; + msglen += strlen(li->unit.driver->name) + 1; + } li = li->next; } - msglen += count; + msglen += count; // one byte per message for the callsign bool suc = true; uint8_t *buff = malloc_ck(msglen, &suc); if (!suc) { com_respond_str(MSG_ERROR, frame_id, "OUT OF MEMORY"); return; } - { PayloadBuilder pb = pb_start(buff, msglen, NULL); pb_u8(&pb, (uint8_t) count); // assume we don't have more than 255 units li = ulist_head; while (li != NULL) { - pb_u8(&pb, li->unit.callsign); - pb_string(&pb, li->unit.name); + if (li->unit.status == E_SUCCESS) { + pb_u8(&pb, li->unit.callsign); + pb_string(&pb, li->unit.name); + pb_string(&pb, li->unit.driver->name); + } li = li->next; } @@ -564,6 +572,5 @@ void ureg_report_active_units(TF_ID frame_id) com_respond_buf(frame_id, MSG_SUCCESS, buff, msglen); } - free(buff); } From 2f5e30b8a4889a48327c5e6649d6f0b6bb43cce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 22:38:21 +0100 Subject: [PATCH 15/17] bulk write implemented but not yet tested. bulk read improved --- .../Class/CDC/Src/usbd_cdc.c | 9 +- comm/messages.h | 4 + comm/msg_bulkread.c | 36 ++++---- comm/msg_bulkread.h | 5 -- comm/msg_bulkwrite.c | 90 +++++++++++++++++++ comm/msg_bulkwrite.h | 41 +++++++++ 6 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 comm/msg_bulkwrite.c create mode 100644 comm/msg_bulkwrite.h diff --git a/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c index 58ff55d..56f4f98 100644 --- a/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c +++ b/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c @@ -646,9 +646,12 @@ uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) if(pdev->pClassData2 != NULL) { - - hcdc->TxState = 0; - USBD_CDC_TransmitDone(pdev); + if (epnum == CDC_IN_EP) { + hcdc->TxState = 0; + USBD_CDC_TransmitDone(pdev); + } else if (epnum == CDC_CMD_EP) { + // command EP send done + } return USBD_OK; } diff --git a/comm/messages.h b/comm/messages.h index 802e52c..a4373d8 100644 --- a/comm/messages.h +++ b/comm/messages.h @@ -9,6 +9,9 @@ #include "task_sched.h" #include "TinyFrame.h" +#define BULK_LST_TIMEOUT_MS 200 +#define BULKREAD_MAX_CHUNK 512 // this is a static buffer + /** * Supported message types (TF_TYPE) */ @@ -38,6 +41,7 @@ extern TinyFrame *comm; // Must be after the enum because it's used in the header file. #include "msg_responses.h" #include "msg_bulkread.h" +#include "msg_bulkwrite.h" /** * Initialize TinyFrame and set up listeners diff --git a/comm/msg_bulkread.c b/comm/msg_bulkread.c index 24fbc47..3866870 100644 --- a/comm/msg_bulkread.c +++ b/comm/msg_bulkread.c @@ -30,40 +30,38 @@ static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) if (msg->type == MSG_BULK_ABORT) { goto close; - } else if (msg->type == MSG_BULK_READ_POLL) { + } + else if (msg->type == MSG_BULK_READ_POLL) { + // find how much data the reader wants PayloadParser pp = pp_start(msg->data, msg->len, NULL); uint32_t chunk = pp_u32(&pp); - // if past len, say we're done and close - if (bulk->offset >= bulk->len) { - TF_ClearMsg(msg); - msg->frame_id = bulk->frame_id; - msg->type = MSG_BULK_END; - TF_Respond(tf, msg); - goto close; - } - chunk = MIN(chunk, bulk->len - bulk->offset); chunk = MIN(chunk, BULKREAD_MAX_CHUNK); + // load data into the buffer bulk->read(bulk, chunk, bulkread_buffer); - TF_ClearMsg(msg); - msg->frame_id = bulk->frame_id; - msg->type = MSG_BULK_DATA; - msg->data = bulkread_buffer; - msg->len = (TF_LEN) chunk; - TF_Respond(tf, msg); + bool last = (bulk->offset + chunk >= bulk->len); + + TF_Msg resp; + TF_ClearMsg(&resp); + resp.frame_id = bulk->frame_id; + resp.type = (last ? MSG_BULK_END : MSG_BULK_DATA); // the last chunk has the END type + resp.data = bulkread_buffer; + resp.len = (TF_LEN) chunk; + TF_Respond(tf, &resp); + + if (last) goto close; // advance the position pointer bulk->offset += chunk; } - msg->userdata = bulk; // We must put it back return TF_RENEW; - close: - if (msg->userdata) { +close: + if (bulk) { // Ask user to free the bulk and userdata bulk->read(bulk, 0, NULL); msg->userdata = NULL; diff --git a/comm/msg_bulkread.h b/comm/msg_bulkread.h index 5226d6c..abe49fb 100644 --- a/comm/msg_bulkread.h +++ b/comm/msg_bulkread.h @@ -11,11 +11,6 @@ #include - -#define BULK_LST_TIMEOUT_MS 200 - -#define BULKREAD_MAX_CHUNK 512 // this is a static buffer - typedef struct bulk_read BulkRead; /** diff --git a/comm/msg_bulkwrite.c b/comm/msg_bulkwrite.c new file mode 100644 index 0000000..77b2677 --- /dev/null +++ b/comm/msg_bulkwrite.c @@ -0,0 +1,90 @@ +// +// Created by MightyPork on 2017/12/23. +// + +#include "platform.h" + +#include + +#include "messages.h" +#include "utils/payload_parser.h" +#include "utils/payload_builder.h" + +/** + * TF listener for the bulk write transaction + */ +static TF_Result bulkwrite_lst(TinyFrame *tf, TF_Msg *msg) +{ + struct bulk_write *bulk = msg->userdata; + + // this is a final call before timeout, to clean up + if (msg->data == NULL) { + dbg("Bulk rx lst cleanup\r\n"); + goto close; + } + + assert_param(NULL != bulk); + + if (msg->type == MSG_BULK_ABORT) { + goto close; + } + else if (msg->type == MSG_BULK_DATA || msg->type == MSG_BULK_END) { + // if past len, say we're done and close + if (bulk->offset >= bulk->len) { + com_respond_err(bulk->frame_id, "WRITE OVERRUN"); + goto close; + } + + bulk->write(bulk, msg->data, msg->len); + + // Return SUCCESS + com_respond_ok(msg->frame_id); + + // advance the position pointer (can be used by the write callback) + bulk->offset += msg->len; + + if (msg->type == MSG_BULK_END) { + // this was the last chunk + goto close; + } + } + + return TF_RENEW; + +close: + if (bulk) { + // Ask user to free the bulk and userdata + bulk->write(bulk, NULL, 0); + msg->userdata = NULL; + } + return TF_CLOSE; +} + +/** Start the bulk write flow */ +void bulkwrite_start(TinyFrame *tf, struct bulk_write *bulk) +{ + assert_param(bulk); + assert_param(bulk->len); + assert_param(bulk->write); + + bulk->offset = 0; + + { + uint8_t buf[8]; + PayloadBuilder pb = pb_start(buf, 4, NULL); + pb_u32(&pb, bulk->len); + pb_u32(&pb, TF_MAX_PAYLOAD_RX); + + // We use userdata1 to hold a reference to the bulk transfer + TF_Msg msg = { + .type = MSG_BULK_WRITE_OFFER, + .frame_id = bulk->frame_id, + .is_response = true, // this ensures the frame_id is not re-generated + .data = buf, + .len = (TF_LEN) pb_length(&pb), + .userdata = bulk, + }; + + TF_Query(tf, &msg, bulkwrite_lst, BULK_LST_TIMEOUT_MS); + } +} diff --git a/comm/msg_bulkwrite.h b/comm/msg_bulkwrite.h new file mode 100644 index 0000000..4391dab --- /dev/null +++ b/comm/msg_bulkwrite.h @@ -0,0 +1,41 @@ +// +// Created by MightyPork on 2017/12/23. +// + +#ifndef GEX_F072_MSG_BULKWRITE_H +#define GEX_F072_MSG_BULKWRITE_H + +#include + +typedef struct bulk_write BulkWrite; + +/** + * Type of the bulk-write listener. Offset within the data can be retrieved from bulk->offset. + * + * If buffer is NULL, this is the last call and the bulk struct must be freed if it was allocated. + * + * @param bulk - a data object passed to the bulkwrite_start() function. + * @param chunk - destination buffer to fill with the data. NULL if bulk should be freed. + * @param len - size of the chunk to write + */ +typedef void (*bulkwrite_data_cb)(BulkWrite *bulk, const uint8_t *chunk, uint32_t len); + +/** Bulk read structure */ +struct bulk_write { + TF_ID frame_id; //!< ID of the requesting frame, used for the entire bulk read session + bulkwrite_data_cb write; //!< Write callback + uint32_t len; //!< Total data length + void *userdata; //!< A place for arbitrary userdata + + uint32_t offset; //!< Internal offset counter, will be set to 0 on start. +}; + +/** + * Start a bulk write session + * @param tf - tinyframe instance + * @param bulk - bulk write config structure (malloc'd or static) + */ +void bulkwrite_start(TinyFrame *tf, struct bulk_write *bulk); + + +#endif //GEX_F072_MSG_BULKWRITE_H From 32c2c5a8836cc37e336dfda4c726f4bae662fec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 22:56:17 +0100 Subject: [PATCH 16/17] updated tinyframe and implemented bulk write --- TinyFrame/TinyFrame.c | 2 +- TinyFrame/TinyFrame.h | 2 +- comm/msg_bulkwrite.c | 2 +- units/test/unit_test.c | 37 +++++++++++++++++++++++++++++++------ 4 files changed, 34 insertions(+), 9 deletions(-) diff --git a/TinyFrame/TinyFrame.c b/TinyFrame/TinyFrame.c index fb6d8ac..bce258c 100644 --- a/TinyFrame/TinyFrame.c +++ b/TinyFrame/TinyFrame.c @@ -549,7 +549,7 @@ void _TF_FN TF_AcceptChar(TinyFrame *tf, unsigned char c) CKSUM_RESET(tf->cksum); // Start collecting the payload - if (tf->len >= TF_MAX_PAYLOAD_RX) { + if (tf->len > TF_MAX_PAYLOAD_RX) { // ERROR - frame too long. Consume, but do not store. tf->discard_data = true; } diff --git a/TinyFrame/TinyFrame.h b/TinyFrame/TinyFrame.h index a588309..1a617e7 100644 --- a/TinyFrame/TinyFrame.h +++ b/TinyFrame/TinyFrame.h @@ -10,7 +10,7 @@ * Upstream URL: https://github.com/MightyPork/TinyFrame */ -#define TF_VERSION "2.0.3" +#define TF_VERSION "2.0.4" //--------------------------------------------------------------------------- #include // for uint8_t etc diff --git a/comm/msg_bulkwrite.c b/comm/msg_bulkwrite.c index 77b2677..a2092b7 100644 --- a/comm/msg_bulkwrite.c +++ b/comm/msg_bulkwrite.c @@ -71,7 +71,7 @@ void bulkwrite_start(TinyFrame *tf, struct bulk_write *bulk) { uint8_t buf[8]; - PayloadBuilder pb = pb_start(buf, 4, NULL); + PayloadBuilder pb = pb_start(buf, 8, NULL); pb_u32(&pb, bulk->len); pb_u32(&pb, TF_MAX_PAYLOAD_RX); diff --git a/units/test/unit_test.c b/units/test/unit_test.c index 7490fe1..55e5fdb 100644 --- a/units/test/unit_test.c +++ b/units/test/unit_test.c @@ -93,6 +93,7 @@ enum PinCmd_ { CMD_PING = 0, CMD_ECHO = 1, CMD_BULKREAD = 2, + CMD_BULKWRITE = 3, }; static const char *longtext = "The history of all hitherto existing societies is the history of class struggles.\n\nFreeman and slave, patrician and plebeian, lord and serf, guild-master and journeyman, in a word, oppressor and oppressed, stood in constant opposition to one another, carried on an uninterrupted, now hidden, now open fight, a fight that each time ended, either in a revolutionary re-constitution of society at large, or in the common ruin of the contending classes.\n\nIn the earlier epochs of history, we find almost everywhere a complicated arrangement of society into various orders, a manifold gradation of social rank. In ancient Rome we have patricians, knights, plebeians, slaves; in the Middle Ages, feudal lords, vassals, guild-masters, journeymen, apprentices, serfs; in almost all of these classes, again, subordinate gradations.\n\nThe modern bourgeois society that has sprouted from the ruins of feudal society has not done away with class antagonisms. It has but established new classes, new conditions of oppression, new forms of struggle in place of the old ones. Our epoch, the epoch of the bourgeoisie, possesses, however, this distinctive feature: it has simplified the class antagonisms. Society as a whole is more and more splitting up into two great hostile camps, into two great classes, directly facing each other: Bourgeoisie and Proletariat.\n\nFrom the serfs of the Middle Ages sprang the chartered burghers of the earliest towns. From these burgesses the first elements of the bourgeoisie were developed.\n\nThe discovery of America, the rounding of the Cape, opened up fresh ground for the rising bourgeoisie. The East-Indian and Chinese markets, the colonisation of America, trade with the colonies, the increase in the means of exchange and in commodities generally, gave to commerce, to navigation, to industry, an impulse never before known, and thereby, to the revolutionary element in the tottering feudal society, a rapid development.\n\nThe feudal system of industry, under which industrial production was monopolised by closed guilds, now no longer sufficed for the growing wants of the new markets. The manufacturing system took its place. The guild-masters were pushed on one side by the manufacturing middle class; division of labour between the different corporate guilds vanished in the face of division of labour in each single workshop.\n\nMeantime the markets kept ever growing, the demand ever rising. Even manufacture no longer sufficed. Thereupon, steam and machinery revolutionised industrial production. The place of manufacture was taken by the giant, Modern Industry, the place of the industrial middle class, by industrial millionaires, the leaders of whole industrial armies, the modern bourgeois.\n\nModern industry has established the world-market, for which the discovery of America paved the way. This market has given an immense development to commerce, to navigation, to communication by land. This development has, in its time, reacted on the extension of industry; and in proportion as industry, commerce, navigation, railways extended, in the same proportion the bourgeoisie developed, increased its capital, and pushed into the background every class handed down from the Middle Ages.\n\nWe see, therefore, how the modern bourgeoisie is itself the product of a long course of development, of a series of revolutions in the modes of production and of exchange.\n\nEach step in the development of the bourgeoisie was accompanied by a corresponding political advance of that class. An oppressed class under the sway of the feudal nobility, an armed and self-governing association in the mediaeval commune; here independent urban republic (as in Italy and Germany), there taxable \"third estate\" of the monarchy (as in France), afterwards, in the period of manufacture proper, serving either the semi-feudal or the absolute monarchy as a counterpoise against the nobility, and, in fact, corner-stone of the great monarchies in general, the bourgeoisie has at last, since the establishment of Modern Industry and of the world-market, conquered for itself, in the modern representative State, exclusive political sway. The executive of the modern State is but a committee for managing the common affairs of the whole bourgeoisie."; @@ -108,6 +109,19 @@ static void br_longtext(struct bulk_read *bulk, uint32_t chunk, uint8_t *buffer) memcpy(buffer, longtext+bulk->offset, chunk); } +static void bw_dump(struct bulk_write *bulk, const uint8_t *chunk, uint32_t len) +{ + // clean-up request + if (chunk == NULL) { + free(bulk); + return; + } + + dbg("\r\nBulk write at %d, len %d", (int)bulk->offset, (int)len); + PUTSN((const char *) chunk, len); + PUTS("\r\n"); +} + /** Handle a request message */ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) { @@ -127,14 +141,25 @@ static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, Paylo break; case CMD_BULKREAD:; - struct bulk_read *bulk = malloc(sizeof(struct bulk_read)); - assert_param(bulk); + struct bulk_read *br = malloc(sizeof(struct bulk_read)); + assert_param(br); + + br->len = (uint32_t) strlen(longtext); + br->frame_id = frame_id; + br->read = br_longtext; + + bulkread_start(comm, br); + break; + + case CMD_BULKWRITE:; + struct bulk_write *bw = malloc(sizeof(struct bulk_write)); + assert_param(bw); - bulk->len = (uint32_t) strlen(longtext); - bulk->frame_id = frame_id; - bulk->read = br_longtext; + bw->len = 1024; + bw->frame_id = frame_id; + bw->write = bw_dump; - bulkread_start(comm, bulk); + bulkwrite_start(comm, bw); break; default: From 4ee1d8efd5fe2ffb5aed3b905555f4ce4a0d08ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 22:59:47 +0100 Subject: [PATCH 17/17] removed some logging --- comm/msg_bulkread.c | 1 - comm/msg_bulkwrite.c | 1 - 2 files changed, 2 deletions(-) diff --git a/comm/msg_bulkread.c b/comm/msg_bulkread.c index 3866870..9ee55c3 100644 --- a/comm/msg_bulkread.c +++ b/comm/msg_bulkread.c @@ -22,7 +22,6 @@ static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) // this is a final call before timeout, to clean up if (msg->data == NULL) { - dbg("Bulk rx lst cleanup\r\n"); goto close; } diff --git a/comm/msg_bulkwrite.c b/comm/msg_bulkwrite.c index a2092b7..bd42b27 100644 --- a/comm/msg_bulkwrite.c +++ b/comm/msg_bulkwrite.c @@ -19,7 +19,6 @@ static TF_Result bulkwrite_lst(TinyFrame *tf, TF_Msg *msg) // this is a final call before timeout, to clean up if (msg->data == NULL) { - dbg("Bulk rx lst cleanup\r\n"); goto close; }