cleanup and added sync + async commands

sipo
Ondřej Hruška 7 years ago
parent 5d12b23ceb
commit b3d1f95e7d
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 7
      comm/msg_responses.c
  2. 10
      comm/msg_responses.h
  3. 119
      units/usart/unit_usart.c
  4. 22
      units/usart/unit_usart.h
  5. 8
      utils/payload_builder.h

@ -5,6 +5,7 @@
#include "platform.h" #include "platform.h"
#include "messages.h" #include "messages.h"
#include "msg_responses.h" #include "msg_responses.h"
#include "payload_builder.h"
void com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...) void com_respond_snprintf(TF_ID frame_id, TF_TYPE type, const char *format, ...)
{ {
@ -37,6 +38,12 @@ void com_respond_ok(TF_ID frame_id)
com_respond_buf(frame_id, MSG_SUCCESS, NULL, 0); com_respond_buf(frame_id, MSG_SUCCESS, NULL, 0);
} }
void com_send_pb(TF_TYPE type, PayloadBuilder *pb)
{
uint32_t len;
uint8_t *buf = pb_close(pb, &len);
com_send_buf(type, buf, len);
}
void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len) void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len)
{ {

@ -9,6 +9,8 @@
#error "Include messages.h instead!" #error "Include messages.h instead!"
#endif #endif
#include "payload_builder.h"
/** /**
* Respond to a TF message using printf-like formatting. * Respond to a TF message using printf-like formatting.
* *
@ -54,6 +56,14 @@ void com_respond_error(TF_ID frame_id, error_t error);
*/ */
void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len); void com_send_buf(TF_TYPE type, const uint8_t *buf, uint32_t len);
/**
* Send a payload builder's content
*
* @param type - response type byte
* @param pb - builder
*/
void com_send_pb(TF_TYPE type, PayloadBuilder *pb);
/** /**
* Same like tf_respond_buf(), but the buffer length is measured with strlen. * Same like tf_respond_buf(), but the buffer length is measured with strlen.
* Used to sending ASCII string responses. * Used to sending ASCII string responses.

@ -6,10 +6,36 @@
#include "comm/messages.h" #include "comm/messages.h"
#include "unit_base.h" #include "unit_base.h"
#include "unit_usart.h" #include "unit_usart.h"
#include "tasks/task_msg.h"
#define UUSART_INTERNAL #define UUSART_INTERNAL
#include "_internal.h" #include "_internal.h"
static void UUSART_SendReceivedDataToMaster(Job *job)
{
Unit *unit = job->data1;
struct priv *priv = unit->data;
uint32_t readpos = job->d32;
uint32_t count = job->len;
// Debug: print to debug port
// PUTS("Job rx >");
// PUTSN((char *) priv->rx_buffer + readpos, (uint16_t) count);
// PUTS("<\r\n");
// Debug: Write out
// UU_USART_Write(unit, (const uint8_t *) (priv->rx_buffer + readpos), count);
// TODO modify TF to allow writing in multiple chunks to avoid this useless buffer copying
PayloadBuilder pb = pb_start(unit_tmp512, UNIT_TMP_LEN, NULL);
pb_u8(&pb, unit->callsign);
pb_u8(&pb, 0x00); // report type "Data received"
pb_buf(&pb, (uint8_t *) (priv->rx_buffer + readpos), count);
assert_param(pb.ok);
com_send_pb(MSG_UNIT_REPORT, &pb);
}
/** /**
* Handle received data (we're inside the IRQ) * Handle received data (we're inside the IRQ)
* *
@ -23,55 +49,90 @@ void UUSART_DMA_HandleRxFromIRQ(Unit *unit, uint16_t endpos)
assert_param(priv); assert_param(priv);
uint16_t readpos = priv->rx_buf_readpos; uint16_t readpos = priv->rx_buf_readpos;
assert_param(endpos > readpos); assert_param(endpos > readpos);
uint16_t count = (endpos - readpos); uint16_t count = (endpos - readpos);
uint8_t *start = (uint8_t *) (priv->rx_buffer + readpos);
// Do something with the data... // We defer it to the job queue
PUTSN((char *) start, count); // FIXME this can starve the shared queue if full duplex is used, we need a second higher priority queue for those report jobs
PUTNL(); Job j = {
.data1 = unit,
.d32 = priv->rx_buf_readpos,
.len = count,
.cb = UUSART_SendReceivedDataToMaster
};
scheduleJob(&j);
// Move the read cursor, wrap around if needed // Move the read cursor, wrap around if needed
if (endpos == UUSART_RXBUF_LEN) endpos = 0; if (endpos == UUSART_RXBUF_LEN) endpos = 0;
priv->rx_buf_readpos = endpos; priv->rx_buf_readpos = endpos;
} }
enum PinCmd_ {
CMD_WRITE = 0,
};
/** Handle a request message */ error_t UU_USART_Write(Unit *unit, const uint8_t *buffer, uint32_t len)
static error_t UUSART_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{ {
CHECK_TYPE(unit, &UNIT_USART);
struct priv *priv = unit->data; struct priv *priv = unit->data;
switch (command) { uint32_t t_start = HAL_GetTick();
case CMD_WRITE:; while (len > 0) {
uint32_t len; // this should be long enough even for the slowest bitrates and 512 bytes
const uint8_t *pld = pp_tail(pp, &len); if (HAL_GetTick() - t_start > 5000) {
return E_HW_TIMEOUT;
}
uint16_t chunk = UUSART_DMA_TxQueue(priv, buffer, (uint16_t) len);
uint32_t t_start = HAL_GetTick(); buffer += chunk;
while (len > 0) { len -= chunk;
// this should be long enough even for the slowest bitrates and 512 bytes
if (HAL_GetTick() - t_start > 5000) {
return E_HW_TIMEOUT;
}
uint16_t chunk = UUSART_DMA_TxQueue(priv, pld, (uint16_t) len); // We give up control if there's another thread waiting and this isn't the last cycle
if (len > 0) {
osThreadYield();
}
}
pld += chunk; return E_SUCCESS;
len -= chunk; }
// We give up control if there's another thread waiting and this isn't the last cycle error_t UU_USART_WriteSync(Unit *unit, const uint8_t *buffer, uint32_t len)
if (len > 0) { {
osThreadYield(); CHECK_TYPE(unit, &UNIT_USART);
} struct priv *priv = unit->data;
}
TRY(UU_USART_Write(unit, buffer, len));
// Now wait for the last DMA to complete
uint32_t t_start = HAL_GetTick();
while (priv->tx_dma_busy) {
if (HAL_GetTick() - t_start > 1000) {
return E_HW_TIMEOUT;
}
}
return E_SUCCESS;
}
enum PinCmd_ {
CMD_WRITE = 0,
CMD_WRITE_SYNC = 1,
};
/** Handle a request message */
static error_t UUSART_handleRequest(Unit *unit, TF_ID frame_id, uint8_t command, PayloadParser *pp)
{
uint32_t len;
const uint8_t *pld;
switch (command) {
case CMD_WRITE:
pld = pp_tail(pp, &len);
TRY(UU_USART_Write(unit, pld, len));
return E_SUCCESS;
case CMD_WRITE_SYNC:
pld = pp_tail(pp, &len);
TRY(UU_USART_WriteSync(unit, pld, len));
return E_SUCCESS; return E_SUCCESS;
//return E_NOT_IMPLEMENTED;
default: default:
return E_UNKNOWN_COMMAND; return E_UNKNOWN_COMMAND;

@ -9,4 +9,26 @@
extern const UnitDriver UNIT_USART; extern const UnitDriver UNIT_USART;
/**
* Write bytes. This function is asynchronous and does not wait for completion.
* It blocks until there's space in the Tx buffer for the data.
*
* @param unit
* @param buffer - bytes to send
* @param len - number of bytes to send
* @return success
*/
error_t UU_USART_Write(Unit *unit, const uint8_t *buffer, uint32_t len);
/**
* Write bytes. Same like UU_USART_Write(), except it waits for the transmission
* to complete after sending the last data.
*
* @param unit
* @param buffer - bytes to send
* @param len - number of bytes to send
* @return success
*/
error_t UU_USART_WriteSync(Unit *unit, const uint8_t *buffer, uint32_t len);
#endif //GEX_F072_UNIT_USART_H #endif //GEX_F072_UNIT_USART_H

@ -48,7 +48,7 @@ struct PayloadBuilder_ {
// --- initializer helper macros --- // --- initializer helper macros ---
/** Start the builder. */ /** Start the builder. */
#define pb_start_e(buf, capacity, bigendian, full_handler) ((PayloadBuilder){buf, buf, (buf)+(capacity), full_handler, bigendian, 1}) #define pb_start_e(buf, capacity, bigendian, full_handler) ((PayloadBuilder){(uint8_t*)buf, (uint8_t*)buf, (uint8_t*)((buf)+(capacity)), full_handler, bigendian, 1})
/** Start the builder in big-endian mode */ /** Start the builder in big-endian mode */
#define pb_start_be(buf, capacity, full_handler) pb_start_e(buf, capacity, 1, full_handler) #define pb_start_be(buf, capacity, full_handler) pb_start_e(buf, capacity, 1, full_handler)
@ -67,6 +67,12 @@ struct PayloadBuilder_ {
/** Reset the current pointer to start */ /** Reset the current pointer to start */
#define pb_rewind(pb) do { pb->current = pb->start; } while (0) #define pb_rewind(pb) do { pb->current = pb->start; } while (0)
/** Finalize the buffer composition and get the size */
static inline uint8_t *pb_close(PayloadBuilder *pb, uint32_t *lendst)
{
*lendst = pb_length(pb);
return pb->start;
}
/** Write from a buffer */ /** Write from a buffer */
bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len); bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len);

Loading…
Cancel
Save