Draft: libtest: Add packet processor
Summary
libtest: Add packet processor
The RTEMS Test Framework packet processor provides a simple mechanism to exchange reliable and in-order data through transmitting and receiving one character at a time.
The packet processor does not buffer data. The processor uses a stop-and-wait automatic repeat request method. There is at most one packet in transmission. The data transfer is done using a single character input and output method. The protocol uses 12-bit sequence numbers, so a host could use a sliding window method to increase throughput. All integers and data are base64url encoded. A 24-bit CRC is used to ensure the data integrity. The {
character starts a packet. The }
character terminates a packet. The #
character prefixes a 24-bit CRC value. The :
character separates fields. The +
character prefixes data fields. The following packets are defined:
- hello:
{<12-bit seq><12-bit ack>:H#<24-bit CRC>}
- acknowledge:
{<12-bit seq><12-bit ack>:A#<24-bit CRC>}
- reject:
{<12-bit seq><12-bit ack>:R :<12-bit seq of rejected packet> #<24-bit CRC>}
- signal:
{<12-bit seq><12-bit ack>:S :<64-bit signal number> :<64-bit signal value> <optional list of colon separated 64-bit values> #<24-bit CRC>}
- channel:
{<12-bit seq><12-bit ack>:C :<64-bit channel number> :<64-bit channel data size> <optional list of colon separated 64-bit values> #<24-bit CRC> + #<24-bit CRC>}
The intended use case are boot loaders and test runners. For example, test runners may interface with an external test server performing equipment handling on request using the packet processor.
Use T_packet_initialize()
to initialize the packet processor. Use T_packet_process()
to drive the packet processing. You can enqueue packets for transmission with T_packet_enqueue()
. You can reliably send signals with T_packet_send()
. You can reliably, in-order transmit and receive channel data with T_packet_channel_push()
and T_packet_channel_exchange()
.
A simple boot loader for test runs could be implemented like this:
#include <bsp.h>
#include <rtems/bspIo.h>
#include <rtems/counter.h>
#include <rtems/test-packet.h>
typedef struct {
T_packet_event_control base;
uint8_t *load_address;
} boot_control;
static void output_char(T_packet_control* self, uint8_t ch) {
(void)self;
rtems_putc(ch);
}
static T_packet_status event_handler(T_packet_control* self,
T_packet_event_control* base,
T_packet_event evt) {
boot_control* evt_ctrl = (boot_control*)base;
switch (evt) {
case T_PACKET_EVENT_SIGNAL:
if (T_packet_get_signal_number(self) == 0) {
T_packet_output_acknowledge(self);
bsp_restart(T_packet_get_signal_value_as_address(self));
}
break;
case T_PACKET_EVENT_HELLO:
T_packet_output_acknowledge(self);
break;
case T_PACKET_EVENT_CHANNEL_BEGIN:
if (T_packet_get_channel_number(self) == 0) {
void *address;
if (T_packet_get_extra_count(self) >= 1) {
address = T_packet_get_extra_as_address(self, 0);
evt_ctrl->load_address = address;
} else {
address = evt_ctrl->load_address;
}
T_packet_set_channel_target(self, address);
}
break;
case T_PACKET_EVENT_CHANNEL_END:
if (T_packet_get_channel_number(self) == 0) {
evt_ctrl->load_address += T_packet_get_channel_size(self);
T_packet_output_acknowledge(self);
}
break;
case T_PACKET_EVENT_OUTPUT_END:
rtems_putc('\n');
break;
default:
break;
}
return T_PACKET_SUCCESSFUL;
}
static uint32_t clock_monotonic(T_packet_control* self) {
(void)self;
return rtems_counter_read();
}