int6kuart.c
Author: cmaier@cmassoc.net

    /*====================================================================*
     *
     *   Copyright (c) 2013 Qualcomm Atheros, Inc.
     *
     *   All rights reserved.
     *
     *   Redistribution and use in source and binary forms, with or
     *   without modification, are permitted (subject to the limitations
     *   in the disclaimer below) provided that the following conditions
     *   are met:
     *
     *   * Redistributions of source code must retain the above copyright
     *     notice, this list of conditions and the following disclaimer.
     *
     *   * Redistributions in binary form must reproduce the above
     *     copyright notice, this list of conditions and the following
     *     disclaimer in the documentation and/or other materials
     *     provided with the distribution.
     *
     *   * Neither the name of Qualcomm Atheros nor the names of
     *     its contributors may be used to endorse or promote products
     *     derived from this software without specific prior written
     *     permission.
     *
     *   NO EXPRESS OR IMPLIED LICENSES TO ANY PARTY'S PATENT RIGHTS ARE
     *   GRANTED BY THIS LICENSE. THIS SOFTWARE IS PROVIDED BY THE
     *   COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
     *   IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     *   WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     *   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
     *   OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     *   LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     *   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     *   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     *   OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     *   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     *
     *--------------------------------------------------------------------*/

    /*====================================================================*
     *
     *   int6kuart.c - Atheros Serial Line Device Manager;
     *
     *
     *   Contributor(s):
     *	Charles Maier <cmaier@qca.qualcomm.com>
     *	Mathieu Olivari <mathieu@qca.qualcomm.com>
     *
     *--------------------------------------------------------------------*/

    /*====================================================================*
     *   system header files;
     *--------------------------------------------------------------------*/

    #include <unistd.h>
    #include <stdlib.h>
    #include <string.h>

    #if defined (WIN32)
    #	include <net/ethernet.h>
    #elif defined (__linux__)
    #	include <net/ethernet.h>
    #elif defined (__APPLE__)
    #	include <net/ethernet.h>
    #elif defined (__OpenBSD__)
    #	include <sys/socket.h>
    #	include <net/if.h>
    #	include <net/if_arp.h>
    #	include <netinet/in.h>
    #	include <netinet/if_ether.h>
    #else
    #error "Unknown Environment"
    #endif

    /*====================================================================*
     *   custom header files;
     *--------------------------------------------------------------------*/

    #include "../tools/getoptv.h"
    #include "../tools/putoptv.h"
    #include "../tools/number.h"
    #include "../tools/memory.h"
    #include "../tools/endian.h"
    #include "../tools/files.h"
    #include "../tools/flags.h"
    #include "../tools/error.h"
    #include "../tools/types.h"
    #include "../serial/serial.h"
    #include "../plc/plc.h"

    /*====================================================================*
     *   custom source files;
     *--------------------------------------------------------------------*/

    #ifndef MAKEFILE
    #include "../tools/getoptv.c"
    #include "../tools/putoptv.c"
    #include "../tools/version.c"
    #include "../tools/uintspec.c"
    #include "../tools/basespec.c"
    #include "../tools/synonym.c"
    #include "../tools/todigit.c"
    #include "../tools/error.c"
    #include "../tools/checksum32.c"
    #include "../tools/hexencode.c"
    #include "../tools/hexdump.c"
    #include "../tools/hexstring.c"
    #include "../tools/hexdecode.c"
    #include "../tools/error.c"
    #endif

    #ifndef MAKEFILE
    #include "../serial/openport.c"
    #include "../serial/closeport.c"
    #include "../serial/serial.c"
    #endif

    /*====================================================================*
     *   program constants;
     *--------------------------------------------------------------------*/

    #define FRAME_MIN_CHAR 120
    #define FRAME_MAX_CHAR 1496

    /*====================================================================*
     *   program variables;
     *--------------------------------------------------------------------*/

    typedef struct uart

    {
    	struct _file_ port;
    	struct _file_ pib;
    	struct _file_ nvm;
    	struct _file_ eth;
    	char const * string;
    	char PIBVersion [3];
    	char IMGVersion [128];
    	byte MACAddress [ETHER_ADDR_LEN];
    	char NMKDigest [16];
    	byte NMKNumber;
    	byte module;
    	uint16_t bfsize;
    	uint16_t snooze;
    	uint16_t timeout;
    	unsigned flags;
    }

    uart;

    /*====================================================================*
     *
     *   void at_writenvm (struct uart * uart);
     *
     *   read firmware image from file and send to device using command
     *   "ATWPF"; the file descriptor is "nvm" member of struct uart;
     *
     *--------------------------------------------------------------------*/

    static void at_writenvm (struct uart * uart)

    {
    	extern struct command command;
    	byte memory [UART_BLOCKSIZE];
    	signed mblock = sizeof (memory);
    	uint16_t mlength = 0;
    	uint32_t moffset = 0;
    	uint32_t mchksum;
    	uint16_t olength = 0;
    	uint32_t ooffset = 0;
    	uint32_t ochksum;
    	while ((mblock = read (uart->nvm.file, memory, mblock)) > 0)
    	{
    		clearcommand ();
    		insert ('A');
    		insert ('T');
    		insert ('W');
    		insert ('P');
    		insert ('F');
    		insert ('1');
    		insert (',');
    		mchksum = checksum32 (memory, (size_t)(mblock), 0);
    		mlength = (uint16_t)(mblock);
    		mlength = HTOBE16 (mlength);
    		decode (&mlength, sizeof (mlength));
    		mlength = BE16TOH (mlength);
    		insert (',');
    		moffset = HTOBE32 (moffset);
    		decode (&moffset, sizeof (moffset));
    		moffset = BE32TOH (moffset);
    		insert (',');
    		mchksum = HTOBE32 (mchksum);
    		decode (&mchksum, sizeof (mchksum));
    		mchksum = BE32TOH (mchksum);
    		insert (',');
    		decode (memory, mlength);
    		insert ('\r');
    		sendcommand (&uart->port, uart->flags);
    		readcommand (&uart->port, uart->flags);
    		mustbe ('O');
    		mustbe ('K');
    		mustbe ('1');
    		mustbe (',');
    		olength = (uint16_t)(hextoint (sizeof (olength)));
    		if (olength != mlength)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected length %X", command.buffer, mlength);
    		}
    		mustbe (',');
    		ooffset = (uint32_t)(hextoint (sizeof (ooffset)));
    		if (ooffset != moffset)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected offset %X", command.buffer, moffset);
    		}
    		mustbe (',');
    		ochksum = (uint32_t)(hextoint (sizeof (ochksum)));
    		if (ochksum != mchksum)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected checksum %X (%X)", command.buffer, mchksum, ochksum);
    		}
    		mustbe (',');
    		encode (memory, mblock);
    		mustbe ('\r');
    		moffset += mlength;
    		if (_allclr (uart->flags, (UART_VERBOSE | UART_SILENCE)))
    		{
    			write (STDOUT_FILENO, ".", 1);
    		}
    	}

    #ifndef WIN32

    	if (_allclr (uart->flags, (UART_VERBOSE | UART_SILENCE)))
    	{
    		write (STDOUT_FILENO, "\n", 1);
    	}

    #endif

    	return;
    }

    /*====================================================================*
     *
     *   void at_writepib (struct uart * uart);
     *
     *   read parameter block file and send to device using command
     *   "ATWPF"; the file descriptor is "pib" member of struct uart;
     *
     *--------------------------------------------------------------------*/

    static void at_writepib (struct uart * uart)

    {
    	extern struct command command;
    	byte memory [UART_BLOCKSIZE];
    	signed mblock = sizeof (memory);
    	uint16_t mlength = 0;
    	uint16_t moffset = 0;
    	uint32_t mchksum;
    	uint16_t olength = 0;
    	uint16_t ooffset = 0;
    	uint32_t ochksum;
    	while ((mblock = read (uart->pib.file, memory, mblock)) > 0)
    	{
    		clearcommand ();
    		insert ('A');
    		insert ('T');
    		insert ('W');
    		insert ('P');
    		insert ('F');
    		insert ('2');
    		insert (',');
    		mchksum = checksum32 (memory, (size_t)(mblock), 0);
    		mlength = (uint16_t)(mblock);
    		mlength = HTOBE16 (mlength);
    		decode (&mlength, sizeof (mlength));
    		mlength = BE16TOH (mlength);
    		insert (',');
    		moffset = HTOBE16 (moffset);
    		decode (&moffset, sizeof (moffset));
    		moffset = BE16TOH (moffset);
    		insert (',');
    		mchksum = HTOBE32 (mchksum);
    		decode (&mchksum, sizeof (mchksum));
    		mchksum = BE32TOH (mchksum);
    		insert (',');
    		decode (memory, mlength);
    		insert ('\r');
    		sendcommand (&uart->port, uart->flags);
    		readcommand (&uart->port, uart->flags);
    		mustbe ('O');
    		mustbe ('K');
    		mustbe ('2');
    		mustbe (',');
    		olength = (uint16_t)(hextoint (sizeof (olength)));
    		if (olength != mlength)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected length %X", command.buffer, mlength);
    		}
    		mustbe (',');
    		ooffset = (uint16_t)(hextoint (sizeof (ooffset)));
    		if (ooffset != moffset)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected offset %X", command.buffer, moffset);
    		}
    		mustbe (',');
    		ochksum = (uint32_t)(hextoint (sizeof (ochksum)));
    		if (ochksum != mchksum)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected checksum %X (%X)", command.buffer, mchksum, ochksum);
    		}
    		mustbe (',');
    		encode (memory, mblock);
    		mustbe ('\r');
    		moffset += mlength;
    		if (_allclr (uart->flags, (UART_VERBOSE | UART_SILENCE)))
    		{
    			write (STDOUT_FILENO, ".", 1);
    		}
    	}

    #ifndef WIN32

    	if (_allclr (uart->flags, (UART_VERBOSE | UART_SILENCE)))
    	{
    		write (STDOUT_FILENO, "\n", 1);
    	}

    #endif

    	return;
    }

    /*====================================================================*
     *
     *   void at_readpib (struct uart * uart);
     *
     *   read parameter block from device and save to file using command
     *   "ATRP"; the file descriptor is "pib" member of struct uart;
     *
     *--------------------------------------------------------------------*/

    static void at_readpib (struct uart * uart)

    {
    	extern struct command command;
    	byte memory [UART_BLOCKSIZE];
    	signed mblock = sizeof (memory);
    	uint16_t mextent = 0;
    	uint16_t mlength = 0;
    	uint16_t moffset = 0;
    	uint16_t olength = 0;
    	uint16_t ooffset = 0;
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('R');
    	insert ('P');
    	insert ('2');
    	insert (',');
    	insert ('4');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('2');
    	mustbe (',');
    	mustbe ('4');
    	mustbe (',');
    	encode (&mextent, sizeof (mextent));
    	mextent = LE16TOH (mextent);
    	mustbe ('\r');
    	while (mextent)
    	{
    		clearcommand ();
    		insert ('A');
    		insert ('T');
    		insert ('R');
    		insert ('P');
    		if (mblock > mextent)
    		{
    			mblock = mextent;
    		}
    		mlength = (uint16_t)(mblock);
    		mlength = HTOBE16 (mlength);
    		decode (&mlength, sizeof (mlength));
    		mlength = BE16TOH (mlength);
    		insert (',');
    		moffset = HTOBE16 (moffset);
    		decode (&moffset, sizeof (moffset));
    		moffset = BE16TOH (moffset);
    		insert ('\r');
    		sendcommand (&uart->port, uart->flags);
    		readcommand (&uart->port, uart->flags);
    		mustbe ('O');
    		mustbe ('K');
    		olength = (uint16_t)(hextoint (sizeof (olength)));
    		if (olength != mlength)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: have %d bytes but wanted %d", command.buffer, olength, mlength);
    		}
    		mustbe (',');
    		ooffset = (uint16_t)(hextoint (sizeof (ooffset)));
    		if (ooffset != moffset)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, EINVAL, "[%s]: expected offset %X", command.buffer, moffset);
    		}
    		mustbe (',');
    		encode (memory, mblock);
    		if (write (uart->pib.file, memory, mblock) < mblock)
    		{
    			command.buffer [command.offset] = (char)(0);
    			error (1, errno, "[%s]: expected length %d", command.buffer, mblock);
    		}
    		mustbe ('\r');
    		moffset += mblock;
    		mextent -= mblock;
    		if (_allclr (uart->flags, (UART_VERBOSE | UART_SILENCE)))
    		{
    			write (STDOUT_FILENO, ".", 1);
    		}
    	}

    #ifndef WIN32

    	if (_allclr (uart->flags, (UART_VERBOSE | UART_SILENCE)))
    	{
    		write (STDOUT_FILENO, "\n", 1);
    	}

    #endif

    	return;
    }

    /*====================================================================*
     *
     *   void at_wake (struct uart * uart);
     *
     *   send wake command "+++" to enter command mode;
     *
     *--------------------------------------------------------------------*/

    static void at_wake (struct uart * uart)

    {
    	clearcommand ();
    	insert ('+');
    	insert ('+');
    	insert ('+');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void at_command (struct uart * uart);
     *
     *   send custom command; use this function to send any serial line
     *   command that may not be supported by this program;
     *
     *--------------------------------------------------------------------*/

    static void at_command (struct uart * uart)

    {
    	clearcommand ();
    	while (*uart->string)
    	{
    		insert (*uart->string++);
    	}
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	clearcommand ();
    	return;
    }

    /*====================================================================*
     *
     *   void at_respond (struct uart * uart);
     *
     *   send command "AT" to test command mode; this command does nothing
     *   but echo "OK";
     *
     *--------------------------------------------------------------------*/

    static void at_respond (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void atz (struct uart * uart);
     *
     *   send command "ATZ" to reset the device; no response is expected;
     *
     *--------------------------------------------------------------------*/

    static void atz (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('Z');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	return;
    }

    /*====================================================================*
     *
     *   void atrv (struct uart * uart);
     *
     *   read and display the firmware image version using command "ATRV";
     *   return the version string in IMGVersion member of struct uart;
     *
     *--------------------------------------------------------------------*/

    static void atrv (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('R');
    	insert ('V');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\"');
    	string (uart->IMGVersion);
    	mustbe ('\"');
    	mustbe ('\r');
    	printf ("%s\n", uart->IMGVersion);
    	return;
    }

    /*====================================================================*
     *
     *   void atrpm (struct uart * uart);
     *
     *   read and display the PIB version and MAC address using command
     *   "ATRPM"; return version string in PIBVersion member and address
     *   string in MACAddress member of struct
     *
     *
     *--------------------------------------------------------------------*/

    static void atrpm (struct uart * uart)

    {
    	char mac [ETHER_ADDR_LEN * 3];
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('R');
    	insert ('P');
    	insert ('M');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\"');
    	string (uart->PIBVersion);
    	mustbe ('\"');
    	mustbe (',');
    	encode (uart->MACAddress, sizeof (uart->MACAddress));
    	mustbe ('\r');
    	printf ("%s %s\n", uart->PIBVersion, hexstring (mac, sizeof (mac), uart->MACAddress, sizeof (uart->MACAddress)));
    	return;
    }

    /*====================================================================*
     *
     *   void atsk1 (struct uart * uart);
     *
     *   send Set Key command "ATSK"; ask device for NMK; encode returned
     *   key into uart-NMK;
     *
     *--------------------------------------------------------------------*/

    static void atsk1 (struct uart * uart)

    {
    	char key [48];
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('S');
    	insert ('K');
    	insert ('?');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	encode (uart->NMKDigest, sizeof (uart->NMKDigest));
    	mustbe ('\r');
    	printf ("%s\n", hexstring (key, sizeof (key), uart->NMKDigest, sizeof (uart->NMKDigest)));
    	return;
    }

    /*====================================================================*
     *
     *   void atsk2 (struct uart * uart);
     *
     *   send Set Key command "ATSK"; send device the NMK; encode returned
     *
     *--------------------------------------------------------------------*/

    static void atsk2 (struct uart * uart)

    {
    	char key [48];
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('S');
    	insert ('K');
    	decode (uart->NMKDigest, sizeof (uart->NMKDigest));
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	encode (uart->NMKDigest, sizeof (uart->NMKDigest));
    	mustbe ('\r');
    	printf ("%s\n", hexstring (key, sizeof (key), uart->NMKDigest, sizeof (uart->NMKDigest)));
    	return;
    }

    /*====================================================================*
     *
     *   void atdst1 (struct uart * uart);
     *
     *   read transparent mode destination MAC address command "ATDST?";
     *
     *--------------------------------------------------------------------*/

    static void atdst1 (struct uart * uart)

    {
    	char mac [ETHER_ADDR_LEN * 3];
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('D');
    	insert ('S');
    	insert ('T');
    	insert ('?');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	encode (uart->MACAddress, sizeof (uart->MACAddress));
    	mustbe ('\r');
    	printf ("%s\n", hexstring (mac, sizeof (mac), uart->MACAddress, sizeof (uart->MACAddress)));
    	return;
    }

    /*====================================================================*
     *
     *   void atdst2 (struct uart * uart);
     *
     *   read transparent mode destination MAC address command "ATDST?";
     *
     *--------------------------------------------------------------------*/

    static void atdst2 (struct uart * uart)

    {
    	char mac [ETHER_ADDR_LEN * 3];
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('D');
    	insert ('S');
    	insert ('T');
    	decode (uart->MACAddress, sizeof (uart->MACAddress));
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	encode (uart->MACAddress, sizeof (uart->MACAddress));
    	mustbe ('\r');
    	printf ("%s\n", hexstring (mac, sizeof (mac), uart->MACAddress, sizeof (uart->MACAddress)));
    	return;
    }

    /*====================================================================*
     *
     *   void atni (struct uart * uart);
     *
     *   reset device to factory default pib command "ATNI";
     *
     *--------------------------------------------------------------------*/

    static void atni (struct uart * uart)

    {
    	unsigned count;
    	unsigned index;
    	uint16_t rxrate;
    	uint16_t txrate;
    	byte address [ETHER_ADDR_LEN];
    	char mac [ETHER_ADDR_LEN * 3];
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('N');
    	insert ('I');
    	insert ('?');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	count = (unsigned)(hextoint (sizeof (unsigned)));
    	while (count--)
    	{
    		mustbe (',');
    		index = (unsigned)(hextoint (sizeof (index)));
    		mustbe (',');
    		encode (address, sizeof (address));
    		mustbe (',');
    		txrate = (uint16_t)(hextoint (sizeof (rxrate)));
    		mustbe (',');
    		rxrate = (uint16_t)(hextoint (sizeof (txrate)));
    		printf ("%d %s %3d RX %3d TX\n", index, hexstring (mac, sizeof (mac), address, sizeof (address)), rxrate, txrate);
    	}
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void atfd (struct uart * uart);
     *
     *   reset device to factory default pib command "ATFD";
     *
     *--------------------------------------------------------------------*/

    static void atfd (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('F');
    	insert ('D');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void atps (struct uart * uart);
     *
     *   etner power save mode command "ATPS";
     *
     *--------------------------------------------------------------------*/

    static void atps (struct uart * uart)

    {
    	extern struct command command;
    	uint16_t result;
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('P');
    	insert ('S');
    	uart->snooze = HTOBE16 (uart->snooze);
    	decode (&uart->snooze, sizeof (uart->snooze));
    	uart->snooze = BE16TOH (uart->snooze);
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	result = (uint16_t)(hextoint (sizeof (result)));
    	if (result != uart->snooze)
    	{
    		error (1, EINVAL, "[%s]: expected timeout %04X", command.buffer, uart->snooze);
    	}
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void ato (struct uart * uart);
     *
     *   exit command mode and enter tyransparent mode command "ATO";
     *
     *--------------------------------------------------------------------*/

    static void ato (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('O');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void athsc (struct uart * uart);
     *
     *   exit command mode; enter high speed command mode "ATHSC";
     *
     *--------------------------------------------------------------------*/

    static void athsc (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('H');
    	insert ('S');
    	insert ('C');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void atwnv (struct uart * uart);
     *
     *   write PIB and/or IMG to NVM "ATWNVx";
     *
     *--------------------------------------------------------------------*/

    static void atwnv (struct uart * uart)

    {
    	extern struct command command;
    	byte result;
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('W');
    	insert ('N');
    	insert ('V');
    	decode (&uart->module, sizeof (uart->module));
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	result = (byte)(hextoint (sizeof (result)));
    	if (result != uart->module)
    	{
    		error (1, EINVAL, "[%s]: expected module %d", command.buffer, uart->module);
    	}
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void atbsz1 (struct uart * uart);
     *
     *   get transparent mode buffer size "ATBSZ?";
     *
     *--------------------------------------------------------------------*/

    static void atbsz1 (struct uart * uart)

    {
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('B');
    	insert ('S');
    	insert ('Z');
    	insert ('?');
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	uart->bfsize = (uint16_t)(hextoint (sizeof (uart->bfsize)));
    	mustbe ('\r');
    	printf ("%d\n", uart->bfsize);
    	return;
    }

    /*====================================================================*
     *
     *   void atbsz2 (struct uart * uart);
     *
     *   set transparent mode buffer size "ATBSZn";
     *
     *--------------------------------------------------------------------*/

    static void atbsz2 (struct uart * uart)

    {
    	extern struct command command;
    	uint16_t result;
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('B');
    	insert ('S');
    	insert ('Z');
    	uart->bfsize = HTOBE16 (uart->bfsize);
    	decode (&uart->bfsize, sizeof (uart->bfsize));
    	uart->bfsize = BE16TOH (uart->bfsize);
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	result = (uint16_t)(hextoint (sizeof (result)));
    	if (result != uart->bfsize)
    	{
    		error (1, EINVAL, "[%s]: expected buffer size %04X", command.buffer, uart->bfsize);
    	}
    	mustbe ('\r');
    	printf ("%d\n", uart->bfsize);
    	return;
    }

    /*====================================================================*
     *
     *   void atto (struct uart * uart);
     *
     *   set transparent mode buffer timeout "ATTO";
     *
     *--------------------------------------------------------------------*/

    static void atto (struct uart * uart)

    {
    	extern struct command command;
    	uint16_t result;
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('T');
    	insert ('O');
    	uart->timeout = HTOBE16 (uart->timeout);
    	decode (&uart->timeout, sizeof (uart->timeout));
    	uart->timeout = BE16TOH (uart->timeout);
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	mustbe ('O');
    	mustbe ('K');
    	result = (uint16_t)(hextoint (sizeof (result)));
    	if (result != uart->timeout)
    	{
    		error (1, EINVAL, "[%s]: expected timeout %04X", command.buffer, uart->timeout);
    	}
    	mustbe ('\r');
    	return;
    }

    /*====================================================================*
     *
     *   void atm (struct uart * uart);
     *
     *
     *--------------------------------------------------------------------*/

    static void atm (struct uart * uart)

    {
    	extern struct command command;
    	uint8_t buffer [ETHER_MAX_LEN + ETHER_MAX_LEN + 512];
    	unsigned length = (unsigned)(readframe (uart->eth.file, buffer, sizeof (buffer)));
    	if (length < FRAME_MIN_CHAR)
    	{
    		error (1, ENOTSUP, "Frame specification of %d bytes less than %d minimum", (length >> 1), (FRAME_MIN_CHAR >> 1));
    	}
    	if (length > FRAME_MAX_CHAR)
    	{
    		error (1, ENOTSUP, "Frame specification of %d bytes more than %d maximum", (length >> 1), (FRAME_MAX_CHAR >> 1));
    	}
    	clearcommand ();
    	insert ('A');
    	insert ('T');
    	insert ('M');
    	memcpy (command.buffer + command.length, buffer, length);
    	command.length += (signed)(length);
    	insert ('\r');
    	sendcommand (&uart->port, uart->flags);
    	readcommand (&uart->port, uart->flags);
    	write (STDOUT_FILENO, command.buffer, command.length);
    	write (STDOUT_FILENO, "\n", sizeof (char));
    	return;
    }

    /*====================================================================*
     *
     *   void manager (struct uart * uart);
     *
     *   examine flagword in struct uart and perform requested operations
     *   in the order that bits are tested; the order that bits are tested
     *   may be changed as needed;
     *
     *--------------------------------------------------------------------*/

    static void manager (struct uart * uart)

    {
    	if (_anyset (uart->flags, UART_WAKE))
    	{
    		at_wake (uart);
    	}
    	if (_anyset (uart->flags, UART_COMMAND))
    	{
    		at_command (uart);
    	}
    	if (_anyset (uart->flags, UART_RESPOND))
    	{
    		at_respond (uart);
    	}
    	if (_anyset (uart->flags, UART_ATRV))
    	{
    		atrv (uart);
    	}
    	if (_anyset (uart->flags, UART_ATRPM))
    	{
    		atrpm (uart);
    	}
    	if (_anyset (uart->flags, UART_ATDST1))
    	{
    		atdst1 (uart);
    	}
    	if (_anyset (uart->flags, UART_ATDST2))
    	{
    		atdst2 (uart);
    	}
    	if (_anyset (uart->flags, UART_ATZ))
    	{
    		atz (uart);
    	}
    	if (_anyset (uart->flags, UART_ATFD))
    	{
    		atfd (uart);
    	}
    	if (_anyset (uart->flags, UART_ATPS))
    	{
    		atps (uart);
    	}
    	if (_anyset (uart->flags, UART_ATO))
    	{
    		ato (uart);
    	}
    	if (_anyset (uart->flags, UART_ATNI))
    	{
    		atni (uart);
    	}
    	if (_anyset (uart->flags, UART_ATHSC))
    	{
    		athsc (uart);
    	}
    	if (_anyset (uart->flags, UART_ATSK1))
    	{
    		atsk1 (uart);
    	}
    	if (_anyset (uart->flags, UART_ATSK2))
    	{
    		atsk2 (uart);
    	}
    	if (_anyset (uart->flags, UART_ATRP))
    	{
    		at_readpib (uart);
    	}
    	if (_anyset (uart->flags, UART_ATWPF1))
    	{
    		at_writenvm (uart);
    	}
    	if (_anyset (uart->flags, UART_ATWPF2))
    	{
    		at_writepib (uart);
    	}
    	if (_anyset (uart->flags, UART_ATWNV))
    	{
    		atwnv (uart);
    	}
    	if (_anyset (uart->flags, UART_ATBSZ1))
    	{
    		atbsz1 (uart);
    	}
    	if (_anyset (uart->flags, UART_ATBSZ2))
    	{
    		atbsz2 (uart);
    	}
    	if (_anyset (uart->flags, UART_ATM))
    	{
    		atm (uart);
    	}
    	if (_anyset (uart->flags, UART_ATTO))
    	{
    		atto (uart);
    	}
    	return;
    }

    /*====================================================================*
     *
     *   int main (int argc, char const * argv []);
     *
     *
     *
     *
     *--------------------------------------------------------------------*/

    int main (int argc, char const * argv [])

    {
    	static char const * optv [] =
    	{
    		"bc:C:dD:F:HiImM:n:N:Op:P:qrRS:s:tTvwW:zZ:",
    		"",
    		"Atheros Serial Line Device Manager",
    		"b\tset default host baud rate",
    		"c s\tsend custom serial line command (s)",
    		"C x\tcommit module (x) to NVM [ATWNVx]",
    		"d\tget destination mac address [ATDST?]",
    		"D x\tset destination mac address [ATDSTx]",
    		"F f\tframe file is (s)",
    		"H\tplace device in High Speed Command Mode [ATHSC]",
    		"i\tget network information [ATNI]",
    		"I\tget PIB version and MAC address [ATRPM]",
    		"m\tget network membership key [ATSK?]",
    		"M x\tset network membership key [ATSKx]",
    		"N f\twrite NVM file (f) to SDRAM [ATWFP1]",
    		"O\tplace device in Transparent Mode [ATO]",
    		"p f\tread PIB from SDRAM to file (f) [ATRP]",
    		"P f\twrite PIB file (f) to SDRAM [ATWFP2]",
    		"q\tplace program in quiet mode",
    		"r\tget parameter/firmware revision [ATRV]",
    		"R\treset device [ATZ]",
    		"s f\tserial port is (f) [" DEVICE "]",
    		"S n\tenter power save mode for (n) seconds [ATPS]",
    		"t\ttest device [AT]",
    		"T\treset to factory defaults [ATFD]",
    		"v\tplace program verbose mode",
    		"w\tplace device in Command Mode [+++]",
    		"W x\tset Transparent Mode aggregation timeout [ATTO]",
    		"z\tget Transparent Mode buffer size [ATBSZ?]",
    		"Z n\tset Transparent Mode buffer size [ATBSZn]",
    		(char const *) (0)
    	};
    	struct uart uart =
    	{
    		{
    			0,
    			DEVICE
    		},
    		{
    			-1,
    			"nvmfile"
    		},
    		{
    			-1,
    			"pibfile"
    		},
    		{
    			-1,
    			"ethfile"
    		},
    		(char *)(0),
    		{
    			0
    		},
    		{
    			0
    		},
    		{
    			0
    		},
    		{
    			0
    		},
    		(uint8_t)(0),
    		(uint8_t)(0),
    		(uint16_t)(0),
    		(uint16_t)(0),
    		(uint16_t)(0),
    		(unsigned)(0)
    	};
    	signed c;
    	if (getenv (UART_PORT))
    	{
    		uart.port.name = strdup (getenv (UART_PORT));
    	}
    	while ((c = getoptv (argc, argv, optv)) != -1)
    	{
    		switch (c)
    		{
    		case 'b':
    			_setbits (uart.flags, UART_DEFAULT);
    			break;
    		case 'c':
    			_setbits (uart.flags, UART_COMMAND);
    			uart.string = optarg;
    			break;
    		case 'C':
    			_setbits (uart.flags, UART_ATWNV);
    			uart.module = (byte)(basespec (optarg, 16, sizeof (uart.module)));
    			break;
    		case 'd':
    			_setbits (uart.flags, UART_ATDST1);
    			break;
    		case 'D':
    			_setbits (uart.flags, UART_ATDST2);
    			if (!hexencode (uart.MACAddress, sizeof (uart.MACAddress), optarg))
    			{
    				error (1, errno, PLC_BAD_MAC, optarg);
    			}
    			break;
    		case 'F':
    			if ((uart.eth.file = open (uart.eth.name = optarg, O_BINARY | O_RDONLY)) == -1)
    			{
    				error (1, errno, "%s", uart.eth.name);
    			}
    			_setbits (uart.flags, UART_ATM);
    			break;
    		case 'H':
    			_setbits (uart.flags, UART_ATHSC);
    			break;
    		case 'i':
    			_setbits (uart.flags, UART_ATNI);
    			break;
    		case 'I':
    			_setbits (uart.flags, UART_ATRPM);
    			break;
    		case 'm':
    			_setbits (uart.flags, UART_ATSK1);
    			break;
    		case 'M':
    			_setbits (uart.flags, UART_ATSK2);
    			if (!hexencode (uart.NMKDigest, sizeof (uart.NMKDigest), optarg))
    			{
    				error (1, errno, PLC_BAD_NMK, optarg);
    			}
    			break;
    		case 'N':
    			if ((uart.nvm.file = open (uart.nvm.name = optarg, O_BINARY | O_RDONLY)) == -1)
    			{
    				error (1, errno, "%s", uart.nvm.name);
    			}
    			_setbits (uart.flags, UART_ATWPF1);
    			break;
    		case 'O':
    			_setbits (uart.flags, UART_ATO);
    			break;
    		case 'P':
    			if ((uart.pib.file = open (uart.pib.name = optarg, O_BINARY | O_RDONLY)) == -1)
    			{
    				error (1, errno, "%s", uart.pib.name);
    			}
    			_setbits (uart.flags, UART_ATWPF2);
    			break;
    		case 'p':
    			if ((uart.pib.file = open (uart.pib.name = optarg, O_BINARY|O_CREAT|O_RDWR|O_TRUNC, FILE_FILEMODE)) == -1)
    			{
    				error (1, errno, "%s", uart.pib.name);
    			}

    #ifndef WIN32

    			chown (optarg, getuid (), getgid ());

    #endif

    			_setbits (uart.flags, UART_ATRP);
    			break;
    		case 'q':
    			_setbits (uart.flags, UART_SILENCE);
    			break;
    		case 'r':
    			_setbits (uart.flags, UART_ATRV);
    			break;
    		case 'R':
    			_setbits (uart.flags, UART_ATZ);
    			break;
    		case 'S':
    			_setbits (uart.flags, UART_ATPS);
    			uart.snooze = (uint16_t)(uintspec (optarg, 1, 900));
    			break;
    		case 's':
    			uart.port.name = optarg;
    			break;
    		case 'T':
    			_setbits (uart.flags, UART_ATFD);
    			break;
    		case 't':
    			_setbits (uart.flags, UART_RESPOND);
    			break;
    		case 'v':
    			_setbits (uart.flags, UART_VERBOSE);
    			break;
    		case 'w':
    			_setbits (uart.flags, UART_WAKE);
    			break;
    		case 'W':
    			_setbits (uart.flags, UART_ATTO);
    			uart.timeout = (unsigned)(uintspec (optarg, 1, 2000));
    			break;
    		case 'z':
    			_setbits (uart.flags, UART_ATBSZ1);
    			break;
    		case 'Z':
    			_setbits (uart.flags, UART_ATBSZ2);
    			uart.bfsize = (uint16_t)(uintspec (optarg, 1, 1500));
    			break;
    		default:
    			break;
    		}
    	}
    	argc -= optind;
    	argv += optind;
    	if (argc)
    	{
    		error (1, ENOTSUP, ERROR_TOOMANY);
    	}
    	openport (&uart.port, uart.flags);
    	manager (&uart);
    	closeport (&uart.port);
    	exit (0);
    }

[PREV] [HOME] [NEXT]