master
Ondřej Hruška 7 years ago
parent c4c0104772
commit 02f654a87b
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 61
      gex/gex_client.c
  2. 38
      gex/gex_client.h
  3. 17
      gex/gex_client_internal.h

@ -25,6 +25,7 @@ TF_Result connectivityCheckCb(TinyFrame *tf, TF_Msg *msg)
return TF_CLOSE; return TF_CLOSE;
} }
/** Delete recursively all GEX callsign look-up table entries */ /** Delete recursively all GEX callsign look-up table entries */
static void destroy_unit_lookup(GexClient *gex) static void destroy_unit_lookup(GexClient *gex)
{ {
@ -37,6 +38,7 @@ static void destroy_unit_lookup(GexClient *gex)
gex->ulu_head = NULL; gex->ulu_head = NULL;
} }
/** Get callsign for unit name */ /** Get callsign for unit name */
static uint8_t find_callsign_by_name(GexClient *gex, const char *name) static uint8_t find_callsign_by_name(GexClient *gex, const char *name)
{ {
@ -50,6 +52,7 @@ static uint8_t find_callsign_by_name(GexClient *gex, const char *name)
return 0; return 0;
} }
/** Listener for the "list units" query response */ /** Listener for the "list units" query response */
TF_Result listUnitsCb(TinyFrame *tf, TF_Msg *msg) TF_Result listUnitsCb(TinyFrame *tf, TF_Msg *msg)
{ {
@ -83,6 +86,7 @@ TF_Result listUnitsCb(TinyFrame *tf, TF_Msg *msg)
return TF_CLOSE; return TF_CLOSE;
} }
/** Create a instance and connect */ /** Create a instance and connect */
GexClient *GEX_Init(const char *device, int timeout_ms) GexClient *GEX_Init(const char *device, int timeout_ms)
{ {
@ -120,14 +124,15 @@ GexClient *GEX_Init(const char *device, int timeout_ms)
return gex; return gex;
} }
/** Try to read from the serial port and process any received bytes with TF */ /** Try to read from the serial port and process any received bytes with TF */
void GEX_Poll(GexClient *gex) void GEX_Poll(GexClient *gex)
{ {
uint8_t pollbuffer[1024]; uint8_t pollbuffer[TF_MAX_PAYLOAD_RX];
assert(gex != NULL); assert(gex != NULL);
ssize_t len = read(gex->acm_fd, pollbuffer, 1024); ssize_t len = read(gex->acm_fd, pollbuffer, TF_MAX_PAYLOAD_RX);
if (len < 0) { if (len < 0) {
fprintf(stderr, "ERROR %d in GEX Poll: %s\n", errno, strerror(errno)); fprintf(stderr, "ERROR %d in GEX Poll: %s\n", errno, strerror(errno));
} else { } else {
@ -136,6 +141,7 @@ void GEX_Poll(GexClient *gex)
} }
} }
/** Free the struct */ /** Free the struct */
void GEX_DeInit(GexClient *gex) void GEX_DeInit(GexClient *gex)
{ {
@ -146,17 +152,20 @@ void GEX_DeInit(GexClient *gex)
free(gex); free(gex);
} }
/** Query a unit */ /** Query a unit */
void GEX_QueryUnit(GexClient *gex, void GEX_Query(GexClient *gex,
const char *unit, uint8_t cmd, const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len, uint8_t *payload, uint32_t len,
TF_Listener listener) TF_Listener listener)
{ {
uint8_t cs = find_callsign_by_name(gex, unit); uint8_t cs = find_callsign_by_name(gex, unit);
assert(cs != 0); assert(cs != 0);
uint8_t *pld = malloc(len + 2); uint8_t *pld = malloc(len + 2);
assert(pld != NULL); assert(pld != NULL);
// 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] = cs; pld[0] = cs;
pld[1] = cmd; pld[1] = cmd;
memcpy(pld+2, payload, len); memcpy(pld+2, payload, len);
@ -169,8 +178,44 @@ void GEX_QueryUnit(GexClient *gex,
TF_Query(gex->tf, &msg, listener, 0); TF_Query(gex->tf, &msg, listener, 0);
free(pld); free(pld);
GEX_Poll(gex); if (NULL != listener) {
GEX_Poll(gex);
}
}
/** listener for the synchronous query functionality */
static TF_Result sync_query_lst(TinyFrame *tf, TF_Msg *msg)
{
GexClient *gex = tf->userdata;
// clone the message
memcpy(&gex->sync_query_response, msg, sizeof(TF_Msg));
// clone the buffer
if (msg->len > 0) memcpy(gex->sync_query_buffer, msg->data, msg->len);
// re-link the buffer
gex->sync_query_response.data = gex->sync_query_buffer;
gex->sync_query_ok = true;
}
/** Query a unit. The response is expected to be relatively short. */
TF_Msg *GEX_SyncQuery(GexClient *gex,
const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len)
{
gex->sync_query_ok = false;
memset(&gex->sync_query_response, 0, sizeof(TF_Msg));
GEX_Query(gex, unit, cmd, payload, len, sync_query_lst);
return gex->sync_query_ok ? &gex->sync_query_response : NULL;
}
/** Command a unit (same like query, but without listener and without polling) */
void GEX_Send(GexClient *gex,
const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len)
{
GEX_Query(gex, unit, cmd, payload, len, NULL);
} }
// TODO add Send command (no query)
// TODO add listener for spontaneous device reports with user configurable handler (per unit) // TODO add listener for spontaneous device reports with user configurable handler (per unit)

@ -44,9 +44,39 @@ void GEX_DeInit(GexClient *gex);
* @param len - number of bytes in the payload * @param len - number of bytes in the payload
* @param listener - TF listener function called for the response * @param listener - TF listener function called for the response
*/ */
void GEX_QueryUnit(GexClient *gex, void GEX_Query(GexClient *gex,
const char *unit, uint8_t cmd, const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len, uint8_t *payload, uint32_t len,
TF_Listener listener); TF_Listener listener);
/**
* Query a unit and return the response. The resulting message (including payload) is
* copied to a internal holder variable. Do not attempt to free it!
*
* @attention Calling `GEX_SyncQuery` destroys the previous sync query message and payload.
*
* @param gex - client instance
* @param unit - unit name
* @param cmd - command (hex)
* @param payload - payload for the unit
* @param len - number of bytes in the payload
* @return a clone of the response, or NULL if none arrived in time.
*/
TF_Msg *GEX_SyncQuery(GexClient *gex,
const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len);
/**
* Send a command with response no listener
*
* @param gex - client instance
* @param unit - unit name
* @param cmd - command (hex)
* @param payload - payload for the unit
* @param len - number of bytes in the payload
*/
void GEX_Send(GexClient *gex,
const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len);
#endif //GEX_CLIENT_GEX_CLIENT_H #endif //GEX_CLIENT_GEX_CLIENT_H

@ -6,19 +6,24 @@
#define GEX_CLIENT_GEX_CLIENT_INTERNAL_H #define GEX_CLIENT_GEX_CLIENT_INTERNAL_H
struct gex_name_lu { struct gex_name_lu {
char *name; char *name; //!< Unit name
char *type; char *type; //!< Unit type
uint8_t callsign; uint8_t callsign; //!< Unit callsign byte
struct gex_name_lu *next; struct gex_name_lu *next; //!< Pointer to the next entry in this linked list, or NULL if none
}; };
struct gex_client_ { struct gex_client_ {
TinyFrame *tf; //!< TinyFrame instance TinyFrame *tf; //!< TinyFrame instance
const char *acm_device; //!< Comport device name, might be used to reconnect const char *acm_device; //!< Comport device name, might be used to reconnect (?)
int acm_fd; //!< Open comport file descriptor int acm_fd; //!< Open comport file descriptor
bool connected; //!< Flag that we're currently connected to the comport bool connected; //!< Flag that we're currently connected to the comport
struct gex_name_lu *ulu_head; //!< Units look-up // synchronous query "hacks"
bool sync_query_ok; //!< flag that the query response was received
TF_Msg sync_query_response; //!< response message, copied here
uint8_t sync_query_buffer[TF_MAX_PAYLOAD_RX]; //!< buffer for the rx payload to be copied here
struct gex_name_lu *ulu_head; //!< Units look-up linked list
}; };
#endif //GEX_CLIENT_GEX_CLIENT_INTERNAL_H #endif //GEX_CLIENT_GEX_CLIENT_INTERNAL_H

Loading…
Cancel
Save