// SPDX-License-Identifier: BSD-3-Clause #include #include #include #include #include #include #include "numeric_types.h" #include "common.h" #include "voltronic/device.h" #include "voltronic/exceptions.h" #include "p18/exceptions.h" #include "util.h" #include "logging.h" #include "server/server.h" #include "server/signal.h" static const char* DEFAULT_HOST = "127.0.0.1"; static int DEFAULT_PORT = 8305; static void usage(const char* progname) { std::cout << "Usage: " << progname << " OPTIONS [COMMAND]\n" << "\n" "Options:\n" " -h, --help: Show this help\n" " --host : Server host (default: " << DEFAULT_HOST << ")\n" " --port Server port (default: " << DEFAULT_PORT << ")\n" " --device : 'usb' (default), 'serial' or 'pseudo'\n" " --timeout : Device timeout in ms (default: " << voltronic::Device::TIMEOUT << ")\n" " --cache-timeout \n" " Default: " << server::Server::CACHE_TIMEOUT << "\n" " --delay : Delay between commands in ms (default: " << server::Server::DELAY << ")\n" " Cache validity time, in ms (default: " << server::Server::CACHE_TIMEOUT << ")\n" " --device-error-limit \n" " Default: " << server::Server::DEVICE_ERROR_LIMIT << "\n" " --verbose: Be verbose\n" "\n"; std::ios_base::fmtflags f(std::cout.flags()); std::cout << std::hex << std::setfill('0') << "USB device options:\n" " --usb-vendor-id : Vendor ID (default: " << std::setw(4) << voltronic::USBDevice::VENDOR_ID << ")\n" " --usb-device-id : Device ID (default: " << std::setw(4) << voltronic::USBDevice::PRODUCT_ID << ")\n"; std::cout.flags(f); std::cout << "\n" "Serial device options:\n" " --serial-name : Path to serial device (default: " << voltronic::SerialDevice::DEVICE_NAME << ")\n" " --serial-baud-rate 110|300|1200|2400|4800|9600|19200|38400|57600|115200\n" " --serial-data-bits 5|6|7|8\n" " --serial-stop-bits 1|1.5|2\n" " --serial-parity none|odd|even|mark|space\n"; exit(1); } int main(int argc, char *argv[]) { // common params u64 timeout = voltronic::Device::TIMEOUT; u64 cacheTimeout = server::Server::CACHE_TIMEOUT; u64 delay = server::Server::DELAY; u32 deviceErrorLimit = server::Server::DEVICE_ERROR_LIMIT; bool verbose = false; // server params std::string host(DEFAULT_HOST); int port = DEFAULT_PORT; // device params DeviceType deviceType = DeviceType::USB; unsigned short usbVendorId = voltronic::USBDevice::VENDOR_ID; unsigned short usbDeviceId = voltronic::USBDevice::PRODUCT_ID; std::string serialDeviceName(voltronic::SerialDevice::DEVICE_NAME); voltronic::SerialBaudRate serialBaudRate = voltronic::SerialDevice::BAUD_RATE; voltronic::SerialDataBits serialDataBits = voltronic::SerialDevice::DATA_BITS; voltronic::SerialStopBits serialStopBits = voltronic::SerialDevice::STOP_BITS; voltronic::SerialParity serialParity = voltronic::SerialDevice::PARITY; try { int opt; struct option long_options[] = { {"help", no_argument, nullptr, 'h'}, {"verbose", no_argument, nullptr, LO_VERBOSE}, {"timeout", required_argument, nullptr, LO_TIMEOUT}, {"cache-timeout", required_argument, nullptr, LO_CACHE_TIMEOUT}, {"delay", required_argument, nullptr, LO_DELAY}, {"device", required_argument, nullptr, LO_DEVICE}, {"device-error-limit", required_argument, nullptr, LO_DEVICE_ERROR_LIMIT}, {"usb-vendor-id", required_argument, nullptr, LO_USB_VENDOR_ID}, {"usb-device-id", required_argument, nullptr, LO_USB_DEVICE_ID}, {"serial-name", required_argument, nullptr, LO_SERIAL_NAME}, {"serial-baud-rate", required_argument, nullptr, LO_SERIAL_BAUD_RATE}, {"serial-data-bits", required_argument, nullptr, LO_SERIAL_DATA_BITS}, {"serial-stop-bits", required_argument, nullptr, LO_SERIAL_STOP_BITS}, {"serial-parity", required_argument, nullptr, LO_SERIAL_PARITY}, {"host", required_argument, nullptr, LO_HOST}, {"port", required_argument, nullptr, LO_PORT}, {nullptr, 0, nullptr, 0} }; bool getoptError = false; // FIXME while ((opt = getopt_long(argc, argv, "h", long_options, nullptr)) != EOF) { if (opt == '?') { getoptError = true; break; } // simple options (flags), no arguments switch (opt) { case 'h': usage(argv[0]); case LO_VERBOSE: verbose = true; continue; default: break; } // options with arguments std::string arg; if (optarg) arg = std::string(optarg); switch (opt) { case LO_DEVICE: if (arg == "usb") deviceType = DeviceType::USB; else if (arg == "serial") deviceType = DeviceType::Serial; else if (arg == "pseudo") deviceType = DeviceType::Pseudo; else throw std::invalid_argument("invalid device"); break; case LO_TIMEOUT: timeout = std::stoull(arg); break; case LO_CACHE_TIMEOUT: cacheTimeout = std::stoull(arg); break; case LO_DELAY: delay = std::stoull(arg); break; case LO_DEVICE_ERROR_LIMIT: deviceErrorLimit = static_cast(std::stoul(arg)); break; case LO_USB_VENDOR_ID: try { if (arg.size() != 4) throw std::invalid_argument("usb-vendor-id: invalid length"); usbVendorId = static_cast(hextoul(arg)); } catch (std::invalid_argument& e) { throw std::invalid_argument(std::string("usb-vendor-id: invalid format: ") + e.what()); } break; case LO_USB_DEVICE_ID: try { if (arg.size() != 4) throw std::invalid_argument("usb-device-id: invalid length"); usbDeviceId = static_cast(hextoul(arg)); } catch (std::invalid_argument& e) { throw std::invalid_argument(std::string("usb-device-id: invalid format: ") + e.what()); } break; case LO_SERIAL_NAME: serialDeviceName = arg; break; case LO_SERIAL_BAUD_RATE: serialBaudRate = static_cast(std::stoul(arg)); if (!voltronic::is_serial_baud_rate_valid(serialBaudRate)) throw std::invalid_argument("invalid serial baud rate"); break; case LO_SERIAL_DATA_BITS: serialDataBits = static_cast(std::stoul(arg)); if (voltronic::is_serial_data_bits_valid(serialDataBits)) throw std::invalid_argument("invalid serial data bits"); break; case LO_SERIAL_STOP_BITS: if (arg == "1") serialStopBits = voltronic::SerialStopBits::One; else if (arg == "1.5") serialStopBits = voltronic::SerialStopBits::OneAndHalf; else if (arg == "2") serialStopBits = voltronic::SerialStopBits::Two; else throw std::invalid_argument("invalid serial stop bits"); break; case LO_SERIAL_PARITY: if (arg == "none") serialParity = voltronic::SerialParity::None; else if (arg == "odd") serialParity = voltronic::SerialParity::Odd; else if (arg == "even") serialParity = voltronic::SerialParity::Even; else if (arg == "mark") serialParity = voltronic::SerialParity::Mark; else if (arg == "space") serialParity = voltronic::SerialParity::Space; else throw std::invalid_argument("invalid serial parity"); break; case LO_HOST: host = arg; break; case LO_PORT: port = std::stoi(arg); break; default: break; } } if (optind < argc) throw std::invalid_argument("extra parameter found"); } catch (std::invalid_argument& e) { myerr << "error: " << e.what(); return 1; } // open device std::shared_ptr dev; try { switch (deviceType) { case DeviceType::USB: dev = std::shared_ptr(new voltronic::USBDevice(usbVendorId, usbDeviceId)); break; case DeviceType::Pseudo: dev = std::shared_ptr(new voltronic::PseudoDevice); break; case DeviceType::Serial: dev = std::shared_ptr(new voltronic::SerialDevice(serialDeviceName, serialBaudRate, serialDataBits, serialStopBits, serialParity)); break; } dev->setTimeout(timeout); } catch (voltronic::DeviceError& e) { myerr << "device error: " << e.what(); return 1; } catch (voltronic::TimeoutError& e) { myerr << "timeout error: " << e.what(); return 1; } catch (voltronic::InvalidDataError& e) { myerr << "data is invalid: " << e.what(); return 1; } catch (p18::InvalidResponseError& e) { myerr << "response is invalid: " << e.what(); return 1; } // create server server::set_signal_handlers(); server::Server server(dev); server.setVerbose(verbose); server.setDelay(delay); server.setDeviceErrorLimit(deviceErrorLimit); server.setCacheTimeout(cacheTimeout); server.start(host, port); if (verbose) mylog << "done"; return 0; }