/* * Copyright (c) 2023 Carl Klemm * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, * are permitted 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 %ORGANIZATION% nor the names of its contributors may be * used to endorse or promote products derived from this software without specific * prior written permission. * * 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. */ #include #include #include #include #include #include "fandevice.h" #include "options.h" static channel_t char_to_channel(char ch) { switch(ch) { case 'a': case 'A': case '1': return FAN_A; case 'b': case 'B': case '2': return FAN_B; case 'c': case 'C': case '3': return FAN_C; case 'd': case 'D': case '4': return FAN_D; default: return FAN_NONE; } } void print_commands(void) { puts("Valid commands:"); puts("hearbeat\t | set a heatbeat packet"); puts("set [CHANNEL] [SPEED]\t | the the fan speed for a channel"); } static int process_commands(char** commands, size_t command_count, struct fandevice* device, char* name) { if(strcmp(commands[0], "help") == 0) { print_commands(); } if(strcmp(commands[0], "heatbeat") == 0) { int ret = fandevice_heartbeat(device); if(ret < 0) printf("Error writeing to device"); else printf("OK"); } else if(strcmp(commands[0], "set") == 0) { if(command_count < 3) { printf("Usage %s %s [CHANNEL] [SPEED]\n", name, commands[0]); return 2; } channel_t channel = char_to_channel(commands[1][0]); if(channel == FAN_NONE) { printf("%s is not a valid channel\n", commands[1]); return 2; } double speed = strtod(commands[2], NULL); if(speed > 1 || speed < 0) { puts("Speed is out of range [0,1]"); return 2; } fandevice_set_channel(device, channel, speed); } else { return -1; } return 0; } enum { INPUT_SUCESS = 0, INPUT_NO_INPUT, INPUT_TOO_LONG }; static int get_input(char *prompt, char *buffer, size_t length) { int ch, extra; if(prompt != NULL) { fputs(prompt, stdout); fflush(stdout); } if(fgets (buffer, length, stdin) == NULL) return INPUT_NO_INPUT; if(buffer[strlen(buffer)-1] != '\n') { extra = 0; while((ch = getchar()) != '\n' && ch != EOF) extra = 1; return (extra == 1) ? INPUT_TOO_LONG : INPUT_SUCESS; } buffer[strlen(buffer)-1] = '\0'; return INPUT_SUCESS; } int main(int argc, char* argv[]) { struct config config = {}; argp_parse(&argp, argc, argv, 0, 0, &config); if(config.list_commands) { print_commands(); return 0; } if(config.command_count < 1 && !(config.interactive || config.pipe)) { printf("A command is required\n"); return 2; } struct fandevice device; if(fandevice_connect(&device, config.serialSet ? config.serial : 0)) { char serialStr[5]; snprintf(serialStr, sizeof(serialStr), "%04hu", config.serial); printf("Can not connect to FanDevice%s%s\n", config.serialSet ? " with serial " : "", config.serialSet ? serialStr : ""); return 1; } int ret = 0; if(config.interactive || config.pipe) { char buffer[256]; while(true) { int ret = get_input(config.pipe ? NULL : "> ", buffer, sizeof(buffer)); if(ret == INPUT_NO_INPUT) { break; } else if(ret != INPUT_SUCESS) { puts("Invalid command"); continue; } char* commands[MAX_COMMANDS]; char* command = strtok(buffer, " \t"); size_t i = 0; while(command && i < MAX_COMMANDS) { commands[i] = command; command = strtok(NULL, " \t"); ++i; } int cmdRet = process_commands(commands, i, &device, ""); if(cmdRet == 0) puts("OK"); else printf("ERR %i\n", cmdRet); } } else { ret = process_commands(config.commands, config.command_count, &device, argv[0]); } fandevice_disconnect(&device); return ret; }