/*====================================================================*
*
* 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.
*
*--------------------------------------------------------------------*/
/*====================================================================*
*
* weeder.c - Weeder Solid State Relay Module Controller;
*
* Contributor(s):
* Charles Maier <cmaier@qca.qualcomm.com>
* Nathaniel Houghton <nhoughto@qca.qualcomm.com>
* Mathieu Olivari <mathieu@qca.qualcomm.com>
*
*--------------------------------------------------------------------*/
/*====================================================================*
* system header files;
*--------------------------------------------------------------------*/
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#if defined (__linux__)
# include <termios.h>
#elif defined (__APPLE__)
# include <termios.h>
#elif defined (__OpenBSD__)
# include <termios.h>
#elif defined (WIN32)
# include <windows.h>
#else
#error "Unknown Environment"
#endif
/*====================================================================*
* custom header files;
*--------------------------------------------------------------------*/
#include "../tools/getoptv.h"
#include "../tools/putoptv.h"
#include "../tools/version.h"
#include "../tools/number.h"
#include "../tools/symbol.h"
#include "../tools/timer.h"
#include "../tools/files.h"
#include "../tools/flags.h"
#include "../tools/error.h"
/*====================================================================*
* custom source files;
*--------------------------------------------------------------------*/
#ifndef MAKEFILE
#include "../tools/getoptv.c"
#include "../tools/putoptv.c"
#include "../tools/version.c"
#include "../tools/uintspec.c"
#include "../tools/synonym.c"
#include "../tools/todigit.c"
#include "../tools/error.c"
#endif
/*====================================================================*
* program constants;
*--------------------------------------------------------------------*/
#define WEEDER_UNITS "BA"
#define WEEDER_LEDS 5
#define WEEDER_BITS 7
#define WEEDER_WAIT 25
#define WEEDER_ECHO 0
#define WEEDER_MODE 1
#define WEEDER_BUFFER_LENGTH 10
#define WEEDER_STRING_LENGTH 15
#ifdef WIN32
# define WEEDER_PORT "com1:"
#else
# define WEEDER_PORT "/dev/ttyS0"
#endif
#define WEEDER_SILENCE (1 << 0)
#define WEEDER_VERBOSE (1 << 1)
#define WEEDER_DISPLAY (1 << 2)
#define WEEDER_NEWLINE (1 << 2)
/*====================================================================*
* program variables;
*--------------------------------------------------------------------*/
static struct _term_ const modes [] =
{
{
"off",
"0"
},
{
"on",
"1"
}
};
static char buffer [WEEDER_BUFFER_LENGTH];
static char string [WEEDER_STRING_LENGTH];
static signed length = 0;
static signed offset = 0;
/*====================================================================*
*
* void function1 (struct _file_ * port, char const * units, unsigned wait, unsigned echo);
*
* send echo command to Weeder Solid State Relay modules B then A;
* Standard Atheros relay modules were wired in reverse order for
* some reason;
*
*--------------------------------------------------------------------*/
static void function1 (struct _file_ * port, char const * units, unsigned wait, unsigned echo)
{
extern char buffer [];
extern signed length;
while (*units)
{
length = 0;
buffer [length++] = *units++;
buffer [length++] = 'X';
buffer [length++] = '0' + (echo & 1);
buffer [length++] = '\r';
if (write (port->file, buffer, length) != length)
{
error (1, errno, FILE_CANTSAVE, port->name);
}
SLEEP (wait);
}
return;
}
/*====================================================================*
*
* void function2 (struct _file_ * port, char const * units, unsigned wait, unsigned mode, unsigned data);
*
* send write command to Weeder Solid State Relay modules B then A
* because Qualcomm Atheros relay modules are wired in reverse order
* for some reason;
*
*--------------------------------------------------------------------*/
static void function2 (struct _file_ * port, char const * units, unsigned wait, unsigned mode, unsigned data)
{
extern char buffer [WEEDER_BUFFER_LENGTH];
extern signed length;
length = 0;
buffer [length++] = *units++;
buffer [length++] = 'W';
buffer [length++] = '0' + (mode & 1);
buffer [length++] = '0';
buffer [length++] = '0';
while (length < WEEDER_BITS)
{
buffer [length++] = '0' + (data & 1);
data >>= 1;
}
buffer [length++] = '\r';
if (write (port->file, buffer, length) != length)
{
error (1, errno, FILE_CANTSAVE, port->name);
}
SLEEP (wait);
length = 0;
buffer [length++] = *units++;
buffer [length++] = 'W';
while (length < WEEDER_BITS)
{
buffer [length++] = '0' + (data & 1);
data >>= 1;
}
buffer [length++] = '\r';
if (write (port->file, buffer, length) != length)
{
error (1, errno, FILE_CANTSAVE, port->name);
}
SLEEP (wait);
return;
}
/*====================================================================*
*
* void function3 (struct _file_ * port, char const * units, unsigned wait);
*
* read weeder solid state controller and display settings on the
* console as attenuation;
*
*--------------------------------------------------------------------*/
static void function3 (struct _file_ * port, char const * units, unsigned wait)
{
extern char buffer [WEEDER_BUFFER_LENGTH];
extern char string [WEEDER_STRING_LENGTH];
extern signed length;
extern signed offset;
unsigned number = 0;
memset (string, 0, sizeof (string));
for (offset = 0; *units; offset += WEEDER_LEDS)
{
length = 0;
buffer [length++] = *units++;
buffer [length++] = 'R';
buffer [length++] = '\r';
if (write (port->file, buffer, length) != length)
{
error (1, errno, FILE_CANTSAVE, port->name);
}
SLEEP (wait);
memset (buffer, 0, sizeof (buffer));
if (read (port->file, buffer, WEEDER_LEDS + 2) == -1)
{
error (1, errno, FILE_CANTREAD, port->name);
}
SLEEP (wait);
memcpy (&string [offset], &buffer [1], WEEDER_LEDS);
}
while (offset-- > 3)
{
number <<= 1;
number |= string [offset] - '0';
}
printf ("%d\n", number);
return;
}
/*====================================================================*
*
* int main (int argc, char const * argv []);
*
*--------------------------------------------------------------------*/
int main (int argc, char const * argv [])
{
static char const * optv [] =
{
"e:m:o:p:iqrvw:",
"",
"Weeder Solid State Relay Module Controller",
"e n\techo is (n) [" LITERAL (WEEDER_ECHO) "]",
"m n\tmode is (n) [" LITERAL (WEEDER_MODE) "]",
"o s\tunit order is (s) [" WEEDER_UNITS "]",
"p f\tport is (f) [" WEEDER_PORT "]",
"q\tquiet mode",
"r\tread attenuator value",
"v\tverbose mode",
"w n\twait (n) millseconds [" LITERAL (WEEDER_WAIT) "]",
(char const *) (0)
};
struct _file_ port =
{
-1,
WEEDER_PORT
};
#if defined (WIN32)
HANDLE hSerial;
DCB dcbSerial =
{
0
};
#else
struct termios termios;
#endif
char const * units = WEEDER_UNITS;
unsigned wait = WEEDER_WAIT;
unsigned echo = WEEDER_ECHO;
unsigned mode = WEEDER_MODE;
unsigned data = 0;
flag_t flags = (flag_t)(0);
signed c;
optind = 1;
if (getenv ("WEEDER"))
{
port.name = strdup (getenv ("WEEDER"));
}
while ((c = getoptv (argc, argv, optv)) != -1)
{
switch (c)
{
case 'e':
echo = (unsigned)(uintspec (synonym (optarg, modes, SIZEOF (modes)), 0, 1));
break;
case 'm':
mode = (unsigned)(uintspec (synonym (optarg, modes, SIZEOF (modes)), 0, 1));
break;
case 'n':
_setbits (flags, WEEDER_NEWLINE);
break;
case 'o':
units = optarg;
break;
case 'p':
port.name = optarg;
break;
case 'w':
wait = (unsigned)(uintspec (optarg, 5, 100));
break;
case 'q':
_setbits (flags, WEEDER_SILENCE);
break;
case 'r':
_setbits (flags, WEEDER_DISPLAY);
break;
case 'v':
_setbits (flags, WEEDER_VERBOSE);
break;
default:
break;
}
}
argc -= optind;
argv += optind;
if ((argc) && (* argv))
{
data = (unsigned)(uintspec (* argv, 0, 0x7F));
}
#if defined (WIN32)
hSerial = CreateFile (port.name, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
if (hSerial == INVALID_HANDLE_VALUE)
{
error (1, errno, FILE_CANTOPEN, port.name);
}
dcbSerial.DCBlength = sizeof (dcbSerial);
if (!GetCommState (hSerial, &dcbSerial))
{
error (1, 0, FILE_CANTREAD " state", port.name);
}
dcbSerial.BaudRate = CBR_9600;
dcbSerial.ByteSize = 8;
dcbSerial.StopBits = ONESTOPBIT;
dcbSerial.Parity = NOPARITY;
if (!SetCommState (hSerial, &dcbSerial))
{
error (1, 0, FILE_CANTSAVE, port.name);
}
CloseHandle (hSerial);
if ((port.file = open (port.name, O_BINARY | O_RDWR)) == -1)
{
error (1, errno, FILE_CANTOPEN " state", port.name);
}
#else
if ((port.file = open (port.name, O_RDWR|O_NOCTTY|O_NDELAY)) == -1)
{
error (1, 0, FILE_CANTOPEN, port.name);
}
tcgetattr (port.file, &termios);
termios.c_cflag = CS8;
cfsetospeed (&termios, B9600);
tcsetattr (port.file, TCSANOW, &termios);
#endif
function1 (&port, units, wait, echo);
if ((argc) && (* argv))
{
function2 (&port, units, wait, mode, data);
}
if (_anyset (flags, WEEDER_DISPLAY))
{
function3 (&port, units, wait);
}
close (port.file);
exit (0);
}