|
|
|
@ -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) { |
|
|
|
|