From 02f654a87b35d6e7dc806abef9dd4cc256bcd4fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Tue, 19 Dec 2017 00:47:40 +0100 Subject: [PATCH] new apis --- gex/gex_client.c | 61 ++++++++++++++++++++++++++++++++++----- gex/gex_client.h | 38 +++++++++++++++++++++--- gex/gex_client_internal.h | 17 +++++++---- 3 files changed, 98 insertions(+), 18 deletions(-) diff --git a/gex/gex_client.c b/gex/gex_client.c index b662d5e..1f65b04 100644 --- a/gex/gex_client.c +++ b/gex/gex_client.c @@ -25,6 +25,7 @@ TF_Result connectivityCheckCb(TinyFrame *tf, TF_Msg *msg) return TF_CLOSE; } + /** Delete recursively all GEX callsign look-up table entries */ static void destroy_unit_lookup(GexClient *gex) { @@ -37,6 +38,7 @@ static void destroy_unit_lookup(GexClient *gex) gex->ulu_head = NULL; } + /** Get callsign for unit 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; } + /** Listener for the "list units" query response */ TF_Result listUnitsCb(TinyFrame *tf, TF_Msg *msg) { @@ -83,6 +86,7 @@ TF_Result listUnitsCb(TinyFrame *tf, TF_Msg *msg) return TF_CLOSE; } + /** Create a instance and connect */ GexClient *GEX_Init(const char *device, int timeout_ms) { @@ -120,14 +124,15 @@ GexClient *GEX_Init(const char *device, int timeout_ms) return gex; } + /** Try to read from the serial port and process any received bytes with TF */ void GEX_Poll(GexClient *gex) { - uint8_t pollbuffer[1024]; + uint8_t pollbuffer[TF_MAX_PAYLOAD_RX]; 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) { fprintf(stderr, "ERROR %d in GEX Poll: %s\n", errno, strerror(errno)); } else { @@ -136,6 +141,7 @@ void GEX_Poll(GexClient *gex) } } + /** Free the struct */ void GEX_DeInit(GexClient *gex) { @@ -146,17 +152,20 @@ void GEX_DeInit(GexClient *gex) free(gex); } + /** Query a unit */ -void GEX_QueryUnit(GexClient *gex, - const char *unit, uint8_t cmd, - uint8_t *payload, uint32_t len, - TF_Listener listener) +void GEX_Query(GexClient *gex, + const char *unit, uint8_t cmd, + uint8_t *payload, uint32_t len, + TF_Listener listener) { uint8_t cs = find_callsign_by_name(gex, unit); assert(cs != 0); uint8_t *pld = malloc(len + 2); 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[1] = cmd; memcpy(pld+2, payload, len); @@ -169,8 +178,44 @@ void GEX_QueryUnit(GexClient *gex, TF_Query(gex->tf, &msg, listener, 0); 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) diff --git a/gex/gex_client.h b/gex/gex_client.h index c98c7f4..5c12593 100644 --- a/gex/gex_client.h +++ b/gex/gex_client.h @@ -44,9 +44,39 @@ void GEX_DeInit(GexClient *gex); * @param len - number of bytes in the payload * @param listener - TF listener function called for the response */ -void GEX_QueryUnit(GexClient *gex, - const char *unit, uint8_t cmd, - uint8_t *payload, uint32_t len, - TF_Listener listener); +void GEX_Query(GexClient *gex, + const char *unit, uint8_t cmd, + uint8_t *payload, uint32_t len, + 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 diff --git a/gex/gex_client_internal.h b/gex/gex_client_internal.h index e1c1502..adf8d4d 100644 --- a/gex/gex_client_internal.h +++ b/gex/gex_client_internal.h @@ -6,19 +6,24 @@ #define GEX_CLIENT_GEX_CLIENT_INTERNAL_H struct gex_name_lu { - char *name; - char *type; - uint8_t callsign; - struct gex_name_lu *next; + char *name; //!< Unit name + char *type; //!< Unit type + uint8_t callsign; //!< Unit callsign byte + struct gex_name_lu *next; //!< Pointer to the next entry in this linked list, or NULL if none }; struct gex_client_ { 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 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