Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 34 additions & 18 deletions target/min.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
#define TRANSPORT_FIFO_SIZE_FRAME_DATA_MASK ((uint16_t)((1U << TRANSPORT_FIFO_SIZE_FRAME_DATA_BITS) - 1U))

// Number of bytes needed for a frame with a given payload length, excluding stuff bytes
// 3 header bytes, ID/control byte, length byte, seq byte, 4 byte CRC, EOF byte
#define ON_WIRE_SIZE(p) ((p) + 11U)
// 3 header bytes, ID/control byte, 1 or 2 length bytes, seq byte, 4 byte CRC, EOF byte
#define ON_WIRE_SIZE(p) ((p) + 4U + sizeof(pl_len_t) + 6U)

// Special protocol bytes
enum {
Expand All @@ -23,7 +23,8 @@ enum {
SEARCHING_FOR_SOF,
RECEIVING_ID_CONTROL,
RECEIVING_SEQ,
RECEIVING_LENGTH,
RECEIVING_LENGTH_MSB,
RECEIVING_LENGTH_LSB,
RECEIVING_PAYLOAD,
RECEIVING_CHECKSUM_3,
RECEIVING_CHECKSUM_2,
Expand Down Expand Up @@ -101,9 +102,9 @@ static void stuffed_tx_byte(struct min_context *self, uint8_t byte, bool crc)
}
}

static void on_wire_bytes(struct min_context *self, uint8_t id_control, uint8_t seq, uint8_t const *payload_base, uint16_t payload_offset, uint16_t payload_mask, uint8_t payload_len)
static void on_wire_bytes(struct min_context *self, uint8_t id_control, uint8_t seq, uint8_t const *payload_base, uint16_t payload_offset, uint16_t payload_mask, pl_len_t payload_len)
{
uint8_t n, i;
pl_len_t n, i;
uint32_t checksum;

self->tx_header_byte_countdown = 2U;
Expand All @@ -122,7 +123,10 @@ static void on_wire_bytes(struct min_context *self, uint8_t id_control, uint8_t
stuffed_tx_byte(self, seq, true);
}

stuffed_tx_byte(self, payload_len, true);
#if (MAX_PAYLOAD > UINT8_MAX)
stuffed_tx_byte(self, payload_len >> 8, true);
#endif
stuffed_tx_byte(self, payload_len & 0xFF, true);

for(i = 0, n = payload_len; n > 0; n--, i++) {
stuffed_tx_byte(self, payload_base[payload_offset], true);
Expand Down Expand Up @@ -276,7 +280,7 @@ void min_transport_reset(struct min_context *self, bool inform_other_side)
// Queues a MIN ID / payload frame into the outgoing FIFO
// API call.
// Returns true if the frame was queued OK.
bool min_queue_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, uint8_t payload_len)
bool min_queue_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, pl_len_t payload_len)
{
struct transport_frame *frame = transport_fifo_push(self, payload_len); // Claim a FIFO slot, reserve space for payload

Expand All @@ -301,7 +305,7 @@ bool min_queue_frame(struct min_context *self, uint8_t min_id, uint8_t const *pa
}
}

bool min_queue_has_space_for_frame(struct min_context *self, uint8_t payload_len) {
bool min_queue_has_space_for_frame(struct min_context *self, pl_len_t payload_len) {
return self->transport_fifo.n_frames < TRANSPORT_FIFO_MAX_FRAMES &&
self->transport_fifo.n_ring_buffer_bytes <= TRANSPORT_FIFO_MAX_FRAME_DATA - payload_len;
}
Expand Down Expand Up @@ -339,12 +343,12 @@ static struct transport_frame *find_retransmit_frame(struct min_context *self)
// duplicates received, and handling RESET requests.
static void valid_frame_received(struct min_context *self)
{
uint8_t id_control = self->rx_frame_id_control;
uint8_t *payload = self->rx_frame_payload_buf;
uint8_t payload_len = self->rx_control;
const uint8_t id_control = self->rx_frame_id_control;
const uint8_t * const payload = self->rx_frame_payload_buf;
const pl_len_t payload_len = self->rx_length;

#ifdef TRANSPORT_PROTOCOL
uint8_t seq = self->rx_frame_seq;
const uint8_t seq = self->rx_frame_seq;
uint8_t num_acked;
uint8_t num_nacked;
uint8_t num_in_window;
Expand Down Expand Up @@ -493,17 +497,29 @@ static void rx_byte(struct min_context *self, uint8_t byte)
}
else {
self->rx_frame_seq = 0;
self->rx_frame_state = RECEIVING_LENGTH;
self->rx_frame_state = RECEIVING_LENGTH_MSB;
}
break;
case RECEIVING_SEQ:
self->rx_frame_seq = byte;
crc32_step(&self->rx_checksum, byte);
self->rx_frame_state = RECEIVING_LENGTH;
self->rx_frame_state = RECEIVING_LENGTH_MSB;
break;
case RECEIVING_LENGTH_MSB:
#if (MAX_PAYLOAD > UINT8_MAX)
self->rx_frame_length = ((uint16_t)byte) << 8;
crc32_step(&self->rx_checksum, byte);
self->rx_frame_state = RECEIVING_LENGTH_LSB;
break;
case RECEIVING_LENGTH:
self->rx_frame_length = byte;
self->rx_control = byte;
#else
// MSB == LSB if value is 8-bit
self->rx_frame_length = 0;
self->rx_frame_state = RECEIVING_LENGTH_LSB;
#endif
// FALLTHRU
case RECEIVING_LENGTH_LSB:
self->rx_frame_length |= byte;
self->rx_length = self->rx_frame_length;
crc32_step(&self->rx_checksum, byte);
if(self->rx_frame_length > 0) {
// Can reduce the RAM size by compiling limits to frame sizes
Expand Down Expand Up @@ -657,7 +673,7 @@ void min_init_context(struct min_context *self, uint8_t port)
}

// Sends an application MIN frame on the wire (do not put into the transport queue)
void min_send_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, uint8_t payload_len)
void min_send_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, pl_len_t payload_len)
{
if((ON_WIRE_SIZE(payload_len) <= min_tx_space(self->port))) {
on_wire_bytes(self, min_id & (uint8_t) 0x3fU, 0, payload, 0, 0xffffU, payload_len);
Expand Down
26 changes: 16 additions & 10 deletions target/min.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@
#define TRANSPORT_FIFO_MAX_FRAMES (1U << TRANSPORT_FIFO_SIZE_FRAMES_BITS)
#define TRANSPORT_FIFO_MAX_FRAME_DATA (1U << TRANSPORT_FIFO_SIZE_FRAME_DATA_BITS)

#if (MAX_PAYLOAD > 255)
#error "MIN frame payloads can be no bigger than 255 bytes"
#if (MAX_PAYLOAD > 0x7FFF)
#error "MIN frame payloads can be no bigger than 32767 (0x7FFF) bytes"
#endif

// Indices into the frames FIFO are uint8_t and so can't have more than 256 frames in a FIFO
Expand All @@ -100,6 +100,12 @@
#error "Transport FIFO data allocated cannot exceed 64Kbytes"
#endif

#if (MAX_PAYLOAD > UINT8_MAX)
typedef uint16_t pl_len_t;
#else
typedef uint8_t pl_len_t;
#endif

struct crc32_context {
uint32_t crc;
};
Expand All @@ -109,7 +115,7 @@ struct crc32_context {
struct transport_frame {
uint32_t last_sent_time_ms; // When frame was last sent (used for re-send timeouts)
uint16_t payload_offset; // Where in the ring buffer the payload is
uint8_t payload_len; // How big the payload is
pl_len_t payload_len; // How big the payload is
uint8_t min_id; // ID of frame
uint8_t seq; // Sequence number of frame
};
Expand Down Expand Up @@ -146,25 +152,25 @@ struct min_context {
struct crc32_context tx_checksum; // Calculated checksum for sending frame
uint8_t rx_header_bytes_seen; // Countdown of header bytes to reset state
uint8_t rx_frame_state; // State of receiver
uint8_t rx_frame_payload_bytes; // Length of payload received so far
pl_len_t rx_frame_payload_bytes; // Length of payload received so far
uint8_t rx_frame_id_control; // ID and control bit of frame being received
uint8_t rx_frame_seq; // Sequence number of frame being received
uint8_t rx_frame_length; // Length of frame
uint8_t rx_control; // Control byte
pl_len_t rx_frame_length; // Remaining length of frame to be received
pl_len_t rx_length; // Original received length of the payload
uint8_t tx_header_byte_countdown; // Count out the header bytes
uint8_t port; // Number of the port associated with the context
};

#ifdef TRANSPORT_PROTOCOL
// Queue a MIN frame in the transport queue
bool min_queue_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, uint8_t payload_len);
bool min_queue_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, pl_len_t payload_len);

// Determine if MIN has space to queue a transport frame
bool min_queue_has_space_for_frame(struct min_context *self, uint8_t payload_len);
bool min_queue_has_space_for_frame(struct min_context *self, pl_len_t payload_len);
#endif

// Send a non-transport frame MIN frame
void min_send_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, uint8_t payload_len);
void min_send_frame(struct min_context *self, uint8_t min_id, uint8_t const *payload, pl_len_t payload_len);

// Must be regularly called, with the received bytes since the last call.
// NB: if the transport protocol is being used then even if there are no bytes
Expand All @@ -175,7 +181,7 @@ void min_poll(struct min_context *self, uint8_t const *buf, uint32_t buf_len);
void min_transport_reset(struct min_context *self, bool inform_other_side);

// CALLBACK. Handle incoming MIN frame
void min_application_handler(uint8_t min_id, uint8_t const *min_payload, uint8_t len_payload, uint8_t port);
void min_application_handler(uint8_t min_id, uint8_t const *min_payload, pl_len_t len_payload, uint8_t port);

#ifdef TRANSPORT_PROTOCOL
// CALLBACK. Must return current time in milliseconds.
Expand Down