more work on cleaning it up, added experimental QueryUnit cmd and mesage constants

master
Ondřej Hruška 7 years ago
parent 852c0946bb
commit c4c0104772
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 2
      CMakeLists.txt
  2. 2
      gex/TF_Integration.c
  3. 121
      gex/gex_client.c
  4. 27
      gex/gex_client.h
  5. 24
      gex/gex_client_internal.h
  6. 23
      gex/gex_message_types.h

@ -9,6 +9,8 @@ set(SOURCE_FILES
gex/serial/serial.h gex/serial/serial.h
gex/gex_client.c gex/gex_client.c
gex/gex_client.h gex/gex_client.h
gex/gex_client_internal.h
gex/gex_message_types.h
gex/utils/hexdump.c gex/utils/hexdump.c
gex/utils/hexdump.h gex/utils/hexdump.h
gex/TF_Integration.c gex/TF_Integration.c

@ -6,6 +6,8 @@
#include <assert.h> #include <assert.h>
#include <errno.h> #include <errno.h>
#include "gex_client_internal.h"
void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len) void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len)
{ {
GexClient *gc = tf->userdata; GexClient *gc = tf->userdata;

@ -8,11 +8,15 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include "TinyFrame.h" #include "TinyFrame.h"
#include "gex_client.h" #include "gex_client.h"
#include "serial.h" #include "serial.h"
#include "gex_client_internal.h"
#include "gex_message_types.h"
#include "utils/payload_parser.h"
/** Callback for ping */
TF_Result connectivityCheckCb(TinyFrame *tf, TF_Msg *msg) TF_Result connectivityCheckCb(TinyFrame *tf, TF_Msg *msg)
{ {
GexClient *gex = tf->userdata; GexClient *gex = tf->userdata;
@ -21,14 +25,74 @@ TF_Result connectivityCheckCb(TinyFrame *tf, TF_Msg *msg)
return TF_CLOSE; return TF_CLOSE;
} }
/** Delete recursively all GEX callsign look-up table entries */
static void destroy_unit_lookup(GexClient *gex)
{
struct gex_name_lu *next = gex->ulu_head;
while (next != NULL) {
struct gex_name_lu *cur = next;
next = next->next;
free(cur);
}
gex->ulu_head = NULL;
}
/** Get callsign for unit name */
static uint8_t find_callsign_by_name(GexClient *gex, const char *name)
{
struct gex_name_lu *next = gex->ulu_head;
while (next != NULL) {
if (strcmp(next->name, name) == 0) {
return next->callsign;
}
next = next->next;
}
return 0;
}
/** Listener for the "list units" query response */
TF_Result listUnitsCb(TinyFrame *tf, TF_Msg *msg)
{
GexClient *gex = tf->userdata;
destroy_unit_lookup(gex);
PayloadParser pp = pp_start((uint8_t*)msg->data, msg->len, NULL);
uint8_t count = pp_u8(&pp);
char buf[100];
struct gex_name_lu *tail = NULL;
for(int i=0; i< count; i++) {
uint8_t cs = pp_u8(&pp);
pp_string(&pp, buf, 100);
fprintf(stderr, "Available unit \"%s\" @ %d\n", buf, cs);
// append
struct gex_name_lu *lu = malloc(sizeof(struct gex_name_lu));
lu->next = NULL;
lu->type = "UNKNOWN";
lu->name = strdup(buf);
lu->callsign = cs;
if (tail == NULL) {
gex->ulu_head = lu;
} else {
tail->next = lu;
}
tail = lu;
}
return TF_CLOSE;
}
/** Create a instance and connect */
GexClient *GEX_Init(const char *device, int timeout_ms) GexClient *GEX_Init(const char *device, int timeout_ms)
{ {
assert(device != NULL); assert(device != NULL);
// --- Init the struct ---
GexClient *gex = calloc(1, sizeof(GexClient)); GexClient *gex = calloc(1, sizeof(GexClient));
assert(gex != NULL); assert(gex != NULL);
// Open the device // --- Open the device ---
gex->acm_device = device; gex->acm_device = device;
gex->acm_fd = serial_open(device, false, (timeout_ms + 50) / 100); gex->acm_fd = serial_open(device, false, (timeout_ms + 50) / 100);
if (gex->acm_fd == -1) { if (gex->acm_fd == -1) {
@ -39,11 +103,8 @@ GexClient *GEX_Init(const char *device, int timeout_ms)
gex->tf = TF_Init(TF_MASTER); gex->tf = TF_Init(TF_MASTER);
gex->tf->userdata = gex; gex->tf->userdata = gex;
// Test connectivity // --- Test connectivity ---
TF_Msg msg; TF_QuerySimple(gex->tf, MSG_PING, /*pld*/ NULL, 0, /*cb*/ connectivityCheckCb, 0);
TF_ClearMsg(&msg);
msg.type = 0x01; // TODO use constant
TF_Query(gex->tf, &msg, connectivityCheckCb, 0);
GEX_Poll(gex); GEX_Poll(gex);
if (!gex->connected) { if (!gex->connected) {
@ -52,12 +113,14 @@ GexClient *GEX_Init(const char *device, int timeout_ms)
return NULL; return NULL;
} }
// TODO load and store unit callsigns + names // --- populate callsign look-up table ---
TF_QuerySimple(gex->tf, MSG_LIST_UNITS, /*pld*/ NULL, 0, /*cb*/ listUnitsCb, 0);
GEX_Poll(gex);
return gex; return gex;
} }
/** 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[1024];
@ -73,11 +136,41 @@ void GEX_Poll(GexClient *gex)
} }
} }
/** Free the struct */
void GEX_DeInit(GexClient *gex)
{
if (gex == NULL) return;
close(gex->acm_fd);
destroy_unit_lookup(gex);
TF_DeInit(gex->tf);
free(gex);
}
void GEX_DeInit(GexClient *gc) /** Query a unit */
void GEX_QueryUnit(GexClient *gex,
const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len,
TF_Listener listener)
{ {
if (gc == NULL) return; uint8_t cs = find_callsign_by_name(gex, unit);
close(gc->acm_fd); assert(cs != 0);
TF_DeInit(gc->tf); uint8_t *pld = malloc(len + 2);
free(gc); assert(pld != NULL);
pld[0] = cs;
pld[1] = cmd;
memcpy(pld+2, payload, len);
TF_Msg msg;
TF_ClearMsg(&msg);
msg.type = MSG_UNIT_REQUEST;
msg.data = pld;
msg.len = (TF_LEN) (len + 2);
TF_Query(gex->tf, &msg, listener, 0);
free(pld);
GEX_Poll(gex);
} }
// TODO add Send command (no query)
// TODO add listener for spontaneous device reports with user configurable handler (per unit)

@ -10,13 +10,6 @@
#include <stdbool.h> #include <stdbool.h>
#include "TinyFrame.h" #include "TinyFrame.h"
struct gex_client_ {
TinyFrame *tf;
const char *acm_device;
int acm_fd;
bool connected;
};
typedef struct gex_client_ GexClient; typedef struct gex_client_ GexClient;
/** /**
@ -37,15 +30,23 @@ void GEX_Poll(GexClient *gex);
/** /**
* Safely release all resources used up by GEX_Init() * Safely release all resources used up by GEX_Init()
* *
* @param gc - the allocated client structure * @param gex - the allocated client structure
*/ */
void GEX_DeInit(GexClient *gc); void GEX_DeInit(GexClient *gex);
// --- Internal ---
/** /**
* This is accessed by TF_WriteImpl(). * Query a unit
* To be removed once TF supports multiple instances, i.e. without globals *
* @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
* @param listener - TF listener function called for the response
*/ */
extern int gex_serial_fd; void GEX_QueryUnit(GexClient *gex,
const char *unit, uint8_t cmd,
uint8_t *payload, uint32_t len,
TF_Listener listener);
#endif //GEX_CLIENT_GEX_CLIENT_H #endif //GEX_CLIENT_GEX_CLIENT_H

@ -0,0 +1,24 @@
//
// Created by MightyPork on 2017/12/15.
//
#ifndef GEX_CLIENT_GEX_CLIENT_INTERNAL_H
#define GEX_CLIENT_GEX_CLIENT_INTERNAL_H
struct gex_name_lu {
char *name;
char *type;
uint8_t callsign;
struct gex_name_lu *next;
};
struct gex_client_ {
TinyFrame *tf; //!< TinyFrame instance
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
};
#endif //GEX_CLIENT_GEX_CLIENT_INTERNAL_H

@ -0,0 +1,23 @@
//
// Created by MightyPork on 2017/12/15.
//
#ifndef GEX_CLIENT_GEX_MESSAGE_TYPES_H
#define GEX_CLIENT_GEX_MESSAGE_TYPES_H
/**
* Supported message types (TF_TYPE)
*/
enum TF_Types_ {
// General, low level
MSG_SUCCESS = 0x00, //!< Generic success response; used by default in all responses; payload is transaction-specific
MSG_PING = 0x01, //!< Ping request (or response), used to test connection
MSG_ERROR = 0x02, //!< Generic failure response (when a request fails to execute)
// Unit messages
MSG_UNIT_REQUEST = 0x10, //!< Command addressed to a particular unit
MSG_UNIT_REPORT = 0x11, //!< Spontaneous report from a unit
// System messages
MSG_LIST_UNITS = 0x20, //!< Get all unit call-signs and names
};
#endif //GEX_CLIENT_GEX_MESSAGE_TYPES_H
Loading…
Cancel
Save