a better example, some small cleaning

master
Ondřej Hruška 6 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 */
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

@ -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

@ -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*/);
}

175
main.c

@ -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);
//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;
}

Loading…
Cancel
Save