commit
45910e7f04
@ -0,0 +1,98 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
|
||||||
|
#include <TinyFrame.h> |
||||||
|
|
||||||
|
#include "messages.h" |
||||||
|
#include "utils/payload_parser.h" |
||||||
|
#include "utils/payload_builder.h" |
||||||
|
|
||||||
|
/** Buffer for preparing bulk chunks */ |
||||||
|
static uint8_t bulkread_buffer[BULKREAD_MAX_CHUNK]; |
||||||
|
|
||||||
|
/**
|
||||||
|
* TF listener for the bulk read transaction |
||||||
|
*/ |
||||||
|
static TF_Result bulkread_lst(TinyFrame *tf, TF_Msg *msg) |
||||||
|
{ |
||||||
|
struct bulk_read *bulk = msg->userdata; |
||||||
|
|
||||||
|
// this is a final call before timeout, to clean up
|
||||||
|
if (msg->data == NULL) { |
||||||
|
goto close; |
||||||
|
} |
||||||
|
|
||||||
|
assert_param(NULL != bulk); |
||||||
|
|
||||||
|
if (msg->type == MSG_BULK_ABORT) { |
||||||
|
goto close; |
||||||
|
} |
||||||
|
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); |
||||||
|
|
||||||
|
chunk = MIN(chunk, bulk->len - bulk->offset); |
||||||
|
chunk = MIN(chunk, BULKREAD_MAX_CHUNK); |
||||||
|
|
||||||
|
// load data into the buffer
|
||||||
|
bulk->read(bulk, chunk, bulkread_buffer); |
||||||
|
|
||||||
|
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; |
||||||
|
} |
||||||
|
|
||||||
|
return TF_RENEW; |
||||||
|
|
||||||
|
close: |
||||||
|
if (bulk) { |
||||||
|
// Ask user to free the bulk and userdata
|
||||||
|
bulk->read(bulk, 0, NULL); |
||||||
|
msg->userdata = NULL; |
||||||
|
} |
||||||
|
return TF_CLOSE; |
||||||
|
} |
||||||
|
|
||||||
|
/** Start the bulk read flow */ |
||||||
|
void bulkread_start(TinyFrame *tf, struct bulk_read *bulk) |
||||||
|
{ |
||||||
|
assert_param(bulk); |
||||||
|
assert_param(bulk->len); |
||||||
|
assert_param(bulk->read); |
||||||
|
|
||||||
|
bulk->offset = 0; |
||||||
|
|
||||||
|
{ |
||||||
|
uint8_t buf[8]; |
||||||
|
PayloadBuilder pb = pb_start(buf, 4, NULL); |
||||||
|
pb_u32(&pb, bulk->len); |
||||||
|
pb_u32(&pb, BULKREAD_MAX_CHUNK); |
||||||
|
|
||||||
|
// We use userdata1 to hold a reference to the bulk transfer
|
||||||
|
TF_Msg msg = { |
||||||
|
.type = MSG_BULK_READ_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, bulkread_lst, BULK_LST_TIMEOUT_MS); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_MSG_BULKREAD_H |
||||||
|
#define GEX_F072_MSG_BULKREAD_H |
||||||
|
|
||||||
|
#ifndef GEX_MESSAGES_H |
||||||
|
#error "Include messages.h instead!" |
||||||
|
#endif |
||||||
|
|
||||||
|
#include <TinyFrame.h> |
||||||
|
|
||||||
|
typedef struct bulk_read BulkRead; |
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the bulk-read 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 bulkread_start() function. |
||||||
|
* @param chunk - size of the chunk to read |
||||||
|
* @param buffer - destination buffer to fill with the data. NULL if bulk should be freed. |
||||||
|
*/ |
||||||
|
typedef void (*bulkread_data_cb)(BulkRead *bulk, uint32_t chunk, uint8_t *buffer); |
||||||
|
|
||||||
|
/** Bulk read structure */ |
||||||
|
struct bulk_read { |
||||||
|
TF_ID frame_id; //!< ID of the requesting frame, used for the entire bulk read session
|
||||||
|
bulkread_data_cb read; //!< Read 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 read session |
||||||
|
* @param tf - tinyframe instance |
||||||
|
* @param bulk - bulk read config structure (malloc'd or static) |
||||||
|
*/ |
||||||
|
void bulkread_start(TinyFrame *tf, struct bulk_read *bulk); |
||||||
|
|
||||||
|
|
||||||
|
#endif //GEX_F072_MSG_BULKREAD_H
|
@ -0,0 +1,89 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
|
||||||
|
#include <TinyFrame.h> |
||||||
|
|
||||||
|
#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) { |
||||||
|
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, 8, 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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/23.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_MSG_BULKWRITE_H |
||||||
|
#define GEX_F072_MSG_BULKWRITE_H |
||||||
|
|
||||||
|
#include <TinyFrame.h> |
||||||
|
|
||||||
|
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
|
@ -0,0 +1,98 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "messages.h" |
||||||
|
#include "msg_responses.h" |
||||||
|
|
||||||
|
void com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...) |
||||||
|
{ |
||||||
|
#define ERR_STR_LEN 64 |
||||||
|
|
||||||
|
char buf[ERR_STR_LEN]; |
||||||
|
va_list args; |
||||||
|
va_start(args, format); |
||||||
|
uint32_t len = (uint32_t) fixup_vsnprintf(&buf[0], ERR_STR_LEN, format, args); |
||||||
|
va_end(args); |
||||||
|
|
||||||
|
com_respond_buf(frame_id, type, (const uint8_t *) buf, len); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t len) |
||||||
|
{ |
||||||
|
TF_Msg msg; |
||||||
|
TF_ClearMsg(&msg); |
||||||
|
{ |
||||||
|
msg.type = type; |
||||||
|
msg.frame_id = frame_id; |
||||||
|
msg.data = buf; |
||||||
|
msg.len = (TF_LEN) len; |
||||||
|
} |
||||||
|
TF_Respond(comm, &msg); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_ok(TF_ID frame_id) |
||||||
|
{ |
||||||
|
com_respond_buf(frame_id, MSG_SUCCESS, NULL, 0); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) |
||||||
|
{ |
||||||
|
TF_Msg msg; |
||||||
|
TF_ClearMsg(&msg); |
||||||
|
{ |
||||||
|
msg.type = MSG_UNIT_REPORT; |
||||||
|
msg.data = buf; |
||||||
|
msg.len = (TF_LEN) len; |
||||||
|
msg.type = type; |
||||||
|
} |
||||||
|
TF_Send(comm, &msg); // no listener
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_str(TF_TYPE type, TF_ID frame_id, const char *str) |
||||||
|
{ |
||||||
|
com_respond_buf(frame_id, type, (const uint8_t *) str, (uint32_t) strlen(str)); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void com_respond_err(TF_ID frame_id, const char *message) |
||||||
|
{ |
||||||
|
com_respond_str(MSG_ERROR, frame_id, message); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_bad_cmd(TF_ID frame_id) |
||||||
|
{ |
||||||
|
com_respond_err(frame_id, "BAD COMMAND"); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_malformed_cmd(TF_ID frame_id) |
||||||
|
{ |
||||||
|
com_respond_err(frame_id, "MALFORMED PAYLOAD"); |
||||||
|
} |
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void com_respond_u8(TF_ID frame_id, uint8_t d) |
||||||
|
{ |
||||||
|
com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) &d, 1); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_u16(TF_ID frame_id, uint16_t d) |
||||||
|
{ |
||||||
|
com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) &d, 2); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void com_respond_u32(TF_ID frame_id, uint32_t d) |
||||||
|
{ |
||||||
|
com_respond_buf(frame_id, MSG_SUCCESS, (const uint8_t *) &d, 4); |
||||||
|
} |
@ -0,0 +1,114 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_MSG_RESPONSES_H |
||||||
|
#define GEX_F072_MSG_RESPONSES_H |
||||||
|
|
||||||
|
#ifndef GEX_MESSAGES_H |
||||||
|
#error "Include messages.h instead!" |
||||||
|
#endif |
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to a TF message using printf-like formatting. |
||||||
|
* Works synchronously, must be called on a job queue. |
||||||
|
* |
||||||
|
* @param type - response type byte |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param format - printf format |
||||||
|
* @param ... - replacements |
||||||
|
*/ |
||||||
|
void __attribute__((format(printf,3,4))) |
||||||
|
com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to a TF message with a buffer of fixed length and custom type. |
||||||
|
* Works synchronously, must be called on a job queue. |
||||||
|
* |
||||||
|
* @param type - response type byte |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param buf - byte buffer |
||||||
|
* @param len - buffer size |
||||||
|
*/ |
||||||
|
void com_respond_buf(TF_ID frame_id, TF_TYPE type, const uint8_t *buf, uint32_t len); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Respond to a TF message with empty body and MSG_SUCCESS type. |
||||||
|
* Works synchronously, must be called on a job queue. |
||||||
|
* |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
*/ |
||||||
|
void com_respond_ok(TF_ID frame_id); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Same like tf_respond_buf(), but used for sending spontaneous reports. |
||||||
|
* Works synchronously, must be called on a job queue / timer task etc. |
||||||
|
* |
||||||
|
* @param type - response type byte |
||||||
|
* @param buf - byte buffer |
||||||
|
* @param len - buffer size |
||||||
|
*/ |
||||||
|
void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Same like tf_respond_buf(), but the buffer length is measured with strlen. |
||||||
|
* Used to sending ASCII string responses. |
||||||
|
* Works synchronously, must be called on a job queue. |
||||||
|
* |
||||||
|
* @param type - response type byte |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param str - character buffer, zero terminated |
||||||
|
*/ |
||||||
|
void com_respond_str(TF_TYPE type, TF_ID frame_id, const char *str); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule sending an ASCII string error response. |
||||||
|
* Schedules a low priority job. |
||||||
|
* |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param str - character buffer, zero terminated |
||||||
|
*/ |
||||||
|
void com_respond_err(TF_ID frame_id, const char *str); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of sched_respond_err() for reporting bad received command code |
||||||
|
* |
||||||
|
* @param msg_id - ID of the original msg |
||||||
|
*/ |
||||||
|
void com_respond_bad_cmd(TF_ID frame_id); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Variant of sched_respond_err() for reporting malformed commands (e.g. too short payload) |
||||||
|
* |
||||||
|
* @param msg_id - ID of the original msg |
||||||
|
*/ |
||||||
|
void com_respond_malformed_cmd(TF_ID frame_id); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule sending a one-byte response with MSG_SUCCESS type. |
||||||
|
* Schedules a high priority job. |
||||||
|
* |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param d - data |
||||||
|
*/ |
||||||
|
void com_respond_u8(TF_ID frame_id, uint8_t d); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule sending a two-byte response with MSG_SUCCESS type. |
||||||
|
* Schedules a high priority job. |
||||||
|
* |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param d - data |
||||||
|
*/ |
||||||
|
void com_respond_u16(TF_ID frame_id, uint16_t d); |
||||||
|
|
||||||
|
/**
|
||||||
|
* Schedule sending a 4-byte response with MSG_SUCCESS type. |
||||||
|
* Schedules a high priority job. |
||||||
|
* |
||||||
|
* @param frame_id - ID of the original msg |
||||||
|
* @param d - data |
||||||
|
*/ |
||||||
|
void com_respond_u32(TF_ID frame_id, uint32_t d); |
||||||
|
|
||||||
|
#endif //GEX_F072_MSG_RESPONSES_H
|
@ -0,0 +1,31 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "platform.h" |
||||||
|
#include "comm/messages.h" |
||||||
|
#include "utils/hexdump.h" |
||||||
|
#include "task_msg.h" |
||||||
|
#include "sched_queue.h" |
||||||
|
|
||||||
|
/**
|
||||||
|
* Process data received from TinyFrame. |
||||||
|
* The queue holds received messages or parts of messages, |
||||||
|
* copied there by the USB thread. |
||||||
|
* |
||||||
|
* Since this is a separate thread that handles TF input and runs the listeners, |
||||||
|
* TF functions (send, respond) can be called immediately without the need for an |
||||||
|
* intermediate queued job. |
||||||
|
*/ |
||||||
|
void TaskMessaging(const void * argument) |
||||||
|
{ |
||||||
|
dbg("> Message queue task started!"); |
||||||
|
|
||||||
|
struct rx_que_item slot; |
||||||
|
while (1) { |
||||||
|
xQueueReceive(queRxDataHandle, &slot, osWaitForever); |
||||||
|
assert_param(slot.len>0 && slot.len<=64); // check the len is within bounds
|
||||||
|
|
||||||
|
TF_Accept(comm, slot.data, slot.len); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/12/22.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef GEX_F072_TASK_MSG_H |
||||||
|
#define GEX_F072_TASK_MSG_H |
||||||
|
|
||||||
|
extern osMessageQId queRxDataHandle; |
||||||
|
extern osThreadId tskMsgHandle; |
||||||
|
void TaskMessaging(const void * argument); |
||||||
|
|
||||||
|
#endif //GEX_F072_TASK_MSG_H
|
@ -0,0 +1,190 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/11/25.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "comm/messages.h" |
||||||
|
#include "unit_base.h" |
||||||
|
#include "unit_test.h" |
||||||
|
|
||||||
|
/** Private data structure */ |
||||||
|
struct priv { |
||||||
|
uint32_t unused; |
||||||
|
}; |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Load from a binary buffer stored in Flash */ |
||||||
|
static void Tst_loadBinary(Unit *unit, PayloadParser *pp) |
||||||
|
{ |
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
//
|
||||||
|
} |
||||||
|
|
||||||
|
/** Write to a binary buffer for storing in Flash */ |
||||||
|
static void Tst_writeBinary(Unit *unit, PayloadBuilder *pb) |
||||||
|
{ |
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
//
|
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Parse a key-value pair from the INI file */ |
||||||
|
static bool Tst_loadIni(Unit *unit, const char *key, const char *value) |
||||||
|
{ |
||||||
|
bool suc = true; |
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
return suc; |
||||||
|
} |
||||||
|
|
||||||
|
/** Generate INI file section for the unit */ |
||||||
|
static void Tst_writeIni(Unit *unit, IniWriter *iw) |
||||||
|
{ |
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
//
|
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Allocate data structure and set defaults */ |
||||||
|
static bool Tst_preInit(Unit *unit) |
||||||
|
{ |
||||||
|
bool suc = true; |
||||||
|
struct priv *priv = unit->data = calloc_ck(1, sizeof(struct priv), &suc); |
||||||
|
CHECK_SUC(); |
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** Finalize unit set-up */ |
||||||
|
static bool Tst_init(Unit *unit) |
||||||
|
{ |
||||||
|
bool suc = true; |
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
/** Tear down the unit */ |
||||||
|
static void Tst_deInit(Unit *unit) |
||||||
|
{ |
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
|
// Free memory
|
||||||
|
free(unit->data); |
||||||
|
unit->data = NULL; |
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
enum PinCmd_ { |
||||||
|
CMD_PING = 0, |
||||||
|
CMD_ECHO = 1, |
||||||
|
CMD_BULKREAD = 2, |
||||||
|
CMD_BULKWRITE = 3, |
||||||
|
}; |
||||||
|
|
||||||
|
static const char *longtext = "The history of all hitherto existing societies is the history of class struggles.\n\nFreeman and slave, patrician and plebeian, lord and serf, guild-master and journeyman, in a word, oppressor and oppressed, stood in constant opposition to one another, carried on an uninterrupted, now hidden, now open fight, a fight that each time ended, either in a revolutionary re-constitution of society at large, or in the common ruin of the contending classes.\n\nIn the earlier epochs of history, we find almost everywhere a complicated arrangement of society into various orders, a manifold gradation of social rank. In ancient Rome we have patricians, knights, plebeians, slaves; in the Middle Ages, feudal lords, vassals, guild-masters, journeymen, apprentices, serfs; in almost all of these classes, again, subordinate gradations.\n\nThe modern bourgeois society that has sprouted from the ruins of feudal society has not done away with class antagonisms. It has but established new classes, new conditions of oppression, new forms of struggle in place of the old ones. Our epoch, the epoch of the bourgeoisie, possesses, however, this distinctive feature: it has simplified the class antagonisms. Society as a whole is more and more splitting up into two great hostile camps, into two great classes, directly facing each other: Bourgeoisie and Proletariat.\n\nFrom the serfs of the Middle Ages sprang the chartered burghers of the earliest towns. From these burgesses the first elements of the bourgeoisie were developed.\n\nThe discovery of America, the rounding of the Cape, opened up fresh ground for the rising bourgeoisie. The East-Indian and Chinese markets, the colonisation of America, trade with the colonies, the increase in the means of exchange and in commodities generally, gave to commerce, to navigation, to industry, an impulse never before known, and thereby, to the revolutionary element in the tottering feudal society, a rapid development.\n\nThe feudal system of industry, under which industrial production was monopolised by closed guilds, now no longer sufficed for the growing wants of the new markets. The manufacturing system took its place. The guild-masters were pushed on one side by the manufacturing middle class; division of labour between the different corporate guilds vanished in the face of division of labour in each single workshop.\n\nMeantime the markets kept ever growing, the demand ever rising. Even manufacture no longer sufficed. Thereupon, steam and machinery revolutionised industrial production. The place of manufacture was taken by the giant, Modern Industry, the place of the industrial middle class, by industrial millionaires, the leaders of whole industrial armies, the modern bourgeois.\n\nModern industry has established the world-market, for which the discovery of America paved the way. This market has given an immense development to commerce, to navigation, to communication by land. This development has, in its time, reacted on the extension of industry; and in proportion as industry, commerce, navigation, railways extended, in the same proportion the bourgeoisie developed, increased its capital, and pushed into the background every class handed down from the Middle Ages.\n\nWe see, therefore, how the modern bourgeoisie is itself the product of a long course of development, of a series of revolutions in the modes of production and of exchange.\n\nEach step in the development of the bourgeoisie was accompanied by a corresponding political advance of that class. An oppressed class under the sway of the feudal nobility, an armed and self-governing association in the mediaeval commune; here independent urban republic (as in Italy and Germany), there taxable \"third estate\" of the monarchy (as in France), afterwards, in the period of manufacture proper, serving either the semi-feudal or the absolute monarchy as a counterpoise against the nobility, and, in fact, corner-stone of the great monarchies in general, the bourgeoisie has at last, since the establishment of Modern Industry and of the world-market, conquered for itself, in the modern representative State, exclusive political sway. The executive of the modern State is but a committee for managing the common affairs of the whole bourgeoisie."; |
||||||
|
|
||||||
|
static void br_longtext(struct bulk_read *bulk, uint32_t chunk, uint8_t *buffer) |
||||||
|
{ |
||||||
|
// clean-up request
|
||||||
|
if (buffer == NULL) { |
||||||
|
free(bulk); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
memcpy(buffer, longtext+bulk->offset, chunk); |
||||||
|
} |
||||||
|
|
||||||
|
static void bw_dump(struct bulk_write *bulk, const uint8_t *chunk, uint32_t len) |
||||||
|
{ |
||||||
|
// clean-up request
|
||||||
|
if (chunk == NULL) { |
||||||
|
free(bulk); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
dbg("\r\nBulk write at %d, len %d", (int)bulk->offset, (int)len); |
||||||
|
PUTSN((const char *) chunk, len); |
||||||
|
PUTS("\r\n"); |
||||||
|
} |
||||||
|
|
||||||
|
/** Handle a request message */ |
||||||
|
static bool Tst_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp) |
||||||
|
{ |
||||||
|
(void)pp; |
||||||
|
|
||||||
|
struct priv *priv = unit->data; |
||||||
|
|
||||||
|
switch (command) { |
||||||
|
case CMD_PING: |
||||||
|
com_respond_ok(frame_id); |
||||||
|
break; |
||||||
|
|
||||||
|
case CMD_ECHO:; |
||||||
|
uint32_t len; |
||||||
|
const uint8_t *data = pp_tail(pp, &len); |
||||||
|
com_respond_buf(frame_id, MSG_SUCCESS, data, len); |
||||||
|
break; |
||||||
|
|
||||||
|
case CMD_BULKREAD:; |
||||||
|
struct bulk_read *br = malloc(sizeof(struct bulk_read)); |
||||||
|
assert_param(br); |
||||||
|
|
||||||
|
br->len = (uint32_t) strlen(longtext); |
||||||
|
br->frame_id = frame_id; |
||||||
|
br->read = br_longtext; |
||||||
|
|
||||||
|
bulkread_start(comm, br); |
||||||
|
break; |
||||||
|
|
||||||
|
case CMD_BULKWRITE:; |
||||||
|
struct bulk_write *bw = malloc(sizeof(struct bulk_write)); |
||||||
|
assert_param(bw); |
||||||
|
|
||||||
|
bw->len = 1024; |
||||||
|
bw->frame_id = frame_id; |
||||||
|
bw->write = bw_dump; |
||||||
|
|
||||||
|
bulkwrite_start(comm, bw); |
||||||
|
break; |
||||||
|
|
||||||
|
default: |
||||||
|
com_respond_bad_cmd(frame_id); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** Unit template */ |
||||||
|
const UnitDriver UNIT_TEST = { |
||||||
|
.name = "TEST", |
||||||
|
.description = "Test unit", |
||||||
|
// Settings
|
||||||
|
.preInit = Tst_preInit, |
||||||
|
.cfgLoadBinary = Tst_loadBinary, |
||||||
|
.cfgWriteBinary = Tst_writeBinary, |
||||||
|
.cfgLoadIni = Tst_loadIni, |
||||||
|
.cfgWriteIni = Tst_writeIni, |
||||||
|
// Init
|
||||||
|
.init = Tst_init, |
||||||
|
.deInit = Tst_deInit, |
||||||
|
// Function
|
||||||
|
.handleRequest = Tst_handleRequest, |
||||||
|
}; |
@ -0,0 +1,13 @@ |
|||||||
|
//
|
||||||
|
// Created by MightyPork on 2017/11/25.
|
||||||
|
// Testing unit that uses most of the protocol to verify the core functionality
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef U_TEST_H |
||||||
|
#define U_TEST_H |
||||||
|
|
||||||
|
#include "unit.h" |
||||||
|
|
||||||
|
extern const UnitDriver UNIT_TEST; |
||||||
|
|
||||||
|
#endif //U_TEST_H
|
Loading…
Reference in new issue