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 "TinyFrame.h"
#include "utils/hexdump.h"
#include "gex.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;
assert(gc->acm_fd != 0);
hexDump("TF_Write", buff, (uint32_t)len);
ssize_t rv = write(gc->acm_fd, buff, len);
if (rv != (ssize_t)len) {
fprintf(stderr, "ERROR %d in TF write: %s\n", errno, strerror(errno));

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

@ -21,6 +21,7 @@ struct gex_client {
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
uint32_t ser_timeout; //!< Timeout for read()/write()
// synchronous query "hacks"
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 userdata2 userdata2 argument for the TF listener's message
*/
static void GEX_LL_Query(GexUnit *unit,
uint8_t cmd,
static void GEX_LL_Query(GexUnit *unit, uint8_t cmd,
const uint8_t *payload, uint32_t len,
GexSession session, bool is_reply,
TF_Listener lst, void *userdata2)
TF_Listener lst, void *userdata2,
bool raw_pld)
{
assert(unit != NULL);
assert(unit->gex != NULL);
fprintf(stderr, "raw pld? %d\n", raw_pld);
GexClient *gex = unit->gex;
uint8_t callsign = unit->callsign;
assert(callsign != 0);
uint8_t *pld = malloc(len + 2);
uint8_t callsign = 0;
uint8_t *pld = NULL;
if (!raw_pld) {
callsign = unit->callsign;
assert(callsign != 0);
pld = malloc(len + 2);
} else {
pld = malloc(len);
}
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] = callsign;
pld[1] = cmd;
memcpy(pld + 2, payload, len);
if (!raw_pld) {
// 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] = callsign;
pld[1] = cmd;
memcpy(pld + 2, payload, len);
} else {
memcpy(pld, payload, len);
}
TF_Msg msg;
TF_ClearMsg(&msg);
msg.type = MSG_UNIT_REQUEST;
msg.type = (raw_pld ? cmd : (uint8_t) MSG_UNIT_REQUEST);
msg.data = pld;
msg.len = (TF_LEN) (len + 2);
msg.len = (TF_LEN) (len + (raw_pld?0:2));
msg.userdata = unit;
msg.userdata2 = userdata2;
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->gex != NULL);
GEX_LL_Query(unit, cmd,
payload, len,
0, false,
NULL, NULL);
GEX_LL_Query(unit, cmd, payload, len, 0, false, NULL, NULL, false);
}
/** 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->gex != NULL);
GEX_LL_Query(unit, cmd,
payload, len,
session, is_reply,
NULL, NULL);
GEX_LL_Query(unit, cmd, payload, len, session, is_reply, NULL, NULL, false);
}
/** 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;
assert(gex != NULL);
fprintf(stderr, "sync query lst called <-\n");
// clone the message
gex->squery_msg.len = msg->len;
gex->squery_msg.unit = msg->userdata;
@ -109,7 +119,8 @@ static TF_Result sync_query_lst(TinyFrame *tf, TF_Msg *msg)
/** Static query */
static GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd,
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->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.payload = gex->squery_buffer;
GEX_LL_Query(unit, cmd,
payload, len,
session, is_reply,
sync_query_lst, NULL);
GEX_LL_Query(unit, cmd, payload, len, session, is_reply, sync_query_lst, NULL, raw_pld);
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->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);
// Async query does not poll, instead the user listener is attached to the message
GEX_LL_Query(unit, cmd,
payload, len,
0, false,
async_query_lst, lst);
GEX_LL_Query(unit, cmd, payload, len, 0, false, async_query_lst, lst, false);
}
// ---------------------------- 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)
{
fprintf(stderr, "Ask to read:\n");
// 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);
@ -220,14 +226,19 @@ uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk)
fprintf(stderr, "Total is %d\n", total);
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];
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,
buf, (uint32_t) pb_length(&pb),
resp0.session, true);
fprintf(stderr, "Poll read:\n");
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_READ_POLL, buf,
(uint32_t) pb_length(&pb), resp0.session, true, true);
if (resp.type == MSG_ERROR) {
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) {
// No more data
fprintf(stderr, "Bulk read OK, closed.\n");
return at;
}
@ -289,9 +301,9 @@ bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk)
uint32_t at = 0;
while (at < bulk->len) {
uint32_t chunk = MIN(max_chunk, bulk->len - at);
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_DATA,
bulk->buffer+at, chunk,
resp0.session, true);
fprintf(stderr, "Query at %d, len %d\n", (int)at, (int)chunk);
GexMsg resp = GEX_QueryEx(unit, MSG_BULK_DATA, bulk->buffer + at, chunk,
resp0.session, true, true);
at += chunk;
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,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 5; // 0.5 seconds read timeout
tty.c_cc[VMIN] = 0; // read doesn't block
tty.c_cc[VTIME] = 2; // 0.2 seconds read timeout
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;
}
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;
memset(&tty, 0, sizeof tty);
@ -55,23 +69,25 @@ static void set_blocking(int fd, bool should_block, int read_timeout_0s1)
return;
}
tty.c_cc[VMIN] = (cc_t) (should_block ? 1 : 0);
tty.c_cc[VTIME] = (cc_t) read_timeout_0s1;
tty.c_cc[VMIN] = (cc_t) 0;
tty.c_cc[VTIME] = (cc_t) 0;
if (tcsetattr(fd, TCSANOW, &tty) != 0)
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);
if (fd < 0) {
fprintf (stderr, "FAILED TO OPEN SERIAL! Error %d opening %s: %s\n", errno, device, strerror (errno));
return -1;
struct termios tty;
memset(&tty, 0, sizeof tty);
if (tcgetattr(fd, &tty) != 0) {
fprintf(stderr, "error %d from tggetattr\n", errno);
return;
}
set_interface_attribs(fd, B115200, 0);
set_blocking (fd, blocking, timeout_0s1);
tty.c_cc[VMIN] = (cc_t) 0;
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
*
* @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
*/
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

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

Loading…
Cancel
Save