From 737700a1575d531c0cb29449728d172255ce5903 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Fri, 22 Dec 2017 01:03:24 +0100 Subject: [PATCH] small cleaning up --- CMakeLists.txt | 2 +- gex/gex_bulk.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ gex/gex_bulk.h | 35 ++++++++++++ gex/gex_unit.c | 138 +---------------------------------------------- gex/gex_unit.h | 13 +++++ main.c | 2 +- 6 files changed, 196 insertions(+), 138 deletions(-) create mode 100644 gex/gex_bulk.c create mode 100644 gex/gex_bulk.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d653d5..c687b18 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,7 +26,7 @@ set(SOURCE_FILES gex/protocol/TinyFrame.c gex/protocol/TinyFrame.h gex/utils/type_coerce.h - gex/gex_defines.h gex/gex_unit.c gex/gex_unit.h gex/gex.h) + gex/gex_defines.h gex/gex_unit.c gex/gex_unit.h gex/gex.h gex/gex_bulk.c) include_directories( gex diff --git a/gex/gex_bulk.c b/gex/gex_bulk.c new file mode 100644 index 0000000..0725811 --- /dev/null +++ b/gex/gex_bulk.c @@ -0,0 +1,144 @@ +// +// Created by MightyPork on 2017/12/22. +// + +#include +#include +#include "utils/payload_parser.h" +#include "utils/payload_builder.h" + +#define GEX_H +#include "gex_bulk.h" +#include "gex_internal.h" +#include "gex_message_types.h" + +/** + * Bulk read from a unit, synchronous + * + * @param unit - the unit to target + * @param bulk - the bulk transport info struct + * @return actual number of bytes received. + */ +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); + + if (resp0.type == MSG_ERROR) { + fprintf(stderr, "Bulk read rejected! %.*s\n", resp0.len, (char*)resp0.payload); + return 0; + } + + if (resp0.type != MSG_BULK_READ_OFFER) { + fprintf(stderr, "Bulk read failed, response not BULK_READ_OFFER!\n"); + return 0; + } + +// fprintf(stderr, "BR, got offer!\n"); + + // Check how much data is available + PayloadParser pp = pp_start(resp0.payload, resp0.len, NULL); + uint32_t total = pp_u32(&pp); + assert(pp.ok); + + total = MIN(total, bulk->capacity); // clamp... +// fprintf(stderr, "Total is %d\n", total); + + uint32_t at = 0; + 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, 120); // This selects the chunk size. + // FIXME Something is wrong in the poll function, or the transport in general, + // because chunks larger than e.g. 128 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. + +// 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); + return 0; + } + + if (resp.type == MSG_BULK_END) { + // No more data + fprintf(stderr, "Bulk read OK, closed.\n"); + return at; + } + + if (resp.type == MSG_BULK_DATA) { + memcpy(bulk->buffer+at, resp.payload, resp.len); + at += resp.len; + } else { + fprintf(stderr, "Bulk read failed! Bad response type.\n"); + return 0; + } + } + + return at; +} + + +/** + * Bulk write to a unit, synchronous + * + * @param unit - the unit to target + * @param bulk - the bulk transport info struct + * @return true on success + */ +bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk) +{ + // We ask for the transfer. This is unit specific + GexMsg resp0 = GEX_Query(unit, bulk->req_cmd, bulk->req_data, bulk->req_len); + + if (resp0.type == MSG_ERROR) { + fprintf(stderr, "Bulk write rejected! %.*s\n", resp0.len, (char*)resp0.payload); + return false; + } + + if (resp0.type != MSG_BULK_WRITE_OFFER) { + fprintf(stderr, "Bulk write failed, response not MSG_BULK_WRITE_OFFER!\n"); + return false; + } + + PayloadParser pp = pp_start(resp0.payload, resp0.len, NULL); + uint32_t max_size = pp_u32(&pp); + uint32_t max_chunk = pp_u32(&pp); + assert(pp.ok); + + if (max_size < bulk->len) { + fprintf(stderr, "Write not possible, not enough space.\n"); + // Inform GEX we're not going to do it + GEX_SendEx(unit, MSG_BULK_ABORT, NULL, 0, resp0.session, true); + return false; + } + + uint32_t at = 0; + while (at < bulk->len) { + uint32_t chunk = MIN(max_chunk, bulk->len - at); +// 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) { + fprintf(stderr, "Bulk write failed! %.*s\n", resp.len, (char *) resp.payload); + return false; + } + + if (resp.type != MSG_SUCCESS) { + fprintf(stderr, "Bulk write failed! Bad response type.\n"); + return false; + } + } + + // Conclude the transfer + GEX_SendEx(unit, MSG_BULK_END, NULL, 0, resp0.session, true); + + return true; +} diff --git a/gex/gex_bulk.h b/gex/gex_bulk.h new file mode 100644 index 0000000..146f5f6 --- /dev/null +++ b/gex/gex_bulk.h @@ -0,0 +1,35 @@ +// +// Created by MightyPork on 2017/12/19. +// + +#ifndef GEX_CLIENT_GEX_BULK_H +#define GEX_CLIENT_GEX_BULK_H + +#ifndef GEX_H +#error "Include gex.h instead!" +#endif + +#include "gex_defines.h" +#include "gex_unit.h" +#include +#include + +/** + * Bulk read from a unit, synchronous + * + * @param unit - the unit to target + * @param bulk - the bulk transport info struct + * @return actual number of bytes received. + */ +uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk); + +/** + * Bulk write to a unit, synchronous + * + * @param unit - the unit to target + * @param bulk - the bulk transport info struct + * @return true on success + */ +bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk); + +#endif //GEX_CLIENT_GEX_BULK_H diff --git a/gex/gex_unit.c b/gex/gex_unit.c index fef3583..28916df 100644 --- a/gex/gex_unit.c +++ b/gex/gex_unit.c @@ -117,10 +117,10 @@ static TF_Result sync_query_lst(TinyFrame *tf, TF_Msg *msg) /** Static query */ -static GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd, +GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t len, GexSession session, bool is_reply, - bool raw_pld) + bool raw_pld) // FIXME this is horrible, split to multiple functions or use a struct { assert(unit != NULL); assert(unit->gex != NULL); @@ -188,137 +188,3 @@ void GEX_QueryAsync(GexUnit *unit, uint8_t cmd, const uint8_t *payload, uint32_t // 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, false); } - -// ---------------------------- BULK ---------------------------- - - -/** - * Bulk read from a unit, synchronous - * - * @param unit - the unit to target - * @param bulk - the bulk transport info struct - * @return actual number of bytes received. - */ -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); - - if (resp0.type == MSG_ERROR) { - fprintf(stderr, "Bulk read rejected! %.*s\n", resp0.len, (char*)resp0.payload); - return 0; - } - - if (resp0.type != MSG_BULK_READ_OFFER) { - fprintf(stderr, "Bulk read failed, response not BULK_READ_OFFER!\n"); - return 0; - } - -// fprintf(stderr, "BR, got offer!\n"); - - // Check how much data is available - PayloadParser pp = pp_start(resp0.payload, resp0.len, NULL); - uint32_t total = pp_u32(&pp); - assert(pp.ok); - - total = MIN(total, bulk->capacity); // clamp... -// fprintf(stderr, "Total is %d\n", total); - - uint32_t at = 0; - 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, 120); // This selects the chunk size. - // FIXME Something is wrong in the poll function, or the transport in general, - // because chunks larger than e.g. 128 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. - -// 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); - return 0; - } - - if (resp.type == MSG_BULK_END) { - // No more data - fprintf(stderr, "Bulk read OK, closed.\n"); - return at; - } - - if (resp.type == MSG_BULK_DATA) { - memcpy(bulk->buffer+at, resp.payload, resp.len); - at += resp.len; - } else { - fprintf(stderr, "Bulk read failed! Bad response type.\n"); - return 0; - } - } - - return at; -} - - -/** - * Bulk write to a unit, synchronous - * - * @param unit - the unit to target - * @param bulk - the bulk transport info struct - * @return true on success - */ -bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk) -{ - // We ask for the transfer. This is unit specific - GexMsg resp0 = GEX_Query(unit, bulk->req_cmd, bulk->req_data, bulk->req_len); - - if (resp0.type == MSG_ERROR) { - fprintf(stderr, "Bulk write rejected! %.*s\n", resp0.len, (char*)resp0.payload); - return false; - } - - if (resp0.type != MSG_BULK_WRITE_OFFER) { - fprintf(stderr, "Bulk write failed, response not MSG_BULK_WRITE_OFFER!\n"); - return false; - } - - PayloadParser pp = pp_start(resp0.payload, resp0.len, NULL); - uint32_t max_size = pp_u32(&pp); - uint32_t max_chunk = pp_u32(&pp); - assert(pp.ok); - - if (max_size < bulk->len) { - fprintf(stderr, "Write not possible, not enough space.\n"); - // Inform GEX we're not going to do it - GEX_SendEx(unit, MSG_BULK_ABORT, NULL, 0, resp0.session, true); - return false; - } - - uint32_t at = 0; - while (at < bulk->len) { - uint32_t chunk = MIN(max_chunk, bulk->len - at); -// 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) { - fprintf(stderr, "Bulk write failed! %.*s\n", resp.len, (char *) resp.payload); - return false; - } - - if (resp.type != MSG_SUCCESS) { - fprintf(stderr, "Bulk write failed! Bad response type.\n"); - return false; - } - } - - // Conclude the transfer - GEX_SendEx(unit, MSG_BULK_END, NULL, 0, resp0.session, true); - - return true; -} diff --git a/gex/gex_unit.h b/gex/gex_unit.h index 7b793b3..02e5c56 100644 --- a/gex/gex_unit.h +++ b/gex/gex_unit.h @@ -54,4 +54,17 @@ uint32_t GEX_BulkRead(GexUnit *unit, GexBulk *bulk); */ bool GEX_BulkWrite(GexUnit *unit, GexBulk *bulk); + +// extended low level stuff + +/** Static query */ +GexMsg GEX_QueryEx(GexUnit *unit, uint8_t cmd, + const uint8_t *payload, uint32_t len, + GexSession session, bool is_reply, + bool raw_pld); + +void GEX_SendEx(GexUnit *unit, uint8_t cmd, + const uint8_t *payload, uint32_t len, + GexSession session, bool is_reply); + #endif //GEX_CLIENT_GEX_UNIT_H diff --git a/main.c b/main.c index 1253d6b..b65e400 100644 --- a/main.c +++ b/main.c @@ -34,7 +34,7 @@ int main(void) // Bind ^C handler for safe shutdown signal(SIGINT, sigintHandler); - gex = GEX_Init("/dev/ttyACM0", 100); + gex = GEX_Init("/dev/ttyACM0", 200); if (!gex) exit(1); TF_AddGenericListener(GEX_GetTF(gex), hdl_default);