bulk kinda works (reading oly so far)Ã

master
Ondřej Hruška 6 years ago
parent bc619c6139
commit 0f711495df
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 3
      gex/TF_Integration.c
  2. 37
      gex/gex_client.c
  3. 1
      gex/gex_internal.h
  4. 90
      gex/gex_unit.c
  5. 42
      gex/serial/serial.c
  6. 8
      gex/serial/serial.h
  7. 4
      main.c

@ -5,6 +5,7 @@
#include <errno.h> #include <errno.h>
#include "TinyFrame.h" #include "TinyFrame.h"
#include "utils/hexdump.h"
#include "gex.h" #include "gex.h"
#include "gex_internal.h" #include "gex_internal.h"
@ -14,6 +15,8 @@ void TF_WriteImpl(TinyFrame *tf, const uint8_t *buff, size_t len)
GexClient *gc = tf->userdata; GexClient *gc = tf->userdata;
assert(gc->acm_fd != 0); assert(gc->acm_fd != 0);
hexDump("TF_Write", buff, (uint32_t)len);
ssize_t rv = write(gc->acm_fd, buff, len); ssize_t rv = write(gc->acm_fd, buff, len);
if (rv != (ssize_t)len) { if (rv != (ssize_t)len) {
fprintf(stderr, "ERROR %d in TF write: %s\n", errno, strerror(errno)); fprintf(stderr, "ERROR %d in TF write: %s\n", errno, strerror(errno));

@ -8,6 +8,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <errno.h> #include <errno.h>
#include <utils/hexdump.h>
#include "TinyFrame.h" #include "TinyFrame.h"
#define GEX_H // to allow including other headers #define GEX_H // to allow including other headers
@ -138,7 +139,8 @@ GexClient *GEX_Init(const char *device, int timeout_ms)
// --- 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->ser_timeout = timeout_ms;
gex->acm_fd = serial_open(device);
if (gex->acm_fd == -1) { if (gex->acm_fd == -1) {
free(gex); free(gex);
fprintf(stderr, "FAILED TO CONNECT TO %s!\n", device); fprintf(stderr, "FAILED TO CONNECT TO %s!\n", device);
@ -177,12 +179,33 @@ void GEX_Poll(GexClient *gex)
assert(gex != NULL); assert(gex != NULL);
ssize_t len = read(gex->acm_fd, pollbuffer, TF_MAX_PAYLOAD_RX); // TODO wait only for expect amount? bool first = true;
if (len < 0) {
fprintf(stderr, "ERROR %d in GEX Poll: %s\n", errno, strerror(errno)); do {
} else { if (first) serial_shouldwait(gex->acm_fd, gex->ser_timeout);
TF_Accept(gex->tf, pollbuffer, (size_t) len); ssize_t len = read(gex->acm_fd, pollbuffer, TF_MAX_PAYLOAD_RX);
} if (first) {
serial_noblock(gex->acm_fd);
first = false;
}
if (len < 0) {
fprintf(stderr, "ERROR %d in GEX Poll: %s\n", errno, strerror(errno));
break;
}
else {
if (len == 0) {
fprintf(stderr,"No more data to read.\n");
break;
}
else {
fprintf(stderr, "rx %d bytes\n", (int) len);
hexDump("TF_Receive", pollbuffer, (uint32_t) len);
TF_Accept(gex->tf, pollbuffer, (size_t) len);
}
}
} while(1);
} }
/** Free the struct */ /** Free the struct */

@ -21,6 +21,7 @@ struct gex_client {
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
uint32_t ser_timeout; //!< Timeout for read()/write()
// synchronous query "hacks" // synchronous query "hacks"
bool squery_ok; //!< flag that the query response was received bool squery_ok; //!< flag that the query response was received

@ -24,33 +24,47 @@
* @param lst - TF listener to handle the response, can be NULL * @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
*/ */
static void GEX_LL_Query(GexUnit *unit, static void GEX_LL_Query(GexUnit *unit, uint8_t cmd,
uint8_t cmd,
const uint8_t *payload, uint32_t len, const uint8_t *payload, uint32_t len,
GexSession session, bool is_reply, GexSession session, bool is_reply,
TF_Listener lst, void *userdata2) TF_Listener lst, void *userdata2,
bool raw_pld)
{ {
assert(unit != NULL); assert(unit != NULL);
assert(unit->gex != NULL); assert(unit->gex != NULL);
fprintf(stderr, "raw pld? %d\n", raw_pld);
GexClient *gex = unit->gex; GexClient *gex = unit->gex;
uint8_t callsign = unit->callsign; uint8_t callsign = 0;
assert(callsign != 0); uint8_t *pld = NULL;
uint8_t *pld = malloc(len + 2);
if (!raw_pld) {
callsign = unit->callsign;
assert(callsign != 0);
pld = malloc(len + 2);
} else {
pld = malloc(len);
}
assert(pld != NULL); assert(pld != NULL);
{ {
// prefix the actual payload with the callsign and command bytes. if (!raw_pld) {
// TODO provide TF API for sending the payload externally in smaller chunks? Will avoid the malloc here // prefix the actual payload with the callsign and command bytes.
pld[0] = callsign; // TODO provide TF API for sending the payload externally in smaller chunks? Will avoid the malloc here
pld[1] = cmd; pld[0] = callsign;
memcpy(pld + 2, payload, len); pld[1] = cmd;
memcpy(pld + 2, payload, len);
} else {
memcpy(pld, payload, len);
}
TF_Msg msg; TF_Msg msg;
TF_ClearMsg(&msg); TF_ClearMsg(&msg);
msg.type = MSG_UNIT_REQUEST; msg.type = (raw_pld ? cmd : (uint8_t) MSG_UNIT_REQUEST);
msg.data = pld; msg.data = pld;
msg.len = (TF_LEN) (len + 2); msg.len = (TF_LEN) (len + (raw_pld?0:2));
msg.userdata = unit; msg.userdata = unit;
msg.userdata2 = userdata2; msg.userdata2 = userdata2;
msg.frame_id = session; msg.frame_id = session;
@ -66,10 +80,7 @@ void GEX_Send(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t len)
assert(unit != NULL); assert(unit != NULL);
assert(unit->gex != NULL); assert(unit->gex != NULL);
GEX_LL_Query(unit, cmd, GEX_LL_Query(unit, cmd, payload, len, 0, false, NULL, NULL, false);
payload, len,
0, false,
NULL, NULL);
} }
/** Send with no listener, don't wait for response */ /** Send with no listener, don't wait for response */
@ -80,10 +91,7 @@ void GEX_SendEx(GexUnit *unit, uint8_t cmd,
assert(unit != NULL); assert(unit != NULL);
assert(unit->gex != NULL); assert(unit->gex != NULL);
GEX_LL_Query(unit, cmd, GEX_LL_Query(unit, cmd, payload, len, session, is_reply, NULL, NULL, false);
payload, len,
session, is_reply,
NULL, NULL);
} }
/** listener for the synchronous query functionality */ /** listener for the synchronous query functionality */
@ -92,6 +100,8 @@ static TF_Result sync_query_lst(TinyFrame *tf, TF_Msg *msg)
GexClient *gex = tf->userdata; GexClient *gex = tf->userdata;
assert(gex != NULL); assert(gex != NULL);
fprintf(stderr, "sync query lst called <-\n");
// clone the message // clone the message
gex->squery_msg.len = msg->len; gex->squery_msg.len = msg->len;
gex->squery_msg.unit = msg->userdata; gex->squery_msg.unit = msg->userdata;
@ -109,7 +119,8 @@ static TF_Result sync_query_lst(TinyFrame *tf, TF_Msg *msg)
/** Static query */ /** Static query */
static GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd, static GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd,
const uint8_t *payload, uint32_t len, const uint8_t *payload, uint32_t len,
GexSession session, bool is_reply) GexSession session, bool is_reply,
bool raw_pld)
{ {
assert(unit != NULL); assert(unit != NULL);
assert(unit->gex != NULL); assert(unit->gex != NULL);
@ -126,10 +137,7 @@ static GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd,
gex->squery_msg.len = (uint32_t) strlen("TIMEOUT"); gex->squery_msg.len = (uint32_t) strlen("TIMEOUT");
gex->squery_msg.payload = gex->squery_buffer; gex->squery_msg.payload = gex->squery_buffer;
GEX_LL_Query(unit, cmd, GEX_LL_Query(unit, cmd, payload, len, session, is_reply, sync_query_lst, NULL, raw_pld);
payload, len,
session, is_reply,
sync_query_lst, NULL);
GEX_Poll(gex); GEX_Poll(gex);
@ -145,7 +153,7 @@ GexMsg GEX_Query(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t le
{ {
assert(unit != NULL); assert(unit != NULL);
assert(unit->gex != NULL); assert(unit->gex != NULL);
return GEX_QueryEx(unit, cmd, payload, len, 0, false); return GEX_QueryEx(unit, cmd, payload, len, 0, false, false);
} }
@ -178,10 +186,7 @@ void GEX_QueryAsync(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t
assert(unit->gex != NULL); assert(unit->gex != NULL);
// Async query does not poll, instead the user listener is attached to the message // Async query does not poll, instead the user listener is attached to the message
GEX_LL_Query(unit, cmd, GEX_LL_Query(unit, cmd, payload, len, 0, false, async_query_lst, lst, false);
payload, len,
0, false,
async_query_lst, lst);
} }
// ---------------------------- BULK ---------------------------- // ---------------------------- BULK ----------------------------
@ -196,6 +201,7 @@ void GEX_QueryAsync(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t
*/ */
uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk) uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk)
{ {
fprintf(stderr, "Ask to read:\n");
// We ask for the transfer. This is unit specific and can contain information that determines the transferred data // We ask for the transfer. This is unit specific and can contain information that determines the transferred data
GexMsg resp0 = GEX_Query(unit, bulk->req_cmd, bulk->req_data, bulk->req_len); GexMsg resp0 = GEX_Query(unit, bulk->req_cmd, bulk->req_data, bulk->req_len);
@ -220,14 +226,19 @@ uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk)
fprintf(stderr, "Total is %d\n", total); fprintf(stderr, "Total is %d\n", total);
uint32_t at = 0; uint32_t at = 0;
while (at < total) { while (at < total+1) { // +1 makes sure we read one past end and trigger the END OF DATA msg
uint8_t buf[10]; uint8_t buf[10];
PayloadBuilder pb = pb_start(buf, 10, NULL); PayloadBuilder pb = pb_start(buf, 10, NULL);
pb_u32(&pb, 512); pb_u32(&pb, 128); // This selects the chunk size.
// FIXME Something is wrong in the poll function, or the transport in general,
// because chunks larger than e.g. 130 bytes seem to get stuck half-transferred.
// This isn't an issue for events and regular sending, only query responses like here.
// This may also cause problems when receiving events while reading a bulk.
// It may be best to get rid of the comport and use libusb, after all.
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_READ_POLL, fprintf(stderr, "Poll read:\n");
buf, (uint32_t) pb_length(&pb), GexMsg resp = GEX_QueryEx(unit, MSG_BULK_READ_POLL, buf,
resp0.session, true); (uint32_t) pb_length(&pb), resp0.session, true, true);
if (resp.type == MSG_ERROR) { if (resp.type == MSG_ERROR) {
fprintf(stderr, "Bulk read failed! %.*s\n", resp.len, (char *) resp.payload); fprintf(stderr, "Bulk read failed! %.*s\n", resp.len, (char *) resp.payload);
@ -236,6 +247,7 @@ uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk)
if (resp.type == MSG_BULK_END) { if (resp.type == MSG_BULK_END) {
// No more data // No more data
fprintf(stderr, "Bulk read OK, closed.\n");
return at; return at;
} }
@ -289,9 +301,9 @@ bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk)
uint32_t at = 0; uint32_t at = 0;
while (at < bulk->len) { while (at < bulk->len) {
uint32_t chunk = MIN(max_chunk, bulk->len - at); uint32_t chunk = MIN(max_chunk, bulk->len - at);
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_DATA, fprintf(stderr, "Query at %d, len %d\n", (int)at, (int)chunk);
bulk->buffer+at, chunk, GexMsg resp = GEX_QueryEx(unit, MSG_BULK_DATA, bulk->buffer + at, chunk,
resp0.session, true); resp0.session, true, true);
at += chunk; at += chunk;
if (resp.type == MSG_ERROR) { if (resp.type == MSG_ERROR) {

@ -27,8 +27,8 @@ static int set_interface_attribs(int fd, int speed, int parity)
tty.c_lflag = 0; // no signaling chars, no echo, tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing // no canonical processing
tty.c_oflag = 0; // no remapping, no delays tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout tty.c_cc[VTIME] = 2; // 0.2 seconds read timeout
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
@ -46,7 +46,21 @@ static int set_interface_attribs(int fd, int speed, int parity)
return 0; return 0;
} }
static void set_blocking(int fd, bool should_block, int read_timeout_0s1)
int serial_open(const char *device)
{
int fd = open (device, O_RDWR | O_NOCTTY | O_SYNC);
if (fd < 0) {
fprintf (stderr, "FAILED TO OPEN SERIAL! Error %d opening %s: %s\n", errno, device, strerror (errno));
return -1;
}
set_interface_attribs(fd, B115200, 0);
return fd;
}
void serial_noblock(int fd)
{ {
struct termios tty; struct termios tty;
memset(&tty, 0, sizeof tty); memset(&tty, 0, sizeof tty);
@ -55,23 +69,25 @@ static void set_blocking(int fd, bool should_block, int read_timeout_0s1)
return; return;
} }
tty.c_cc[VMIN] = (cc_t) (should_block ? 1 : 0); tty.c_cc[VMIN] = (cc_t) 0;
tty.c_cc[VTIME] = (cc_t) read_timeout_0s1; tty.c_cc[VTIME] = (cc_t) 0;
if (tcsetattr(fd, TCSANOW, &tty) != 0) if (tcsetattr(fd, TCSANOW, &tty) != 0)
fprintf(stderr, "error %d setting term attributes\n", errno); fprintf(stderr, "error %d setting term attributes\n", errno);
} }
int serial_open(const char *device, bool blocking, int timeout_0s1) void serial_shouldwait(int fd, int ms)
{ {
int fd = open (device, O_RDWR | O_NOCTTY | O_SYNC); struct termios tty;
if (fd < 0) { memset(&tty, 0, sizeof tty);
fprintf (stderr, "FAILED TO OPEN SERIAL! Error %d opening %s: %s\n", errno, device, strerror (errno)); if (tcgetattr(fd, &tty) != 0) {
return -1; fprintf(stderr, "error %d from tggetattr\n", errno);
return;
} }
set_interface_attribs(fd, B115200, 0); tty.c_cc[VMIN] = (cc_t) 0;
set_blocking (fd, blocking, timeout_0s1); tty.c_cc[VTIME] = (cc_t) (ms+50/100);
return fd; if (tcsetattr(fd, TCSANOW, &tty) != 0)
fprintf(stderr, "error %d setting term attributes\n", errno);
} }

@ -8,10 +8,12 @@
* Open a serial port * Open a serial port
* *
* @param device - device to open, e.g. /dev/ttyACM0 * @param device - device to open, e.g. /dev/ttyACM0
* @param blocking - true for `read()` to block until at least 1 byte is read
* @param timeout_0s1 - timeout for `read()` - if blocking, starts after the first character
* @return file descriptor * @return file descriptor
*/ */
int serial_open(const char *device, bool blocking, int timeout_0s1); int serial_open(const char *device);
void serial_shouldwait(int fd, int ms);
void serial_noblock(int fd);
#endif #endif

@ -34,7 +34,7 @@ int main(void)
// Bind ^C handler for safe shutdown // Bind ^C handler for safe shutdown
signal(SIGINT, sigintHandler); signal(SIGINT, sigintHandler);
gex = GEX_Init("/dev/ttyACM0", 200); gex = GEX_Init("/dev/ttyACM0", 100);
if (!gex) exit(1); if (!gex) exit(1);
TF_AddGenericListener(GEX_GetTF(gex), hdl_default); TF_AddGenericListener(GEX_GetTF(gex), hdl_default);
@ -67,7 +67,7 @@ int main(void)
}; };
uint32_t actuallyRead = GEX_BulkRead(test, &br); uint32_t actuallyRead = GEX_BulkRead(test, &br);
fprintf(stderr, "Read %d bytes:\n", actuallyRead); fprintf(stderr, "Read %d bytes:\n", actuallyRead);
fprintf(stderr, "%*.s", actuallyRead, buffr); fprintf(stderr, "%.*s", actuallyRead, buffr);
fprintf(stderr, "ALL OK, ending.\n"); fprintf(stderr, "ALL OK, ending.\n");
GEX_DeInit(gex); GEX_DeInit(gex);

Loading…
Cancel
Save