summaryrefslogtreecommitdiff
path: root/packages/robostix-utils
diff options
context:
space:
mode:
authorKoen Kooi <koen@openembedded.org>2009-01-10 10:44:13 +0100
committerKoen Kooi <koen@openembedded.org>2009-01-10 10:44:13 +0100
commitd076ad3dbeac4bf7a58a335348c1560dd23799a7 (patch)
treef402fe30741bb8ea76d0f411a1179c6ac937be76 /packages/robostix-utils
parent06af67f2e653d6b0d45117f9aaad0b25db1eaa67 (diff)
gumstix utils: add char-driver, gpio-event, i2c and microwindows
Diffstat (limited to 'packages/robostix-utils')
-rw-r--r--packages/robostix-utils/robostix-cmdline.bb28
-rw-r--r--packages/robostix-utils/robostix-cmdline/robostix.c278
-rw-r--r--packages/robostix-utils/robostix-cmdline/robostix.h114
-rw-r--r--packages/robostix-utils/robostix-sertest.bb28
-rw-r--r--packages/robostix-utils/robostix-sertest/sertest.c443
5 files changed, 891 insertions, 0 deletions
diff --git a/packages/robostix-utils/robostix-cmdline.bb b/packages/robostix-utils/robostix-cmdline.bb
new file mode 100644
index 0000000000..0eecfc2e14
--- /dev/null
+++ b/packages/robostix-utils/robostix-cmdline.bb
@@ -0,0 +1,28 @@
+DESCRIPTION = "robostix programs"
+SECTION = "base"
+PRIORITY = "required"
+PR = "r1"
+
+DEPENDS = robostix-module
+
+SRC_URI = " \
+ file://robostix.h \
+ file://robostix.c \
+ "
+
+CMD_NAME=robostix
+
+S = "${WORKDIR}"
+
+do_compile () {
+ ${CC} -o ${CMD_NAME} *.c
+}
+
+do_install () {
+ install -d ${D}${bindir}/
+ install -m 0755 ${WORKDIR}/${CMD_NAME} ${D}${bindir}/
+}
+
+PACKAGES = "${PN}"
+FILES_${PN} = "${bindir}/*"
+
diff --git a/packages/robostix-utils/robostix-cmdline/robostix.c b/packages/robostix-utils/robostix-cmdline/robostix.c
new file mode 100644
index 0000000000..be47b5c5a9
--- /dev/null
+++ b/packages/robostix-utils/robostix-cmdline/robostix.c
@@ -0,0 +1,278 @@
+/****************************************************************************
+*
+* Copyright (c) 2006 Dave Hylands <dhylands@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* Alternatively, this software may be distributed under the terms of BSD
+* license.
+*
+* See README and COPYING for more details.
+*
+****************************************************************************/
+/**
+*
+* robostix.c
+*
+* PURPOSE:
+*
+* This implements the usermode program for talking to the robostix.
+*
+*****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "robostix.h"
+
+/* ---- Public Variables ------------------------------------------------- */
+
+int gFd = -1;
+
+int gVal;
+
+/* ---- Private Constants and Types -------------------------------------- */
+/* ---- Private Variables ------------------------------------------------ */
+
+typedef struct
+{
+ const char *cmdStr;
+ const char *argStr;
+ const char *helpStr;
+ int (*parseArgs)( int argc, char **argv );
+ void (*execFunc)( int cmd );
+ int cmd;
+
+} Cmd;
+
+int ParseNone( int argc, char **argv );
+int ParseOnOffArg( int argc, char **argv );
+int ParseOnOffPulseArg( int argc, char **argv );
+void Usage( void );
+
+void Power( int cmd );
+void ReadIOctl( int cmd );
+void SimpleIOctl( int cmd );
+
+Cmd gCmd[] =
+{
+ { "power", "on|off", "Controls the robostix voltage regulators", ParseOnOffArg, Power, -1 },
+ { "reset", "on|off|pulse", "Resets the robostix", ParseOnOffPulseArg, SimpleIOctl, ROBOSTIX_IOCTL_RESET },
+ { "245", "on|off", "Controls the 245 buffer chip", ParseOnOffArg, SimpleIOctl, ROBOSTIX_IOCTL_245_ENABLE },
+
+ { "sck", "on|off", "Sets/clears the SCK line", ParseOnOffArg, SimpleIOctl, ROBOSTIX_IOCTL_SET_SCK },
+ { "ss", "on|off", "Sets/clears the SS line", ParseOnOffArg, SimpleIOctl, ROBOSTIX_IOCTL_SET_SS },
+ { "txd", "on|off", "Sets/clears the IR-TXD line", ParseOnOffArg, SimpleIOctl, ROBOSTIX_IOCTL_SET_IR_TXD },
+ { "mosi", "on|off", "Sets/clears the MOSI line", ParseOnOffArg, SimpleIOctl, ROBOSTIX_IOCTL_SET_MOSI },
+
+ { "rxd", "", "Reads the IR-RXD line", ParseNone, ReadIOctl, ROBOSTIX_IOCTL_GET_IR_RXD },
+ { "irq", "", "Reads the TM-IRQ line", ParseNone, ReadIOctl, ROBOSTIX_IOCTL_GET_IRQ },
+ { "miso", "", "Reads the MISO line", ParseNone, ReadIOctl, ROBOSTIX_IOCTL_GET_MISO },
+
+ { NULL }
+};
+
+/* ---- Private Function Prototypes -------------------------------------- */
+/* ---- Functions -------------------------------------------------------- */
+
+
+/****************************************************************************
+*
+* main
+*
+***************************************************************************/
+
+int main( int argc, char **argv )
+{
+ char *cmdStr;
+ int argIdx;
+ Cmd *cmd;
+
+ if ( argc == 1 )
+ {
+ Usage( );
+ exit( 0 );
+ }
+
+ if (( gFd = open( "/dev/robostix", O_RDWR )) < 0 )
+ {
+ perror( "Unable to open /dev/robostix" );
+ exit( 1 );
+ }
+
+ argIdx = 1;
+ cmdStr = argv[ argIdx++ ];
+
+ for ( cmd = gCmd; cmd->cmdStr != NULL; cmd++ )
+ {
+ if ( strcasecmp( cmdStr, cmd->cmdStr ) == 0 )
+ {
+ break;
+ }
+ }
+ if ( cmd->cmdStr == NULL )
+ {
+ fprintf( stderr, "Unrecognized command: '%s'\n", cmdStr );
+ exit( 1 );
+ }
+
+ if ( cmd->parseArgs( argc - argIdx, &argv[ argIdx ] ))
+ {
+ cmd->execFunc( cmd->cmd );
+ }
+
+ close( gFd );
+
+ exit( 0 );
+ return 0;
+
+} // main
+
+/****************************************************************************
+*
+* Checks to see if the argument is on/off (or equivalent)
+*
+***************************************************************************/
+
+int IsOnOffArg( int argc, char **argv )
+{
+ if (( strcasecmp( *argv, "on" ) == 0 )
+ || ( strcasecmp( *argv, "t" ) == 0 )
+ || ( strcasecmp( *argv, "1" ) == 0 ))
+ {
+ gVal = 1;
+ return 1;
+ }
+
+ if (( strcasecmp( *argv, "off" ) == 0 )
+ || ( strcasecmp( *argv, "f" ) == 0 )
+ || ( strcasecmp( *argv, "0" ) == 0 ))
+ {
+ gVal = 0;
+ return 1;
+ }
+
+ return 0;
+
+} // IsOnOffArg
+
+/****************************************************************************
+*
+* Parses no arguments
+*
+***************************************************************************/
+
+int ParseNone( int argc, char **argv )
+{
+ return 1;
+
+} // ParseNone
+
+/****************************************************************************
+*
+* Parses a command line argument for legel on/off values
+*
+***************************************************************************/
+
+int ParseOnOffArg( int argc, char **argv )
+{
+ if ( IsOnOffArg( argc, argv ))
+ {
+ return 1;
+ }
+
+ fprintf( stderr, "Expecting on/off, found: '%s'\n", *argv );
+ return 0;
+
+} // ParseOnOffArg
+
+/****************************************************************************
+*
+* Parses a command line argument for legel on/off values
+*
+***************************************************************************/
+
+int ParseOnOffPulseArg( int argc, char **argv )
+{
+ if (( strcasecmp( *argv, "pulse" ) == 0 )
+ || ( strcasecmp( *argv, "2" ) == 0 ))
+ {
+ gVal = 2;
+ return 1;
+ }
+
+ if ( IsOnOffArg( argc, argv ))
+ {
+ return 1;
+ }
+
+ fprintf( stderr, "Expecting on/off/pulse, found: '%s'\n", *argv );
+ return 0;
+
+} // ParseOnoffPulseArg
+
+/****************************************************************************
+*
+* Power
+*
+***************************************************************************/
+
+void Power( int cmd )
+{
+ SimpleIOctl( ROBOSTIX_IOCTL_POWER_VCC5 );
+
+} // Power
+
+/****************************************************************************
+*
+* SimpleIOctl
+*
+***************************************************************************/
+
+void SimpleIOctl( int cmd )
+{
+ if ( ioctl( gFd, cmd, gVal ) != 0 )
+ {
+ fprintf( stderr, "ioctl call failed: %d\n", errno );
+ }
+
+} // SimpleIOctl
+
+/****************************************************************************
+*
+* SimpleIOctl
+*
+***************************************************************************/
+
+void ReadIOctl( int cmd )
+{
+ if ( ioctl( gFd, cmd, &gVal ) != 0 )
+ {
+ fprintf( stderr, "ioctl call failed: %d\n", errno );
+ }
+
+} // ReadIOctl
+
+/****************************************************************************
+*
+* Usage
+*
+***************************************************************************/
+
+void Usage( void )
+{
+ Cmd *cmd;
+
+ for ( cmd = gCmd; cmd->cmdStr != NULL; cmd++ )
+ {
+ printf( "%-12s %-12s %s\n", cmd->cmdStr, cmd->argStr, cmd->helpStr );
+ }
+
+} // Usage
+
diff --git a/packages/robostix-utils/robostix-cmdline/robostix.h b/packages/robostix-utils/robostix-cmdline/robostix.h
new file mode 100644
index 0000000000..0d860bc7a4
--- /dev/null
+++ b/packages/robostix-utils/robostix-cmdline/robostix.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+*
+* Copyright (c) 2006 Dave Hylands <dhylands@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* Alternatively, this software may be distributed under the terms of BSD
+* license.
+*
+* See README and COPYING for more details.
+*
+****************************************************************************/
+/**
+*
+* robostix_drv.h
+*
+* PURPOSE:
+*
+* This implements a driver for using the robostix from the gumstix
+*
+* Initially, this contains the required support to emulate enough of the
+* parallel port interface to allow avrdude to program the ATMega128.
+*
+*****************************************************************************/
+
+#if !defined( LINUX_ROBOSTIX_H )
+#define LINUX_ROBOSTIX_H )
+
+/* ---- Include Files ----------------------------------------------------- */
+
+#include <linux/ioctl.h>
+
+/* ---- Constants and Types ----------------------------------------------- */
+
+#define ROBOSTIX_MAJOR 240
+
+#define ROBOSTIX_IOCTL_MAGIC 'R'
+
+/**
+ * Deefines for each of the commands. Note that since we want to reduce
+ * the possibility that a user mode program gets out of sync with a given
+ * driver, we explicitly assign a value to each enumeration. This makes
+ * it more difficult to stick new ioctl's in the middle of the list.
+ */
+
+typedef enum
+{
+ ROBOSTIX_CMD_FIRST = 0x80,
+
+ ROBOSTIX_CMD_POWER_VCC5 = 0x80,
+ ROBOSTIX_CMD_RESET = 0x81,
+ ROBOSTIX_CMD_245_ENABLE = 0x82,
+ ROBOSTIX_CMD_SET_SCK = 0x83,
+ ROBOSTIX_CMD_SET_SS = 0x84,
+ ROBOSTIX_CMD_SET_IR_TXD = 0x85,
+ ROBOSTIX_CMD_GET_IR_RXD = 0x86,
+ ROBOSTIX_CMD_SET_MOSI = 0x87,
+ ROBOSTIX_CMD_GET_MISO = 0x88,
+ ROBOSTIX_CMD_GET_IRQ = 0x89,
+ ROBOSTIX_CMD_DELAY_USEC = 0x8A, // value is hardocded in uisp DAPA.C
+
+ /* Insert new ioctls here */
+
+ ROBOSTIX_CMD_LAST,
+
+} ROBOSTIX_CMD;
+
+/*
+ * The following are arguments to the various ioctl's
+ */
+
+#define ROBOSTIX_PIN_OFF 0
+#define ROBOSTIX_PIN_ON 1
+#define ROBOSTIX_PIN_PULSE 2 // only used or Reset
+
+/*
+ * Definitions for the actual ioctl commands
+ */
+
+#define ROBOSTIX_IOCTL_POWER_VCC5 _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_POWER_VCC5 ) // arg is int
+#define ROBOSTIX_IOCTL_RESET _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_RESET ) // arg is int
+#define ROBOSTIX_IOCTL_245_ENABLE _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_245_ENABLE ) // arg is int
+#define ROBOSTIX_IOCTL_SET_SCK _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_SET_SCK ) // arg is int
+#define ROBOSTIX_IOCTL_SET_SS _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_SET_SS ) // arg is int
+#define ROBOSTIX_IOCTL_SET_IR_TXD _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_SET_IR_TXD ) // arg is int
+#define ROBOSTIX_IOCTL_GET_IR_RXD _IOR( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_GET_IR_RXD, int ) // arg is int *
+#define ROBOSTIX_IOCTL_SET_MOSI _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_SET_MOSI ) // arg is int
+#define ROBOSTIX_IOCTL_GET_MISO _IOR( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_GET_MISO, int ) // arg is int *
+#define ROBOSTIX_IOCTL_GET_IRQ _IOR( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_GET_IRQ, int ) // arg is int *
+#define ROBOSTIX_IOCTL_DELAY_USEC _IO( ROBOSTIX_IOCTL_MAGIC, ROBOSTIX_CMD_DELAY_USEC ) // arg is int
+
+
+/*
+ * Definitions for sysctl. The top level define has to be unique system wide.
+ * The kernel defines values 1 thru about 10 (see include/linunx/sysctl.h)
+ */
+
+#define CTL_ROBOSTIX 0x526F626F /* 'Robo' in hex form */
+
+/*
+ * The following are for entries in /proc/sys/robostix
+ */
+
+enum
+{
+ CTL_ROBOSTIX_DEBUG_TRACE = 101,
+ CTL_ROBOSTIX_DEBUG_IOCTL = 102,
+ CTL_ROBOSTIX_DEBUG_ERROR = 103
+};
+
+#endif // LINUX_ROBOSTIX_H
+
diff --git a/packages/robostix-utils/robostix-sertest.bb b/packages/robostix-utils/robostix-sertest.bb
new file mode 100644
index 0000000000..0196f6c8f3
--- /dev/null
+++ b/packages/robostix-utils/robostix-sertest.bb
@@ -0,0 +1,28 @@
+DESCRIPTION = "robostix programs"
+SECTION = "base"
+PRIORITY = "required"
+PR = "r1"
+
+DEPENDS = robostix-module
+
+SRC_URI = " \
+ file://sertest.c \
+ "
+
+CMD_NAME=sertest
+LDLIBS = -lpthread
+
+S = "${WORKDIR}"
+
+do_compile () {
+ ${CC} ${LDLIBS} -o ${CMD_NAME} *.c
+}
+
+do_install () {
+ install -d ${D}${bindir}/
+ install -m 0755 ${WORKDIR}/${CMD_NAME} ${D}${bindir}/
+}
+
+PACKAGES = "${PN}"
+FILES_${PN} = "${bindir}/*"
+
diff --git a/packages/robostix-utils/robostix-sertest/sertest.c b/packages/robostix-utils/robostix-sertest/sertest.c
new file mode 100644
index 0000000000..3f0cf7a6fc
--- /dev/null
+++ b/packages/robostix-utils/robostix-sertest/sertest.c
@@ -0,0 +1,443 @@
+/****************************************************************************
+*
+* Copyright (c) 2006 Dave Hylands <dhylands@gmail.com>
+*
+* This program is free software; you can redistribute it and/or modify
+* it under the terms of the GNU General Public License version 2 as
+* published by the Free Software Foundation.
+*
+* Alternatively, this software may be distributed under the terms of BSD
+* license.
+*
+* See README and COPYING for more details.
+*
+****************************************************************************/
+/**
+*
+* sertest.c
+*
+* PURPOSE:
+*
+* This implements a sample program for accessing the serial port.
+*
+*****************************************************************************/
+
+/* ---- Include Files ---------------------------------------------------- */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <sys/unistd.h>
+#include <pthread.h>
+#include <getopt.h>
+#include <termios.h>
+
+/* ---- Public Variables ------------------------------------------------- */
+
+int gFd = -1;
+
+int gVal;
+
+/* ---- Private Constants and Types -------------------------------------- */
+/* ---- Private Variables ------------------------------------------------ */
+
+struct option gLongOption[] =
+{
+ // option A Flag V (has_arg, flag, val)
+ // ----------- - ---- ---
+ { "baud", 1, NULL, 'b' },
+ { "debug", 0, NULL, 'd' },
+ { "help", 0, NULL, 'h' },
+ { "port", 1, NULL, 'p' },
+ { "verbose", 0, NULL, 'v' },
+ { 0 },
+
+};
+
+struct
+{
+ speed_t speed;
+ unsigned baudRate;
+} gBaudTable[] =
+{
+ { B50, 50 },
+ { B75, 75 },
+ { B110, 110 },
+ { B134, 134 },
+ { B150, 150 },
+ { B200, 200 },
+ { B300, 300 },
+ { B600, 600 },
+ { B1200, 1200 },
+ { B1800, 1800 },
+ { B2400, 2400 },
+ { B4800, 4800 },
+ { B9600, 9600 },
+ { B19200, 19200 },
+ { B38400, 38400 },
+ { B57600, 57600 },
+ { B115200, 115200 },
+ { B230400, 230400 }
+};
+
+#define ARRAY_LEN(x) ( sizeof( x ) / sizeof( x[ 0 ]))
+
+int gVerbose = 0;
+int gDebug = 0;
+
+int gPortFd = -1;
+
+/* ---- Private Function Prototypes -------------------------------------- */
+
+void *ReaderThread( void *param );
+char *StrMaxCpy( char *dst, const char *src, size_t maxLen );
+char *StrMaxCat( char *dst, const char *src, size_t maxLen );
+void Usage( void );
+
+/* ---- Functions -------------------------------------------------------- */
+
+
+/***************************************************************************
+*
+* main
+*
+****************************************************************************/
+
+int main( int argc, char **argv )
+{
+ int rc;
+ int opt;
+ char devName[ 40 ];
+ const char *baudStr = NULL;
+ const char *portStr = "ttyS2";
+ speed_t baudRate;
+ pthread_t readerThreadId;
+
+ struct termios attr;
+
+ // Parse the command line options
+
+ while (( opt = getopt_long( argc, argv, "b:dhp:v", gLongOption, NULL )) > 0 )
+ {
+ switch ( opt )
+ {
+ case 'b':
+ {
+ baudStr = optarg;
+ break;
+ }
+
+ case 'd':
+ {
+ gDebug = 1;
+ break;
+ }
+
+ case 'p':
+ {
+ portStr = optarg;
+ break;
+ }
+
+ case 'v':
+ {
+ gVerbose = 1;
+ break;
+ }
+ case '?':
+ case 'h':
+ {
+ Usage();
+ return 1;
+ }
+ }
+ }
+
+ devName[ 0 ] = '\0';
+ if ( portStr[ 0 ] != '/' )
+ {
+ StrMaxCpy( devName, "/dev/", sizeof( devName ));
+ }
+ StrMaxCat( devName, portStr, sizeof( devName ));
+
+
+ baudRate = B0;
+ if ( baudStr == NULL )
+ {
+ baudRate = B9600;
+ }
+ else
+ {
+ int baudIdx;
+ int testBaud = atoi( baudStr );
+
+ for ( baudIdx = 0; baudIdx < ARRAY_LEN( gBaudTable ); baudIdx++ )
+ {
+ if ( gBaudTable[ baudIdx ].baudRate == testBaud )
+ {
+ baudRate = gBaudTable[ baudIdx ].speed;
+ break;
+ }
+ }
+
+ if ( baudRate == B0 )
+ {
+ fprintf( stderr, "Unrecognized baud rate: '%s'\n", baudStr );
+ exit( 1 );
+ }
+ }
+
+ if (( gPortFd = open( devName, O_RDWR | O_EXCL )) < 0 )
+ {
+ fprintf( stderr, "Unable to open serial port '%s': %s\n", devName, strerror( errno ));
+ exit( 2 );
+ }
+
+ if ( tcgetattr( gPortFd, &attr ) < 0 )
+ {
+ fprintf( stderr, "Call to tcgetattr failed: %s\n", strerror( errno ));
+ exit( 3 );
+ }
+
+ attr.c_iflag = 0;
+ attr.c_oflag = 0;
+ attr.c_cflag = CLOCAL | CREAD | CS8;
+ attr.c_lflag = 0;
+ attr.c_cc[ VTIME ] = 0; // timeout in tenths of a second
+ attr.c_cc[ VMIN ] = 1; // Only wait for a single char
+
+ cfsetispeed( &attr, baudRate );
+ cfsetospeed( &attr, baudRate );
+
+ if ( tcsetattr( gPortFd, TCSAFLUSH, &attr ) < 0 )
+ {
+ fprintf( stderr, "Call to tcsetattr failed: %s\n", strerror( errno ));
+ exit( 4 );
+ }
+
+ // Put stdin & stdout in unbuffered mode.
+
+ setbuf( stdin, NULL );
+ setbuf( stdout, NULL );
+
+ // Put stdin in raw mode (i.e. turn off canonical mode). Canonical mode
+ // causes the driver to wait for the RETURN character so that line editing
+ // can take place. We also want to turn off ECHO.
+
+ {
+ struct termios tio;
+
+ if ( tcgetattr( fileno( stdin ), &tio ) < 0 )
+ {
+ fprintf( stderr, "Unable to retrieve terminal settings: %s\n", strerror( errno ));
+ exit( 5 );
+ }
+
+ tio.c_lflag &= ~( ICANON | ECHO );
+ tio.c_cc[VTIME] = 0;
+ tio.c_cc[VMIN] = 1;
+
+ if ( tcsetattr( fileno( stdin ), TCSANOW, &tio ) < 0 )
+ {
+ fprintf( stderr, "Unable to update terminal settings: %s\n", strerror( errno ));
+ exit( 6 );
+ }
+ }
+
+ // Kick off the serial port reader thread.
+
+ rc = pthread_create( &readerThreadId, NULL, ReaderThread, NULL );
+ if ( rc != 0 )
+ {
+ fprintf( stderr, "Error creating ReaderThread: %s\n", strerror( rc ));
+ exit( 7 );
+ }
+
+ // Read stdin and send rcvd chars to the serial port
+
+ while ( 1 )
+ {
+ char ch;
+ int chInt = fgetc( stdin );
+ if ( chInt < 0 )
+ {
+ fprintf( stderr, "Exiting...\n" );
+ break;
+ }
+ ch = (char)chInt;
+
+ if ( gDebug )
+ {
+ if (( ch < ' ' ) || ( ch > '~' ))
+ {
+ fprintf( stderr, "stdin Read: 0x%02x '.'\n", ch );
+ }
+ else
+ {
+ fprintf( stderr, "stdin Read: 0x%02x '%c'\n", ch, ch );
+ }
+
+ }
+
+ if ( write( gPortFd, &ch, 1 ) != 1 )
+ {
+ fprintf( stderr, "write to serial port failed: %s\n", strerror( errno ));
+ break;
+ }
+ }
+
+
+ close( gPortFd );
+
+ exit( 0 );
+ return 0; // Get rid of warning about not returning anything
+}
+
+/***************************************************************************/
+/**
+* Thread which processes the incoming serial data.
+*/
+
+void *ReaderThread( void *param )
+{
+ while ( 1 )
+ {
+ char ch;
+ int bytesRead;
+
+ if (( bytesRead = read( gPortFd, &ch, 1 )) < 0 )
+ {
+ fprintf( stderr, "Serial port read failed: %s\n", strerror( errno ));
+ exit( 1 );
+ }
+
+ if ( gDebug )
+ {
+ if (( ch < ' ' ) || ( ch > '~' ))
+ {
+ fprintf( stderr, "Serial Read: 0x%02x '.'\n", ch );
+ }
+ else
+ {
+ fprintf( stderr, "Serial Read: 0x%02x '%c'\n", ch, ch );
+ }
+
+ }
+
+ putc( ch, stdout );
+ }
+
+ return 0;
+
+} // ReaderThread
+
+/***************************************************************************/
+/**
+* Concatenates source to the destination, but makes sure that the
+* destination string (including terminating null), doesn't exceed maxLen.
+*
+* @param dst (mod) String to concatnate onto.
+* @param src (in) String to being added to the end of @a dst.
+* @param maxLen (in) Maximum length that @a dst is allowed to be.
+*
+* @return A pointer to the destination string.
+*/
+
+char *StrMaxCat( char *dst, const char *src, size_t maxLen )
+{
+ size_t dstLen = strlen( dst );
+
+ if ( dstLen < maxLen )
+ {
+ StrMaxCpy( &dst[ dstLen ], src, maxLen - dstLen );
+ }
+
+ return dst;
+
+} /* StrMaxCat */
+
+/***************************************************************************/
+/**
+* Copies the source to the destination, but makes sure that the
+* destination string (including terminating null), doesn't exceed
+* maxLen.
+*
+* @param dst (out) Place to store the string copy.
+* @param src (in) String to copy.
+* @param maxLen (in) Maximum number of characters to copy into @a dst.
+*
+* @return A pointer to the destination string.
+*/
+
+char *StrMaxCpy( char *dst, const char *src, size_t maxLen )
+{
+ if ( maxLen < 1 )
+ {
+ /*
+ * There's no room in the buffer?
+ */
+
+ return "";
+ }
+
+ if ( maxLen == 1 )
+ {
+ /*
+ * There's only room for the terminating null character
+ */
+
+ dst[ 0 ] = '\0';
+ return dst;
+ }
+
+ /*
+ * The Visual C++ version of strncpy writes to every single character
+ * of the destination buffer, so we use a length one character smaller
+ * and write in our own null (if required).
+ *
+ * This allows the caller to store a sentinel in the last byte of the
+ * buffer to detect overflows (if desired).
+ */
+
+ strncpy( dst, src, maxLen - 1 );
+ if (( strlen( src ) + 1 ) >= maxLen )
+ {
+ /*
+ * The string exactly fits, or probably overflows the buffer.
+ * Write in the terminating null character since strncpy doesn't in
+ * this particular case.
+ *
+ * We don't do this arbitrarily so that the caller can use a sentinel
+ * in the very end of the buffer to detect buffer overflows.
+ */
+
+ dst[ maxLen - 1 ] = '\0';
+ }
+
+ return dst;
+
+} /* StrMaxCpy */
+
+/***************************************************************************
+*
+* Usage
+*
+****************************************************************************/
+
+void Usage()
+{
+ fprintf( stderr, "Usage: sertest [option(s)]\n" );
+ fprintf( stderr, " Download a program via serial/i2c\n" );
+ fprintf( stderr, "\n" );
+ fprintf( stderr, " -b, --baud=baud Set the baudrate used\n" );
+ fprintf( stderr, " -d, --debug Turn on debug output\n" );
+ fprintf( stderr, " -h, --help Display this message\n" );
+ fprintf( stderr, " -p, --port=port Set the I/O port\n" );
+ fprintf( stderr, " -v, --verbose Turn on verbose messages\n" );
+
+} // Usage
+
+