summaryrefslogtreecommitdiffstats
path: root/claws/rcontrol.c
diff options
context:
space:
mode:
authorroot <root@krebs>2011-08-23 23:17:49 +0200
committerroot <root@krebs>2011-08-23 23:17:49 +0200
commit3a632f7579c107fcfec67c1f6a19a99a9b7d28f7 (patch)
tree9ed313f9886c2ea877a816ad74e07b60d4c4bb1e /claws/rcontrol.c
parentccbb59070dfbec560c989cb8c6bd2baf7a8e047e (diff)
claws: initial commit
claws is the tool to control the relais on the usb board by momo
Diffstat (limited to 'claws/rcontrol.c')
-rw-r--r--claws/rcontrol.c479
1 files changed, 479 insertions, 0 deletions
diff --git a/claws/rcontrol.c b/claws/rcontrol.c
new file mode 100644
index 00000000..972c97d0
--- /dev/null
+++ b/claws/rcontrol.c
@@ -0,0 +1,479 @@
+/* +----------------------------------------------------------------------+
+ * | relay control program |
+ * | by mgr, 2007 |
+ * | last change: 2009-01-05 |
+ * | |
+ * | This program is used to control the relay card version 1.0. For more |
+ * | information have a look at the project homepage. |
+ * | You will need libftdi in order to compile this tool. |
+ * | |
+ * | NOTE: For some reason the -l option causes a program crash if I |
+ * | compile this program with -O2. On top of that this code seems to |
+ * | be quite optimal, the program size gets a little larger with -O2, |
+ * | so I suggest you just compile it without optimization. |
+ * +----------------------------------------------------------------------+
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <time.h>
+#include <ftdi.h> // libftdi
+
+/* Notice that if you experiment with the baud rate, you will have to adapt
+ * the firmware, too. Also I do not recommend it, as 9600 Bauds are completely
+ * sufficient for this application. */
+#define BAUD 9600
+
+/* If you are using more than one FT232-based pieces of hardware at once,
+ * we need a way to uniquely address any given one. This is done by the
+ * serial of the specific device which you can pass to this tool or specify
+ * here. If no serial is specified (NULL), the first found device is opened. */
+#define DEFAULT_FT_SERIAL "A6TMRSS6"
+
+#define VERSION "1.0"
+
+#define OPTION_ADDRESS 0x01
+#define OPTION_INTERVAL 0x04
+#define OPTION_CYCLIC 0x08
+#define OPTION_ON 0x10
+#define OPTION_OFF 0x20
+#define OPTION_TOGGLE 0x40
+#define OPTION_DEL_TIMERS 0x80
+#define OPTION_LIST_DEVICES 0x200
+
+#define EXIT_CODE_OK 0
+#define EXIT_CODE_FAILURE 1
+
+#include "communication.h"
+
+/* function prototypes */
+void usage(char* name);
+void version(void);
+const char* card_strerror(int error);
+int valid_argument(const char* str);
+void exit_gracefully(struct ftdi_context* ftdic, char exit_code);
+
+
+int main(int argc, char **argv)
+{
+ int ret=0, int_argument=0, option_flags=0, long_index=0, i=0, num_ops=0;
+ char c=0;
+ unsigned char buf[COMMANDO_LENGTH], char_argument=0, operation=0;
+ const char* ft_serial=DEFAULT_FT_SERIAL;
+ double double_argument;
+ char buf0[64], buf1[64], buf2[64];
+ time_t start_time;
+
+ //struct ftdi_eeprom eeprom;
+
+ struct ftdi_context ftdic;
+ struct ftdi_device_list *devlist=NULL, *curdev=NULL;
+
+ static struct option long_options[] =
+ {
+ {"help", 0, 0, '?'},
+ {"version", 0, 0, 'V'},
+ {"on", 1, 0, 'o'},
+ {"off", 1, 0, 'f'},
+ {"toggle", 1, 0, 't'},
+ {"set", 1, 0, 's'},
+ {"status", 0, 0, 'S'},
+ {"interval", 1, 0, 'v'},
+ {"cyclic", 0, 0, 'c'},
+ {"address", 1, 0, 'a'},
+ {"delete-timers", 0, 0, 'd'},
+ {"list-devices", 0, 0, 'l'},
+ {0, 0, 0, 0 }
+ };
+
+ /* fetch the command line options */
+ while ((c = getopt_long_only(argc, argv, "?Vo:f:t:s:Sv:ca:dl", long_options,
+ &long_index)) != -1)
+ {
+ switch (c)
+ {
+ case 'o': case 'f': case 't':
+ int_argument = atoi(optarg);
+
+ if (int_argument > 6 || int_argument < 1 || !valid_argument(optarg))
+ {
+ fprintf(stderr, "%s: -s: invalid value `%s' (1-6 is valid)\n",
+ *argv, optarg);
+ return EXIT_CODE_FAILURE;
+ }
+
+ char_argument = (unsigned char)int_argument;
+
+ if (c == 't')
+ {
+ operation = COMMAND_RELAY_TOGGLE;
+ option_flags |= OPTION_TOGGLE;
+ } else if (c == 'o')
+ {
+ operation = COMMAND_RELAY_ON;
+ option_flags |= OPTION_ON;
+ } else
+ {
+ operation = COMMAND_RELAY_OFF;
+ option_flags |= OPTION_OFF;
+ }
+
+ num_ops++;
+
+ break;
+
+ case 's':
+ int_argument = atoi(optarg);
+
+ if (int_argument > (1 << 6)-1 || int_argument < 0 || !valid_argument(optarg))
+ {
+ fprintf(stderr, "%s: -s: invalid value `%s'\n", *argv, optarg);
+ return EXIT_CODE_FAILURE;
+ }
+
+ char_argument = (unsigned char)int_argument;
+ operation = COMMAND_RELAY_SET;
+ num_ops++;
+ break;
+
+ case 'S':
+ operation = COMMAND_GET_STATUS;
+ num_ops++;
+ break;
+
+ case 'v':
+ double_argument = atof(optarg);
+ int_argument = (int)(double_argument*60) /10;
+
+ if (int_argument < 1 || int_argument > (1 << 16)-1)
+ {
+ fprintf(stderr, "%s: -i: invalid interval `%s'\n", *argv, optarg);
+ return EXIT_CODE_FAILURE;
+ }
+
+ option_flags |= OPTION_INTERVAL;
+ break;
+
+ case 'c':
+ option_flags |= OPTION_CYCLIC;
+ break;
+
+ case 'd':
+ operation = COMMAND_DEL_TIMERS;
+ option_flags |= OPTION_DEL_TIMERS;
+ num_ops++;
+ break;
+
+ case 'a':
+ if (strlen(optarg) != 8)
+ {
+ fprintf(stderr, "%s: -s: invalid serial number `%s'\n", *argv, optarg);
+ return EXIT_CODE_FAILURE;
+ }
+
+ ft_serial = optarg;
+ option_flags |= OPTION_ADDRESS;
+ break;
+
+ case 'l':
+ option_flags |= OPTION_LIST_DEVICES;
+ break;
+
+ case 'V':
+ version();
+ break;
+ case '?': default:
+ usage(*argv);
+ break;
+ }
+ }
+
+ /* check whether the command line options are valid */
+ if ((option_flags & OPTION_INTERVAL))
+ {
+ if (option_flags & OPTION_DEL_TIMERS)
+ {
+ fprintf(stderr, "%s: -d cannot be mixed with timing options\n", *argv);
+ usage(*argv);
+ }
+
+ if (option_flags & OPTION_CYCLIC)
+ {
+ operation = COMMAND_RELAY_TIME_CYCLIC;
+ } else if (option_flags & OPTION_ON)
+ {
+ operation = COMMAND_RELAY_TIME_ON;
+ } else if (option_flags & OPTION_OFF)
+ {
+ operation = COMMAND_RELAY_TIME_OFF;
+ } else
+ {
+ fprintf(stderr, "%s: -v: you must also specify an operation (-o or -f)\n", *argv);
+ usage(*argv);
+ }
+ }
+
+ if (!operation && !(option_flags & OPTION_LIST_DEVICES))
+ {
+ usage(*argv);
+ }
+
+ if (((option_flags & OPTION_DEL_TIMERS) && (operation != COMMAND_DEL_TIMERS)))
+ {
+ fprintf(stderr, "%s: invalid mixture of options\n", *argv);
+ usage(*argv);
+ }
+
+ if (num_ops > 1)
+ {
+ fprintf(stderr, "%s: more than one operation specified\n", *argv);
+ usage(*argv);
+ }
+
+ if (ftdi_init(&ftdic) < 0)
+ {
+ fprintf(stderr, "%s: unable to initialize FTDI context: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ return EXIT_CODE_FAILURE;
+ }
+
+ /* list all found FT232 devices */
+ if (option_flags & OPTION_LIST_DEVICES)
+ {
+ printf("scanning for FT232 devices...\n"
+ "you can address the devices using `%s -a <serial>'\n", *argv);
+
+ if ((ret = ftdi_usb_find_all(&ftdic, &devlist, 0x0403, 0x6001)) < 0)
+ {
+ fprintf(stderr, "%s: unable to scan devices: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ exit(EXIT_CODE_FAILURE);
+ }
+
+ if (ret == 0)
+ {
+ printf(" no devices found :(\n");
+ return EXIT_CODE_OK;
+ }
+
+ for (i=0, curdev = devlist; curdev != NULL; i++)
+ {
+ if (ftdi_usb_get_strings(&ftdic, curdev->dev, buf0, sizeof(buf0)/sizeof(char),
+ buf1, sizeof(buf1)/sizeof(char), buf2, sizeof(buf2)/sizeof(char)) < 0)
+ {
+ fprintf(stderr, "unable to fetch information for device #%i: %s\n", i,
+ ftdi_get_error_string(&ftdic));
+ // continue caused an endless loop in case of an error
+ break;
+ }
+
+ printf("\ndevice #%i%s:\n"
+ " manufacturer: %s\n"
+ " device: %s\n"
+ " serial: %s\n", i, (i == 0 ? " (default)" : ""),
+ (buf0 != NULL ? buf0 : "n/a"), (buf1 != NULL ? buf1 : "n/a"),
+ (buf2 != NULL ? buf2 : "n/a"));
+
+ curdev = curdev->next;
+ }
+
+ ftdi_list_free(&devlist);
+ return EXIT_CODE_OK;
+ }
+
+ /* Try to open the specified device. If that fails, we take a long shot
+ * and open the first found FT232 device and assume its the relay card.
+ * We don't do this if an address was specified with the -a option. */
+ if ((ret = ftdi_usb_open_desc(&ftdic, 0x0403, 0x6001, NULL, ft_serial)) < 0)
+ {
+ fprintf(stderr, "%s: unable to open ftdi device: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ exit(EXIT_CODE_FAILURE);
+ }
+
+ /* get rid of any data still floating around the buffer */
+ ftdi_usb_reset(&ftdic);
+ ftdi_usb_purge_buffers(&ftdic);
+
+
+ if ((ret = ftdi_set_baudrate(&ftdic, BAUD)) < 0)
+ {
+ fprintf(stderr, "%s: unable to set baudrate: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ exit_gracefully(&ftdic, EXIT_CODE_FAILURE);
+ }
+
+ if ((ret = ftdi_set_line_property(&ftdic, 8, 2, NONE)) < 0)
+ {
+ fprintf(stderr, "%s: unable to set line property: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ exit_gracefully(&ftdic, EXIT_CODE_FAILURE);
+ }
+
+ if ((ret = ftdi_setflowctrl(&ftdic, SIO_RTS_CTS_HS)) < 0) {
+ fprintf(stderr, "%s: unable to setup flow control: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ exit_gracefully(&ftdic, EXIT_CODE_FAILURE);
+ }
+
+ /*if ((ret = ftdi_set_latency_timer(&ftdic, 10)) < 0)
+ {
+ fprintf(stderr, "%s: unable to set latency timer: %d (%s)\n", *argv, ret,
+ ftdi_get_error_string(&ftdic));
+ exit_gracefully(&ftdic, EXIT_CODE_FAILURE);
+ }*/
+
+ buf[0] = operation;
+ buf[2] = 0; buf[3] = 0; buf[4] = 0;
+
+ switch (operation)
+ {
+ case COMMAND_RELAY_SET:
+ buf[1] = char_argument;
+ break;
+
+ case COMMAND_RELAY_ON: case COMMAND_RELAY_OFF:
+ case COMMAND_RELAY_TOGGLE:
+ buf[1] = (1 << (char_argument-1));
+ break;
+
+ case COMMAND_RELAY_TIME_ON:
+ case COMMAND_RELAY_TIME_OFF:
+ case COMMAND_RELAY_TIME_CYCLIC:
+ buf[1] = char_argument-1;
+ buf[2] = (int_argument & 0xff); // low byte
+ buf[3] = (int_argument >> 8); // high byte
+ break;
+
+ default:
+ break;
+ }
+
+ /* These values might not make much sense are vital to the correct
+ * funtion of this program, so better don't touch them. */
+ ftdi_write_data_set_chunksize(&ftdic, 1);
+ ftdi_read_data_set_chunksize(&ftdic, 4);
+
+ /* send the command */
+ if (ftdi_write_data(&ftdic, buf, COMMANDO_LENGTH) != COMMANDO_LENGTH)
+ {
+ fprintf(stderr, "%s: unable to send command: %s\n", *argv,
+ ftdi_get_error_string(&ftdic));
+ exit_gracefully(&ftdic, EXIT_CODE_FAILURE);
+ }
+
+ /* Read the card's response. */
+ start_time = time(NULL);
+ while ((ret = ftdi_read_data(&ftdic, buf, 1)) == 0) {
+ usleep(500);
+ if (time(NULL)-start_time >= 2) {
+ fprintf(stderr, "%s: unable to read card response, the operation might have "
+ "failed\n", *argv);
+ exit_gracefully(&ftdic, EXIT_FAILURE);
+ }
+ }
+
+ if (operation == COMMAND_GET_STATUS && buf[0] <= ((1 << 7)-1))
+ {
+ printf("relay status: %i (0b%s%s%s%s%s%s)\n", buf[0],
+ (buf[0] & (1 << 5)) ? "1" : "0",
+ (buf[0] & (1 << 4)) ? "1" : "0",
+ (buf[0] & (1 << 3)) ? "1" : "0",
+ (buf[0] & (1 << 2)) ? "1" : "0",
+ (buf[0] & (1 << 1)) ? "1" : "0",
+ (buf[0] & (1 << 0)) ? "1" : "0");
+ exit_gracefully(&ftdic, EXIT_CODE_OK);
+ }
+
+ if (buf[0] != RESPONSE_OK)
+ {
+ fprintf(stderr, "%s: relay card returned: %s\n", *argv, card_strerror(buf[0]));
+ exit_gracefully(&ftdic, EXIT_FAILURE);
+ }
+
+ /* we can exit now */
+ exit_gracefully(&ftdic, EXIT_CODE_OK);
+ return 0; // to make the compiler happy
+}
+
+void exit_gracefully(struct ftdi_context* ftdic, char exit_code)
+{
+ ftdi_usb_purge_buffers(ftdic);
+ ftdi_usb_close(ftdic);
+ ftdi_deinit(ftdic);
+
+ exit(exit_code);
+}
+
+int valid_argument(const char* str)
+{
+ int i;
+
+ for (i=0; i<strlen(str); i++)
+ {
+ if (!isdigit(str[i]) && (str[i] != '.'))
+ return 0;
+ }
+
+ return 1;
+}
+
+const char* card_strerror(int error)
+{
+ const char* message = "no error";
+
+ switch (error)
+ {
+ case RESPONSE_OK:
+ message = "all fine";
+ break;
+ case RESPONSE_INVALID_COMMAND:
+ message = "invalid command";
+ break;
+ case RESPONSE_INVALID_ARGUMENT:
+ message = "invalid command argument";
+ break;
+ case RESPONSE_TRANSMISSION_ERROR:
+ message = "transmission error";
+ break;
+ }
+
+ return message;
+}
+
+void usage(char *name)
+{
+ printf("\nrelay control program usage ==================================================\n"
+ " -?/--help .............. dump this screen\n"
+ " -V/--version ........... echo some program information\n"
+ " -o/--on <num>: ......... switch relay <num> on\n"
+ " -f/--off <num>: ........ switch relay <num> off \n"
+ " -t/--toggle <num>: ..... toggle relay <num> \n"
+ " -s/--set <mask>: ....... set the status of all relays to <mask>\n"
+ " -S/--status: ........... get the current relay status\n"
+ " -v/--interval <units> .. specify a timing interval (in minutes)\n"
+ " -c/--cyclic: ........... makes a timing operation (-v) cyclic\n"
+ " -a/--address <serial> .. addresses a specific card if multiple are installed\n"
+ " -d/--delete-timers ..... deletes all active timers\n"
+ " -l/--list-devices ...... lists all found FT232 devices\n\n");
+ exit(0);
+}
+
+void version(void)
+{
+ printf("\nThis is the relay control program version %s ($Revision: 26 $)\n"
+ "----------------------------------------------------------------\n"
+ " written by Michael Gross, 2007\n"
+ " binary compiled: %s %s\n\n"
+ "This program can be redistributed under the terms of the GNU GPL version 2\n"
+ "or later. For more information about this software and the hardware, visit\n"
+ "my homepage at http://www.coremelt.net. As usual with free software, there\n"
+ "is ABSOLUTELY NO WARRANTY. For details, refer to the GPL.\n\n", VERSION,
+ __DATE__, __TIME__);
+
+ exit(0);
+}