new apis
This commit is contained in:
+53
-8
@@ -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)
|
||||||
|
|||||||
+34
-4
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user