a better example, some small cleaning
This commit is contained in:
+21
-3
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+24
-11
@@ -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*/);
|
||||
}
|
||||
|
||||
@@ -4,8 +4,9 @@
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#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);
|
||||
// INI read example
|
||||
// char buffer[2000];
|
||||
// uint32_t len = GEX_IniRead(gex, buffer, 2000);
|
||||
// printf("%.*s", len, buffer);
|
||||
|
||||
//GexUnit *led = GEX_Unit(gex, "LED");
|
||||
//GEX_Send(led, LED_CMD_TOGGLE, NULL, 0);
|
||||
// DO example
|
||||
GexUnit *bg = GEX_GetUnit(gex, "bargraph", "DO");
|
||||
|
||||
GexUnit *test = GEX_GetUnit(gex, "TEST");
|
||||
assert(test != NULL);
|
||||
struct DO_Set {
|
||||
uint16_t bits;
|
||||
} __attribute__((packed));
|
||||
|
||||
// the "PING" command
|
||||
GexMsg msg;
|
||||
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 1
|
||||
// Simple response
|
||||
msg = GEX_Query0(test, 0);
|
||||
assert(msg.type == MSG_SUCCESS);
|
||||
fprintf(stderr, "Cmd \"PING\" OK\n");
|
||||
#endif
|
||||
// all dark
|
||||
cmd_set.bits = 0x3FF;
|
||||
GEX_Send(bg, 0x00, (uint8_t *)&cmd_set, sizeof(cmd_set));
|
||||
|
||||
#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
|
||||
// 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
|
||||
|
||||
fprintf(stderr, "\n\nALL done, ending.\n");
|
||||
GEX_DeInit(gex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user