joeylib2/examples/sertest/sertest.c
2026-09-29 21:25:37 -05:00

99 lines
2.9 KiB
C

// Minimal headless serial self-test -- NO jlInit (no video/graphics), so it
// runs even where the graphics HAL can't (e.g. AROS on the Amiga). Opens the
// DEFAULT port at 9600 8N1, sends a banner (TX heartbeat), then echoes every
// received byte forever. A host serial peer verifies banner (TX) + echo (RX).
//
// A peer that sees the modem lines (DOSBox's nullmodem reports them in the
// byte stream as they change) can also send DTR_CHECK: the program then
// drops and raises DTR, closes and reopens the port, drops DTR and closes
// the port for good, with a marker line after each step, so the peer can
// check that jlSerialSetDtr reaches the line and that jlSerialClose leaves
// DTR as it is, up or down. After the check the port stays closed.
#include <joey/serial.h>
#define DTR_CHECK 0x04u // ASCII EOT: run the DTR check (not echoed)
#define DTR_ACK 0x06u // ASCII ACK: the peer has the whole marker line
static void dtrCheck(const jlSerialConfigT *cfg);
static void sendMark(const char *text);
static void dtrCheck(const jlSerialConfigT *cfg) {
jlSerialSetDtr(false);
sendMark("JLDTR-OFF\r\n");
jlSerialSetDtr(true);
sendMark("JLDTR-ON\r\n");
jlSerialClose();
if (!jlSerialOpen(JL_SERIAL_DEFAULT, cfg)) {
return;
}
sendMark("JLDTR-REOPENED\r\n");
jlSerialSetDtr(false);
sendMark("JLDTR-HANGUP\r\n");
jlSerialClose();
}
// A marker line, then the peer's DTR_ACK: the line has gone out whole, so
// the next line change comes after it (a changed line is reported at once,
// while bytes wait their turn in the UART), and a close cannot throw any of
// it away.
static void sendMark(const char *text) {
uint16_t len;
uint16_t sent;
uint8_t byte;
len = 0u;
while (text[len] != '\0') {
len++;
}
sent = 0u;
while (sent < len) {
jlSerialPoll();
sent = (uint16_t)(sent + jlSerialWrite((const uint8_t *)&text[sent], (uint16_t)(len - sent)));
}
for (;;) {
jlSerialPoll();
if (jlSerialRead(&byte, 1u) == 1u && byte == DTR_ACK) {
return;
}
}
}
int main(void) {
jlSerialConfigT cfg;
static const char banner[] = "JLSERTEST-READY\r\n";
cfg.baud = 9600u;
cfg.dataBits = 8u;
cfg.stopBits = 1u;
cfg.parity = JL_SERIAL_PARITY_NONE;
cfg.flow = JL_SERIAL_FLOW_NONE;
cfg.unit = 0u;
if (!jlSerialOpen(JL_SERIAL_DEFAULT, &cfg)) {
return 1;
}
jlSerialWrite((const uint8_t *)banner, (uint16_t)(sizeof(banner) - 1u));
for (;;) {
uint8_t buf[64];
uint16_t n;
uint16_t i;
jlSerialPoll();
n = jlSerialRead(buf, (uint16_t)sizeof(buf));
for (i = 0u; i < n; i++) {
if (buf[i] == DTR_CHECK) {
break;
}
}
if (i > 0u) {
jlSerialWrite(buf, i);
}
if (i < n) {
dtrCheck(&cfg);
}
}
// not reached
}