a better example, some small cleaning

master
Ondřej Hruška 7 years ago
parent 3b6017de33
commit bdc91c2ded
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 24
      gex/gex_client.c
  2. 3
      gex/gex_client.h
  3. 35
      gex/gex_unit.c
  4. 175
      main.c

@ -134,15 +134,31 @@ TinyFrame *GEX_GetTF(GexClient *gex)
} }
/** Find a unit */ /** 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); GexUnit *u = find_unit_by_name(gex, name);
if (u == NULL) { if (u == NULL) {
fprintf(stderr, "!! Unit %s not found!\n", name); 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; 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 */ /** Create a instance and connect */
GexClient *GEX_Init(const char *device, uint32_t timeout_ms) 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; gex->tf->userdata = gex;
// --- Test connectivity --- // --- Test connectivity ---
fprintf(stderr, "Testing connection...\n");
TF_QuerySimple(gex->tf, MSG_PING, TF_QuerySimple(gex->tf, MSG_PING,
NULL, 0, NULL, 0,
connectivity_check_lst, 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. // 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); 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; return gex;
} }
@ -231,7 +249,7 @@ void GEX_Poll(GexClient *gex)
else { else {
// nothing received? // nothing received?
if (len == 0) { 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 (gex->tf->state != 0) {
if (cycle < MAX_RETRIES) { if (cycle < MAX_RETRIES) {
// start a new cycle, setting 'first' to use a blocking read // start a new cycle, setting 'first' to use a blocking read

@ -54,8 +54,9 @@ GexUnit *GEX_SysUnit(GexClient *gex);
* *
* @param gex - gex * @param gex - gex
* @param name - unit name * @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 * Initialize the GEX client

@ -17,13 +17,14 @@
* Low level query * Low level query
* *
* @param unit - GEX unit to address. The unit is available in userdata1 of the response message, if any * @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 payload - payload buffer
* @param len - payload length * @param len - payload length
* @param lst - TF listener to handle the response, can be NULL * @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, const uint8_t *payload, uint32_t len,
GexSession session, bool is_reply, GexSession session, bool is_reply,
TF_Listener lst, void *userdata2, 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. // 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 // TODO provide TF API for sending the payload externally in smaller chunks? Will avoid the malloc here
pld[0] = callsign; pld[0] = callsign;
pld[1] = cmd; pld[1] = cmd_or_type;
memcpy(pld + 2, payload, len); memcpy(pld + 2, payload, len);
} else { } else {
memcpy(pld, payload, len); memcpy(pld, payload, len);
@ -59,7 +60,7 @@ static void GEX_LL_Query(GexUnit *unit, uint8_t cmd,
TF_Msg msg; TF_Msg msg;
TF_ClearMsg(&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.data = pld;
msg.len = (TF_LEN) (len + (raw_pld?0:2)); msg.len = (TF_LEN) (len + (raw_pld?0:2));
msg.userdata = unit; 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 != NULL);
assert(unit->gex != 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 */ /** 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 != NULL);
assert(unit->gex != 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 */ /** 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.len = (uint32_t) strlen("TIMEOUT");
gex->squery_msg.payload = gex->squery_buffer; 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); 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 != NULL);
assert(unit->gex != 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) static TF_Result async_query_lst(TinyFrame *tf, TF_Msg *msg)
{ {
(void)tf; (void)tf;
@ -181,5 +192,7 @@ void GEX_QueryAsync(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t
assert(unit->gex != NULL); assert(unit->gex != NULL);
// Async query does not poll, instead the user listener is attached to the message // 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*/);
} }

175
main.c

@ -4,8 +4,9 @@
#include <assert.h> #include <assert.h>
#include <unistd.h> #include <unistd.h>
#include "utils/hexdump.h"
#include "gex.h" #include "gex.h"
#include "utils/hexdump.h"
#include "utils/payload_builder.h"
static GexClient *gex; static GexClient *gex;
@ -13,164 +14,44 @@ static GexClient *gex;
static void sigintHandler(int sig) static void sigintHandler(int sig)
{ {
(void)sig; (void)sig;
if (gex != NULL) GEX_DeInit(gex);
if (gex != NULL) {
GEX_DeInit(gex);
}
exit(0); exit(0);
} }
#define LED_CMD_TOGGLE 0x02 /** Main function - test the library */
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";
int main(void) int main(void)
{ {
GexBulk br; // Bind ^C handler for safe shutdown - need to release the port
// Bind ^C handler for safe shutdown
signal(SIGINT, sigintHandler); signal(SIGINT, sigintHandler);
gex = GEX_Init("/dev/ttyACM0", 200); gex = GEX_Init("/dev/ttyACM0", 200);
if (!gex) exit(1); if (!gex) exit(1);
// Fallback TF listener for reporting unhandled frames // INI read example
TF_AddGenericListener(GEX_GetTF(gex), hdl_default); // char buffer[2000];
// uint32_t len = GEX_IniRead(gex, buffer, 2000);
//GexUnit *led = GEX_Unit(gex, "LED"); // printf("%.*s", len, buffer);
//GEX_Send(led, LED_CMD_TOGGLE, NULL, 0);
// DO example
GexUnit *test = GEX_GetUnit(gex, "TEST"); GexUnit *bg = GEX_GetUnit(gex, "bargraph", "DO");
assert(test != NULL);
struct DO_Set {
// the "PING" command uint16_t bits;
GexMsg msg; } __attribute__((packed));
#if 1 struct DO_Set cmd_set;
// Simple response for (int i = 0; i < 100; i++) {
msg = GEX_Query0(test, 0); int n = i%20;
assert(msg.type == MSG_SUCCESS); if(n>=10) n=10-(n-10);
fprintf(stderr, "Cmd \"PING\" OK\n"); cmd_set.bits = ~(((1 << (n))-1)<<(10-n));
#endif GEX_Send(bg, 0x00, (uint8_t *)&cmd_set, sizeof(cmd_set));
usleep(40000);
#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
#if 0 // all dark
// Read the communist manifesto via bulk transfer cmd_set.bits = 0x3FF;
br = (GexBulk){ GEX_Send(bg, 0x00, (uint8_t *)&cmd_set, sizeof(cmd_set));
.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
fprintf(stderr, "\n\nALL done, ending.\n");
GEX_DeInit(gex); GEX_DeInit(gex);
return 0; return 0;
} }

Loading…
Cancel
Save