From bdc91c2dedfddb679e905214126b76f829673d51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Mon, 2 Apr 2018 12:46:32 +0200 Subject: [PATCH] a better example, some small cleaning --- gex/gex_client.c | 24 ++++++- gex/gex_client.h | 3 +- gex/gex_unit.c | 35 +++++++--- main.c | 175 ++++++++--------------------------------------- 4 files changed, 75 insertions(+), 162 deletions(-) diff --git a/gex/gex_client.c b/gex/gex_client.c index 8bb4615..c4d6af4 100644 --- a/gex/gex_client.c +++ b/gex/gex_client.c @@ -134,15 +134,31 @@ TinyFrame *GEX_GetTF(GexClient *gex) } /** Find a unit */ -GexUnit *GEX_GetUnit(GexClient *gex, const char *name) +GexUnit *GEX_GetUnit(GexClient *gex, const char *name, const char *type) { GexUnit *u = find_unit_by_name(gex, name); if (u == NULL) { fprintf(stderr, "!! Unit %s not found!\n", name); + return NULL; } + + if (type != NULL && strcmp(u->type, type) != 0) { + fprintf(stderr, "!! Unit %s has type %s, expected %s!\n", name, u->type, type); + return NULL; + } + return u; } +/** Unhandled frame listener - for debug */ +static TF_Result hdl_default(TinyFrame *tf, TF_Msg*msg) +{ + (void)tf; + fprintf(stderr, "TF unhandled msg len %d, type %d, id %d", msg->len, msg->type, msg->frame_id); + hexDump("payload", msg->data, msg->len); + return TF_STAY; +} + /** Create a instance and connect */ GexClient *GEX_Init(const char *device, uint32_t timeout_ms) { @@ -176,7 +192,6 @@ GexClient *GEX_Init(const char *device, uint32_t timeout_ms) gex->tf->userdata = gex; // --- Test connectivity --- - fprintf(stderr, "Testing connection...\n"); TF_QuerySimple(gex->tf, MSG_PING, NULL, 0, connectivity_check_lst, 0); @@ -198,6 +213,9 @@ GexClient *GEX_Init(const char *device, uint32_t timeout_ms) // Bind the catch-all event handler. Will be re-distributed to individual unit listeners if needed. TF_AddTypeListener(gex->tf, MSG_UNIT_REPORT, unit_report_lst); + // Fallback TF listener for reporting unhandled frames + TF_AddGenericListener(GEX_GetTF(gex), hdl_default); + return gex; } @@ -231,7 +249,7 @@ void GEX_Poll(GexClient *gex) else { // nothing received? if (len == 0) { - // keep trying to read we have a reason to expect more data + // keep trying to read if we have a reason to expect more data if (gex->tf->state != 0) { if (cycle < MAX_RETRIES) { // start a new cycle, setting 'first' to use a blocking read diff --git a/gex/gex_client.h b/gex/gex_client.h index f6901c9..1b91b4d 100644 --- a/gex/gex_client.h +++ b/gex/gex_client.h @@ -54,8 +54,9 @@ GexUnit *GEX_SysUnit(GexClient *gex); * * @param gex - gex * @param name - unit name + * @param type - unit type, used to verify it's the right type */ -GexUnit *GEX_GetUnit(GexClient *gex, const char *name); +GexUnit *GEX_GetUnit(GexClient *gex, const char *name, const char *type); /** * Initialize the GEX client diff --git a/gex/gex_unit.c b/gex/gex_unit.c index 63a0f17..bd2a823 100644 --- a/gex/gex_unit.c +++ b/gex/gex_unit.c @@ -17,13 +17,14 @@ * Low level query * * @param unit - GEX unit to address. The unit is available in userdata1 of the response message, if any - * @param cmd - command byte, or TYPE if raw query is used + * @param cmd_or_type - command byte, or TYPE if raw query is used * @param payload - payload buffer * @param len - payload length * @param lst - TF listener to handle the response, can be NULL - * @param userdata2 userdata2 argument for the TF listener's message + * @param userdata2 userdata2 - argument for the TF listener's message + * @param raw_pld - true for raw payload (without callsign / cmd prefix) */ -static void GEX_LL_Query(GexUnit *unit, uint8_t cmd, +static void GEX_LL_Query(GexUnit *unit, uint8_t cmd_or_type, const uint8_t *payload, uint32_t len, GexSession session, bool is_reply, TF_Listener lst, void *userdata2, @@ -51,7 +52,7 @@ static void GEX_LL_Query(GexUnit *unit, uint8_t cmd, // prefix the actual payload with the callsign and command bytes. // TODO provide TF API for sending the payload externally in smaller chunks? Will avoid the malloc here pld[0] = callsign; - pld[1] = cmd; + pld[1] = cmd_or_type; memcpy(pld + 2, payload, len); } else { memcpy(pld, payload, len); @@ -59,7 +60,7 @@ static void GEX_LL_Query(GexUnit *unit, uint8_t cmd, TF_Msg msg; TF_ClearMsg(&msg); - msg.type = (raw_pld ? cmd : (uint8_t) MSG_UNIT_REQUEST); + msg.type = (raw_pld ? cmd_or_type : (uint8_t) MSG_UNIT_REQUEST); msg.data = pld; msg.len = (TF_LEN) (len + (raw_pld?0:2)); msg.userdata = unit; @@ -77,7 +78,12 @@ void GEX_Send(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t len) assert(unit != NULL); assert(unit->gex != NULL); - GEX_LL_Query(unit, cmd, payload, len, 0, false, NULL, NULL, false); + GEX_LL_Query(unit, cmd, payload, len, + 0 /* session - unused here, starts a new session */, + false /* is reply */, + NULL, /* listener */ + NULL /* userdata2 */, + false /* is raw payload */); } /** Send with no listener, don't wait for response */ @@ -88,7 +94,9 @@ void GEX_SendEx(GexUnit *unit, uint8_t cmd, assert(unit != NULL); assert(unit->gex != NULL); - GEX_LL_Query(unit, cmd, payload, len, session, is_reply, NULL, NULL, raw_pld); + GEX_LL_Query(unit, cmd, payload, len, + session, is_reply, NULL /* listener */, + NULL /*userdata*/, raw_pld); } /** listener for the synchronous query functionality */ @@ -132,7 +140,9 @@ GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd, gex->squery_msg.len = (uint32_t) strlen("TIMEOUT"); gex->squery_msg.payload = gex->squery_buffer; - GEX_LL_Query(unit, cmd, payload, len, session, is_reply, sync_query_lst, NULL, raw_pld); + GEX_LL_Query(unit, cmd, payload, len, + session, is_reply, sync_query_lst, + NULL /*userdata2*/, raw_pld); GEX_Poll(gex); @@ -148,11 +158,12 @@ GexMsg GEX_Query(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t le { assert(unit != NULL); assert(unit->gex != NULL); - return GEX_QueryEx(unit, cmd, payload, len, 0, false, false); + return GEX_QueryEx(unit, cmd, payload, len, + 0 /*session*/, false /*is_reply*/, false /*raw_pld*/); } -/** listener for the synchronous query functionality */ +/** listener for asynchronous query */ static TF_Result async_query_lst(TinyFrame *tf, TF_Msg *msg) { (void)tf; @@ -181,5 +192,7 @@ void GEX_QueryAsync(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t assert(unit->gex != NULL); // Async query does not poll, instead the user listener is attached to the message - GEX_LL_Query(unit, cmd, payload, len, 0, false, async_query_lst, lst, false); + GEX_LL_Query(unit, cmd, payload, len, + 0 /*session*/, false /*is_reply*/, async_query_lst, + lst /*userdata2*/, false /*raw_pld*/); } diff --git a/main.c b/main.c index 9bbf9d7..2b28dc4 100644 --- a/main.c +++ b/main.c @@ -4,8 +4,9 @@ #include #include -#include "utils/hexdump.h" #include "gex.h" +#include "utils/hexdump.h" +#include "utils/payload_builder.h" static GexClient *gex; @@ -13,164 +14,44 @@ static GexClient *gex; static void sigintHandler(int sig) { (void)sig; - - if (gex != NULL) { - GEX_DeInit(gex); - } + if (gex != NULL) GEX_DeInit(gex); exit(0); } -#define LED_CMD_TOGGLE 0x02 - -TF_Result hdl_default(TinyFrame *tf, TF_Msg*msg) -{ - (void)tf; - fprintf(stderr, "TF unhandled msg len %d, type %d, id %d", msg->len, msg->type, msg->frame_id); - hexDump("payload", msg->data, msg->len); - return TF_STAY; -} - -const char *longtext = "A sharper perspective on this matter is particularly important to feminist\r\n" - "thought today, because a major tendency in feminism has constructed the\r\n" - "problem of domination as a drama of female vulnerability victimized by male\r\n" - "aggression. Even the more sophisticated feminist thinkers frequently shy\r\n" - "away from the analysis of submission, for fear that in admitting woman's\r\n" - "participation in the relationship of domination, the onus of responsibility\r\n" - "will appear to shift from men to women, and the moral victory from women to\r\n" - "men. More generally, this has been a weakness of radical politics: to\r\n" - "idealize the oppressed, as if their politics and culture were untouched by\r\n" - "the system of domination, as if people did not participate in their own\r\n" - "submission. To reduce domination to a simple relation of doer and done-to\r\n" - "is to substitute moral outrage for analysis.\r\n" - "\t\t-- Jessica Benjamin, \"The Bonds of Love\"" - "A sharper perspective on this matter is particularly important to feminist\r\n" - "thought today, because a major tendency in feminism has constructed the\r\n" - "problem of domination as a drama of female vulnerability victimized by male\r\n" - "aggression. Even the more sophisticated feminist thinkers frequently shy\r\n" - "away from the analysis of submission, for fear that in admitting woman's\r\n" - "participation in the relationship of domination, the onus of responsibility\r\n" - "will appear to shift from men to women, and the moral victory from women to\r\n" - "men. More generally, this has been a weakness of radical politics: to\r\n" - "idealize the oppressed, as if their politics and culture were untouched by\r\n" - "the system of domination, as if people did not participate in their own\r\n" - "submission. To reduce domination to a simple relation of doer and done-to\r\n" - "is to substitute moral outrage for analysis.\r\n" - "\t\t-- Jessica Benjamin, \"The Bonds of Love\"" - "A sharper perspective on this matter is particularly important to feminist\r\n" - "thought today, because a major tendency in feminism has constructed the\r\n" - "problem of domination as a drama of female vulnerability victimized by male\r\n" - "aggression. Even the more sophisticated feminist thinkers frequently shy\r\n" - "away from the analysis of submission, for fear that in admitting woman's\r\n" - "participation in the relationship of domination, the onus of responsibility\r\n" - "will appear to shift from men to women, and the moral victory from women to\r\n" - "men. More generally, this has been a weakness of radical politics: to\r\n" - "idealize the oppressed, as if their politics and culture were untouched by\r\n" - "the system of domination, as if people did not participate in their own\r\n" - "submission. To reduce domination to a simple relation of doer and done-to\r\n" - "is to substitute moral outrage for analysis.\r\n" - "\t\t-- Jessica Benjamin, \"The Bonds of Love\" \r\nEND OF TEXT"; - +/** Main function - test the library */ int main(void) { - GexBulk br; - - // Bind ^C handler for safe shutdown + // Bind ^C handler for safe shutdown - need to release the port signal(SIGINT, sigintHandler); gex = GEX_Init("/dev/ttyACM0", 200); if (!gex) exit(1); - // Fallback TF listener for reporting unhandled frames - TF_AddGenericListener(GEX_GetTF(gex), hdl_default); - - //GexUnit *led = GEX_Unit(gex, "LED"); - //GEX_Send(led, LED_CMD_TOGGLE, NULL, 0); - - GexUnit *test = GEX_GetUnit(gex, "TEST"); - assert(test != NULL); - - // the "PING" command - GexMsg msg; - -#if 1 - // Simple response - msg = GEX_Query0(test, 0); - assert(msg.type == MSG_SUCCESS); - fprintf(stderr, "Cmd \"PING\" OK\n"); -#endif - -#if 0 - // Load settings to a buffer as INI - uint8_t inifile[10000]; - br = (GexBulk){ - .buffer = inifile, - .capacity = 10000, - .req_cmd = MSG_INI_READ, - .req_data = NULL, - .req_len = 0, - }; - uint32_t actuallyRead = GEX_BulkRead(GEX_SysUnit(gex), &br); - fprintf(stderr, "Read %d bytes of INI:\n", actuallyRead); - fprintf(stderr, "%.*s", actuallyRead, inifile); - - // And send it back... - br.len = actuallyRead; - br.req_cmd = MSG_INI_WRITE; - GEX_BulkWrite(GEX_SysUnit(gex), &br); -#endif - -#if 0 - // Load settings to a buffer as INI - char inifile[10000]; - uint32_t len = GEX_IniRead(gex, inifile, 10000); - assert(len > 0); - - fprintf(stderr, "Read %d bytes of INI:\n", len); - fprintf(stderr, "%.*s", len, inifile); - - // And send it back... - bool suc = GEX_IniWrite(gex, inifile); - assert(suc); -#endif - -#if 0 - // Test a echo command that returns back what was sent to it as useful payload - const char *s = "I am \r\nreturning this otherwise good typing paper to you because someone " - "has printed gibberish all over it and put your name at the top. Read the communist manifesto via bulk transfer. Read the communist manifesto via bulk transfer. Technology is a constand battle between manufacturers producing bigger and " - "more idiot-proof systems and nature producing bigger and better idiots. END"; - msg = GEX_Query(test, 1, (const uint8_t *) s, (uint32_t) strlen(s)); - fprintf(stderr, "\"ECHO\" cmd resp: %d, len %d, pld: %.*s\n", msg.type, (int) msg.len, (int) msg.len, (char *) msg.payload); - assert(0==strncmp((char*)msg.payload, s, strlen(s))); -#endif - -#if 0 - // Read the communist manifesto via bulk transfer - uint8_t buffr[10000]; - br = (GexBulk){ - .buffer = buffr, - .capacity = 10000, - .req_cmd = 2, - .req_data = NULL, - .req_len = 0, - }; - uint32_t actuallyRead = GEX_BulkRead(test, &br); - fprintf(stderr, "Read %d bytes:\n", actuallyRead); - fprintf(stderr, "%.*s", actuallyRead, buffr); -#endif + // INI read example +// char buffer[2000]; +// uint32_t len = GEX_IniRead(gex, buffer, 2000); +// printf("%.*s", len, buffer); + + // DO example + GexUnit *bg = GEX_GetUnit(gex, "bargraph", "DO"); + + struct DO_Set { + uint16_t bits; + } __attribute__((packed)); + + struct DO_Set cmd_set; + for (int i = 0; i < 100; i++) { + int n = i%20; + if(n>=10) n=10-(n-10); + cmd_set.bits = ~(((1 << (n))-1)<<(10-n)); + GEX_Send(bg, 0x00, (uint8_t *)&cmd_set, sizeof(cmd_set)); + usleep(40000); + } -#if 0 - // Read the communist manifesto via bulk transfer - br = (GexBulk){ - .buffer = (uint8_t *) longtext, - .len = (uint32_t) strlen(longtext), - .req_cmd = 3, - .req_data = NULL, - .req_len = 0, - }; - assert(true == GEX_BulkWrite(test, &br)); -#endif + // all dark + cmd_set.bits = 0x3FF; + GEX_Send(bg, 0x00, (uint8_t *)&cmd_set, sizeof(cmd_set)); - fprintf(stderr, "\n\nALL done, ending.\n"); GEX_DeInit(gex); return 0; }