--- /dev/null
+#
+
+TARGETS= hostside
+CFLAGS= -Wall -Werror -Wstrict-prototypes -Wmissing-prototypes \
+ -Wpointer-arith -Wwrite-strings $(OPTIMISE)
+OPTIMISE= -O2
+
+all: $(TARGETS)
+
+hostside: serialio.o nmra.o main.o
+ $(CC) $(CFLAGS) -o $@ $+
+
+%.c: hostside.h
+
+clean:
+ rm -f *.o $(TARGETS)
--- /dev/null
+/**/
+
+#ifndef HOSTSIDE_H
+#define HOSTSIDE_H
+
+typedef unsigned char Byte;
+
+#define COMMAND_ENCODED_MAX 16
+#define NMRA_PACKET_MAX ((COMMAND_ENCODED_MAX*7 - 14) / 8)
+
+void nmra_transmit(const Byte *nmra_packet, int length);
+
+void sysfatal(const char *m);
+void serial_open(const char *device);
+void command_transmit(const Byte *command, int length);
+
+#endif /*HOSTSIDE_H*/
--- /dev/null
+/**/
+
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+
+#include "hostside.h"
+
+int main(int argc, const char **argv) {
+ int l, i;
+ char hbuf[3], *ep;
+ Byte nmra[NMRA_PACKET_MAX];
+
+ assert(argc==3);
+ serial_open(argv[1]);
+
+ l= strlen(argv[2]);
+ assert(!(l&1));
+ l >>= 1;
+ assert(l<=NMRA_PACKET_MAX);
+
+ for (i=0; i<l; i++) {
+ hbuf[0]= argv[2][i*2];
+ hbuf[1]= argv[2][i*2+1];
+ hbuf[2]= 0;
+ nmra[l]= strtoul(hbuf,&ep,16);
+ assert(ep==&hbuf[2]);
+ }
+
+ nmra_transmit(nmra,l);
+
+ return 0;
+}
--- /dev/null
+/**/
+
+#include <assert.h>
+
+#include "hostside.h"
+
+void nmra_transmit(const Byte *nmra_packet, int length) {
+ Byte encoded[COMMAND_ENCODED_MAX], *encp;
+ unsigned working;
+ int working_bits;
+
+ assert(length <= NMRA_PACKET_MAX);
+ encp= encoded;
+ working= 0xfffc; /* 16-bit temp register. Top working_bits bits */
+ working_bits= 14; /* are some data bits to encode, rest are clear. */
+ for (;;) {
+ assert(working_bits >= 0);
+ if (working_bits < 7) {
+ if (length > 0) {
+ /* plonk new data bits just to right of old data bits */
+ working |= (*nmra_packet++ << (8-working_bits));
+ length--;
+ working_bits += 8;
+ } else if (!working_bits) {
+ /* all done */
+ break;
+ } else {
+ /* pad with exactly enough 1 bits to make up the encoded byte */
+ working |= 0xffU << (8-working_bits);
+ working_bits= 7;
+ }
+ }
+ assert(encp < encoded + COMMAND_ENCODED_MAX);
+ *encp++= (working_bits >> 8) & 0xfe; /* top 7 bits, shifted left one */
+ working_bits -= 7;
+ }
+ assert(encp > encoded);
+ encp[-1] |= 0x01; /* `end of command' bit */
+
+ command_transmit(encoded, encp - encoded);
+}
--- /dev/null
+/**/
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "hostside.h"
+
+static int serial_fd= -1;
+
+void sysfatal(const char *m) { perror(m); exit(12); }
+
+void serial_open(const char *device) {
+ assert(serial_fd==-1);
+
+ serial_fd= open(device,O_RDWR);
+ if (serial_fd<0) sysfatal(device);
+}
+
+void command_transmit(const Byte *command, int length) {
+ int r;
+ assert(length <= COMMAND_ENCODED_MAX);
+
+ while (length > 0) {
+ r= write(serial_fd, command, length);
+ if (r==-1) {
+ if (errno == EINTR) continue;
+ sysfatal("command_transmit");
+ }
+ assert(r<=length);
+ command += r;
+ length -= r;
+ }
+}