From 2f5e30b8a4889a48327c5e6649d6f0b6bb43cce5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sat, 23 Dec 2017 22:38:21 +0100 Subject: [PATCH] bulk write implemented but not yet tested. bulk read improved --- .../Class/CDC/Src/usbd_cdc.c | 9 +- comm/messages.h | 4 + comm/msg_bulkread.c | 36 ++++---- comm/msg_bulkread.h | 5 -- comm/msg_bulkwrite.c | 90 +++++++++++++++++++ comm/msg_bulkwrite.h | 41 +++++++++ 6 files changed, 158 insertions(+), 27 deletions(-) create mode 100644 comm/msg_bulkwrite.c create mode 100644 comm/msg_bulkwrite.h diff --git a/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c b/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c index 58ff55d..56f4f98 100644 --- a/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c +++ b/USB/STM32_USB_Device_Library/Class/CDC/Src/usbd_cdc.c @@ -646,9 +646,12 @@ uint8_t USBD_CDC_DataIn (USBD_HandleTypeDef *pdev, uint8_t epnum) if(pdev->pClassData2 != NULL) { - - hcdc->TxState = 0; - USBD_CDC_TransmitDone(pdev); + if (epnum == CDC_IN_EP) { + hcdc->TxState = 0; + USBD_CDC_TransmitDone(pdev); + } else if (epnum == CDC_CMD_EP) { + // command EP send done + } return USBD_OK; } diff --git a/comm/messages.h b/comm/messages.h index 802e52c..a4373d8 100644 --- a/comm/messages.h +++ b/comm/messages.h @@ -9,6 +9,9 @@ #include "task_sched.h" #include "TinyFrame.h" +#define BULK_LST_TIMEOUT_MS 200 +#define BULKREAD_MAX_CHUNK 512 // this is a static buffer + /** * Supported message types (TF_TYPE) */ @@ -38,6 +41,7 @@ extern TinyFrame *comm; // Must be after the enum because it's used in the header file. #include "msg_responses.h" #include "msg_bulkread.h" +#include "msg_bulkwrite.h" /** * Initialize TinyFrame and set up listeners diff --git a/comm/msg_bulkread.c b/comm/msg_bulkread.c index 24fbc47..3866870 100644 --- a/comm/msg_bulkread.c +++ b/comm/msg_bulkread.c @@ -30,40 +30,38 @@ static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) if (msg->type == MSG_BULK_ABORT) { goto close; - } else if (msg->type == MSG_BULK_READ_POLL) { + } + else if (msg->type == MSG_BULK_READ_POLL) { + // find how much data the reader wants PayloadParser pp = pp_start(msg->data, msg->len, NULL); uint32_t chunk = pp_u32(&pp); - // if past len, say we're done and close - if (bulk->offset >= bulk->len) { - TF_ClearMsg(msg); - msg->frame_id = bulk->frame_id; - msg->type = MSG_BULK_END; - TF_Respond(tf, msg); - goto close; - } - chunk = MIN(chunk, bulk->len - bulk->offset); chunk = MIN(chunk, BULKREAD_MAX_CHUNK); + // load data into the buffer bulk->read(bulk, chunk, bulkread_buffer); - TF_ClearMsg(msg); - msg->frame_id = bulk->frame_id; - msg->type = MSG_BULK_DATA; - msg->data = bulkread_buffer; - msg->len = (TF_LEN) chunk; - TF_Respond(tf, msg); + bool last = (bulk->offset + chunk >= bulk->len); + + TF_Msg resp; + TF_ClearMsg(&resp); + resp.frame_id = bulk->frame_id; + resp.type = (last ? MSG_BULK_END : MSG_BULK_DATA); // the last chunk has the END type + resp.data = bulkread_buffer; + resp.len = (TF_LEN) chunk; + TF_Respond(tf, &resp); + + if (last) goto close; // advance the position pointer bulk->offset += chunk; } - msg->userdata = bulk; // We must put it back return TF_RENEW; - close: - if (msg->userdata) { +close: + if (bulk) { // Ask user to free the bulk and userdata bulk->read(bulk, 0, NULL); msg->userdata = NULL; diff --git a/comm/msg_bulkread.h b/comm/msg_bulkread.h index 5226d6c..abe49fb 100644 --- a/comm/msg_bulkread.h +++ b/comm/msg_bulkread.h @@ -11,11 +11,6 @@ #include - -#define BULK_LST_TIMEOUT_MS 200 - -#define BULKREAD_MAX_CHUNK 512 // this is a static buffer - typedef struct bulk_read BulkRead; /** diff --git a/comm/msg_bulkwrite.c b/comm/msg_bulkwrite.c new file mode 100644 index 0000000..77b2677 --- /dev/null +++ b/comm/msg_bulkwrite.c @@ -0,0 +1,90 @@ +// +// Created by MightyPork on 2017/12/23. +// + +#include "platform.h" + +#include + +#include "messages.h" +#include "utils/payload_parser.h" +#include "utils/payload_builder.h" + +/** + * TF listener for the bulk write transaction + */ +static TF_Result bulkwrite_lst(TinyFrame *tf, TF_Msg *msg) +{ + struct bulk_write *bulk = msg->userdata; + + // this is a final call before timeout, to clean up + if (msg->data == NULL) { + dbg("Bulk rx lst cleanup\r\n"); + goto close; + } + + assert_param(NULL != bulk); + + if (msg->type == MSG_BULK_ABORT) { + goto close; + } + else if (msg->type == MSG_BULK_DATA || msg->type == MSG_BULK_END) { + // if past len, say we're done and close + if (bulk->offset >= bulk->len) { + com_respond_err(bulk->frame_id, "WRITE OVERRUN"); + goto close; + } + + bulk->write(bulk, msg->data, msg->len); + + // Return SUCCESS + com_respond_ok(msg->frame_id); + + // advance the position pointer (can be used by the write callback) + bulk->offset += msg->len; + + if (msg->type == MSG_BULK_END) { + // this was the last chunk + goto close; + } + } + + return TF_RENEW; + +close: + if (bulk) { + // Ask user to free the bulk and userdata + bulk->write(bulk, NULL, 0); + msg->userdata = NULL; + } + return TF_CLOSE; +} + +/** Start the bulk write flow */ +void bulkwrite_start(TinyFrame *tf, struct bulk_write *bulk) +{ + assert_param(bulk); + assert_param(bulk->len); + assert_param(bulk->write); + + bulk->offset = 0; + + { + uint8_t buf[8]; + PayloadBuilder pb = pb_start(buf, 4, NULL); + pb_u32(&pb, bulk->len); + pb_u32(&pb, TF_MAX_PAYLOAD_RX); + + // We use userdata1 to hold a reference to the bulk transfer + TF_Msg msg = { + .type = MSG_BULK_WRITE_OFFER, + .frame_id = bulk->frame_id, + .is_response = true, // this ensures the frame_id is not re-generated + .data = buf, + .len = (TF_LEN) pb_length(&pb), + .userdata = bulk, + }; + + TF_Query(tf, &msg, bulkwrite_lst, BULK_LST_TIMEOUT_MS); + } +} diff --git a/comm/msg_bulkwrite.h b/comm/msg_bulkwrite.h new file mode 100644 index 0000000..4391dab --- /dev/null +++ b/comm/msg_bulkwrite.h @@ -0,0 +1,41 @@ +// +// Created by MightyPork on 2017/12/23. +// + +#ifndef GEX_F072_MSG_BULKWRITE_H +#define GEX_F072_MSG_BULKWRITE_H + +#include + +typedef struct bulk_write BulkWrite; + +/** + * Type of the bulk-write listener. Offset within the data can be retrieved from bulk->offset. + * + * If buffer is NULL, this is the last call and the bulk struct must be freed if it was allocated. + * + * @param bulk - a data object passed to the bulkwrite_start() function. + * @param chunk - destination buffer to fill with the data. NULL if bulk should be freed. + * @param len - size of the chunk to write + */ +typedef void (*bulkwrite_data_cb)(BulkWrite *bulk, const uint8_t *chunk, uint32_t len); + +/** Bulk read structure */ +struct bulk_write { + TF_ID frame_id; //!< ID of the requesting frame, used for the entire bulk read session + bulkwrite_data_cb write; //!< Write callback + uint32_t len; //!< Total data length + void *userdata; //!< A place for arbitrary userdata + + uint32_t offset; //!< Internal offset counter, will be set to 0 on start. +}; + +/** + * Start a bulk write session + * @param tf - tinyframe instance + * @param bulk - bulk write config structure (malloc'd or static) + */ +void bulkwrite_start(TinyFrame *tf, struct bulk_write *bulk); + + +#endif //GEX_F072_MSG_BULKWRITE_H