/*====================================================================* * * 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 * Nathaniel Houghton * Mathieu Olivari * *--------------------------------------------------------------------*/ /*====================================================================* * system header files; *--------------------------------------------------------------------*/ #include #include #include #include #if defined (__linux__) # include #elif defined (__APPLE__) # include #elif defined (__OpenBSD__) || defined (__NetBSD__) || defined (__FreeBSD__) # include #elif defined (WIN32) # include #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 ("%u\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); }