├── .gitignore ├── CMakeLists.txt ├── README.md ├── snap └── snapcraft.yaml └── src ├── devices.h ├── lib ├── HIDDCDCUSB.cpp ├── HIDDCDCUSB.h ├── HIDInterface.cpp ├── HIDInterface.h ├── HIDNUCUPS.cpp ├── HIDNUCUPS.h ├── HIDOpenUPS.cpp ├── HIDOpenUPS.h ├── HIDOpenUPS2.cpp ├── HIDOpenUPS2.h ├── usbhid.cpp └── usbhid.h ├── main.cpp ├── utils ├── HArray.cpp ├── HArray.h ├── HList.cpp ├── HList.h ├── HLock.cpp ├── HLock.h ├── HThread.cpp ├── HThread.h ├── TxFile.cpp ├── TxFile.h ├── util.cpp └── util.h └── version.h /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | build/ 3 | *.swp 4 | *.ninja 5 | .ninja* 6 | CMakeCache.txt 7 | CMakeFiles 8 | cmake_install.cmake 9 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | project(openups CXX C) 3 | 4 | set(SOURCES 5 | src/main.cpp 6 | src/lib/usbhid.cpp 7 | src/lib/HIDOpenUPS.cpp 8 | src/lib/HIDOpenUPS2.cpp 9 | src/lib/HIDNUCUPS.cpp 10 | src/lib/HIDDCDCUSB.cpp 11 | src/lib/HIDInterface.cpp 12 | src/utils/util.cpp 13 | src/utils/HArray.cpp 14 | ) 15 | 16 | option(_DEBUG "Debug messages" ON) 17 | if (_DEBUG) 18 | add_definitions(-D_DEBUG) 19 | endif() 20 | 21 | add_executable(openups ${SOURCES}) 22 | 23 | 24 | target_include_directories(openups PUBLIC src/utils/ src/lib/) 25 | target_link_libraries(openups 26 | #pthread 27 | usb 28 | ) 29 | 30 | install( 31 | TARGETS openups 32 | DESTINATION bin 33 | ) 34 | 35 | # Snap Build 36 | # snapcraft clean 37 | # snapcraft 38 | # snapcraft upload --release=beta openups_0.4_amd64.snap -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Mini-Box.com UPS Status and Configuration Tool 3 | 4 | Mini-Box.com produces several high quality intelligent Uninterruptible Power Supplies. This is a tool to report status information and configure these UPS models. 5 | 6 | ## Supported models 7 | 8 | - **OpenUPS**: 6-30V Intelligent Uninterruptible Power Supply 9 | - **OpenUPS2**: 11-24V Intelligent DC-DC Uninterruptible Power Supply using LiFePO4 or 13-24V using Li-Ion (see manual) 10 | - **NUC-UPS**: 6-38V Intelligent Automotive grade Uninterruptible Power Supply 11 | - **DCDC-USB**: Intelligent buck-boost DC-DC converter with USB interface 12 | - **DCDC-USB-200**: Intelligent buck-boost DC-DC converter with USB interface 13 | 14 | ## Warning 15 | The flash storage on these devices have limited write cycles (should be considered < _100.000_) so it's *not* advisable to keep writing the configuration periodically on a timer. 16 | 17 | ## Comparison table 18 | | Feature | [OpenUPS](https://www.mini-box.com/OpenUPS) | [OpenUPS2](https://www.mini-box.com/OpenUPS2) | [NUC-UPS](https://www.mini-box.com/NUC-UPS) | 19 | |---------|---------|----------|---------| 20 | | Picture | | | | 21 | |Input Voltage | 6-30V| 11-24V| 6-38 | 22 | |Output Voltage| 5-24V (programable)| 12V* | 12V| 23 | |Architecture| Buck/Boost| Boost| Buck/Boost| 24 | |Max Power| 6A| 5A| 5A| 25 | |Battery Chemistry| Li-Ion, Li-Po, LIFEPO4, Lead Acid| LiFePO4, Li-Ion** | Li-Ion 26 | |Battery Charger| Multiple chemistry charger| 3 state charger| 3 state charger| 27 | |Battery balancing| Yes |Yes| Yes| 28 | |USB Interface| Yes| Yes| Yes| 29 | |SMBUS| Slave| Slave| -| 30 | |Coulomb counting (fuel gauge)| Yes| Yes| Yes| 31 | |Temperature monitoring| On board| For each cell| For each cell| 32 | |Battery design| External removable| Onboard removable| Onboard removable| 33 | |Footprint| Custom| 2.5" drive footprint| 2.5" drive footprint| 34 | |Windows compatible| Yes| Yes| Yes| 35 | |Linux compatible| Yes| Yes | Yes| 36 | |Motherboard ON/OFF pulse control| Yes| Yes| Yes| 37 | Deep Sleep power consumption| <50uA| 1uA |5uA| 38 | |Availability| Long life| Long life| New product| 39 | 40 | ### Notes: 41 | * If V(in) > V(out) then V(out) is unregulated (Vin=vout) 42 | * If V(in) < V(out) then V(out) is 12V regulated 43 | ** Li-Ion chemistry supported with hardware modification, consult manual. 44 | 45 | ## Documentation 46 | 47 | These devices allow advanced configuration which can be quite complex. It's recommended to read the documentation using the links below before attempting to configure these UPSes. 48 | 49 | - [OpenUPS ](https://resources.mini-box.com/online/PWR-OpenUPS/PWR-OpenUPS-hardware-manual.pdf) 50 | - [OpenUPS2 ](http://wiki.mini-box.com/index.php?title=OpenUPS2) 51 | - [NUC-UPS ](http://wiki.mini-box.com/index.php?title=NUC-UPS) 52 | - [DCDC-USB](https://resources.mini-box.com/online/PWR-DCDC-USB/PWR-DCDC-USB-Advanced-USB-configuration-manual.pdf) 53 | - [DCDC-USB-200](https://resources.mini-box.com/online/PWR-DCDC-USB-200/PWR-DCDC-USB-200-Advanced-USB-configuration-manual.pdf) 54 | 55 | 56 | ## Install from prebuilt binary 57 | 58 | $ sudo snap install openups --edge 59 | 60 | [![Get it from the Snap Store](https://snapcraft.io/static/images/badges/en/snap-store-white.svg)](https://snapcraft.io/openups) 61 | 62 | ([Don't have snapd installed?](https://snapcraft.io/docs/core/install)) 63 | 64 | ## Install from source 65 | 66 | $ git clone https://github.com/mini-box/ups.git 67 | $ cd ups 68 | $ cmake . 69 | $ sudo make install 70 | 71 | 72 | ## Using 73 | For all commands below replace *device name* with the name of the device you want to control eg: *openups*, *openups2*, *nucups* 74 | 75 | - Show help, supported devices and supported commands per device: 76 | 77 | $ openups -h 78 | 79 | - Show status and configuration: 80 | 81 | $ sudo openups -t 82 | - Show only status 83 | 84 | $ sudo openups -t -s 85 | - Export current configuration variables from device to file 86 | 87 | $ sudo openups -t -o 88 | 89 | - Import configuration from file to device. 90 | **Warning: it will restart your UPS and in certain cases the device connected to it !** 91 | 92 | $ sudo openups -t -i 93 | 94 | - For configuration variables you can add ```-c ``` switch on command line to output a detailed description for each variable. Example: 95 | ```6. UPS_INIT_DELAY_TOUT: 1 # [s] Initial delay before starting the UPS. Default is 1 sec. ``` 96 | 97 | - Some devices accept commands to set for example the output voltage: 98 | 99 | $ sudo openups -t dcdcusb -e set_vout:11.5 -s 100 | 101 | 102 | # Troubleshooting 103 | 104 | There might be issues with apparmor/SELinux that won't allow access to raw usb devices. 105 | For the snap binary this can be solved by: 106 | 107 | $ sudo snap connect openups:raw-usb 108 | 109 | # Network UPS Tools 110 | 111 | For remote management or shutdown configuration it's also possible to use [Network UPS Tools](https://networkupstools.org/). Open UPS and Open UPS 2 are already 112 | integrated in latest version so installation should be straight forward on different Linux flavors. 113 | For more details on custom installations and configuration for our UPS products on [Network UPS Tools](https://networkupstools.org/) see these links: 114 | - [Open UPS](https://github.com/mini-box/openups) 115 | - [Open UPS 2](https://github.com/mini-box/openups2) 116 | -------------------------------------------------------------------------------- /snap/snapcraft.yaml: -------------------------------------------------------------------------------- 1 | name: openups 2 | base: core20 # the base snap is the execution environment for this snap 3 | version: 'git' # just for humans, typically '1.2+git' or '1.3.2' 4 | version-script: cat src/version.h | grep VERSION | cut -f 3 -d " " | tr -d '"' 5 | summary: Control app for Mini-Box.com UPS products 6 | description: Allows displaying the status and configuring the settings for all UPS products from Mini-Box.com. These include Open UPS, Open UPS2, NUC UPS and more. 7 | 8 | grade: devel # must be 'stable' to release into candidate/stable channels 9 | confinement: strict # devmode # use 'strict' once you have the right plugs and slots 10 | 11 | apps: 12 | openups: 13 | plugs: [raw-usb] 14 | command: usr/local/bin/openups 15 | parts: 16 | openups: 17 | # See 'snapcraft plugins' 18 | plugin: cmake 19 | source: . 20 | source-type: local 21 | build-packages: 22 | - g++ 23 | - make 24 | - libusb-0.1-4 25 | - libusb-dev 26 | stage-packages: 27 | - libusb-0.1-4 -------------------------------------------------------------------------------- /src/devices.h: -------------------------------------------------------------------------------- 1 | #define MINIBOX_VENDOR_ID 0x04d8 2 | 3 | #define DCDCUSB_PRODUCT_ID 0xd003 4 | #define OPENUPS_PRODUCT_ID 0xd004 5 | #define OPENUPS2_PRODUCT_ID 0xd005 6 | #define NUCUPS_PRODUCT_ID 0xd007 7 | 8 | struct deviceId { 9 | const char *name; 10 | const char *desc; 11 | const unsigned int vendorid; 12 | const unsigned int productid; 13 | const unsigned int max_transfer_size; 14 | const struct deviceCmd *cmds; 15 | }; 16 | 17 | struct deviceCmd { 18 | const char *cmd; 19 | const char *desc; 20 | }; 21 | 22 | static const struct deviceCmd dcdc_usb_cmds[] = { 23 | { "set_vout", "Set Output Voltage" }, 24 | {} 25 | }; 26 | 27 | static const struct deviceId deviceIds[] = { 28 | { 29 | "dcdcusb", 30 | "DCDC USB", 31 | MINIBOX_VENDOR_ID, 32 | DCDCUSB_PRODUCT_ID, 33 | 24, 34 | dcdc_usb_cmds 35 | }, 36 | { 37 | "openups", 38 | "Open UPS", 39 | MINIBOX_VENDOR_ID, 40 | OPENUPS_PRODUCT_ID, 41 | 32, 42 | {} 43 | }, 44 | { 45 | "openups2", 46 | "Open UPS2", 47 | MINIBOX_VENDOR_ID, 48 | OPENUPS2_PRODUCT_ID, 49 | 32, 50 | {} 51 | }, 52 | { 53 | "nucups", 54 | "DC-DC NUC UPS", 55 | MINIBOX_VENDOR_ID, 56 | NUCUPS_PRODUCT_ID, 57 | 32, 58 | {} 59 | }, 60 | {} 61 | }; 62 | -------------------------------------------------------------------------------- /src/lib/HIDDCDCUSB.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nicu Pavel 3 | * Copyright (c) 2020 Mini-Box.com 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | * 7 | */ 8 | 9 | #include "HIDDCDCUSB.h" 10 | #include "util.h" 11 | #include 12 | 13 | #define A_SLEEP 5 14 | #define A_TIMEOUT 3000 15 | #define BUF_LINE_LEN 47 16 | #define STR_LINE_LEN 57 17 | 18 | #define PKG_LEN_LCD 64 19 | #define PKG_LEN_FLASH 37 20 | 21 | unsigned int g_DCDCUSB_memTerm[] = {(unsigned int)0x01}; 22 | 23 | ATXMSG g_DCDCUSB_memMessages[DCDCUSB_MAX_MESSAGE_CNT] = 24 | { 25 | {52, 1, _T("VOLTAGE_0"), true, 7, 0, 0, 0, _T("Set Output Voltage 0. Changes will take effect after a power cycle."), _T("[V]")}, 26 | {53, 1, _T("VOLTAGE_1"), true, 7, 0, 0, 0, _T("Set Output Voltage 1. Changes will take effect after a power cycle."), _T("[V]")}, 27 | {54, 1, _T("VOLTAGE_2"), true, 7, 0, 0, 0, _T("Set Output Voltage 2. Changes will take effect after a power cycle."), _T("[V]")}, 28 | {55, 1, _T("VOLTAGE_3"), true, 7, 0, 0, 0, _T("Set Output Voltage 3. Changes will take effect after a power cycle."), _T("[V]")}, 29 | {56, 1, _T("VOLTAGE_4"), true, 7, 0, 0, 0, _T("Set Output Voltage 4. Changes will take effect after a power cycle."), _T("[V]")}, 30 | {57, 1, _T("VOLTAGE_5"), true, 7, 0, 0, 0, _T("Set Output Voltage 5. Changes will take effect after a power cycle."), _T("[V]")}, 31 | {58, 1, _T("VOLTAGE_6"), true, 7, 0, 0, 0, _T("Set Output Voltage 6. Changes will take effect after a power cycle."), _T("[V]")}, 32 | {59, 1, _T("VOLTAGE_7"), true, 7, 0, 0, 0, _T("Set Output Voltage 7. Changes will take effect after a power cycle."), _T("[V]")}, 33 | 34 | {0, 1, _T("IGNITION_HIGH_LIMIT"), true, 2, 0.1558, 0, 0, _T("Above this voltage IGN is considered ON"), _T("[V]")}, 35 | {1, 1, _T("IGNITION_LOW_LIMIT"), true, 2, 0.1558, 0, 0, _T("Below this voltage IGN is considered OFF"), _T("[V]")}, 36 | {2, 1, _T("IGNITION_DEBOUNCE"), false, 1, 10, 0, 0, _T("Ignition filter de-bouncing"), _T("[ms]")}, 37 | 38 | {30, 1, _T("AUTOMOTIVE_IGNITION_CANCEL_TIME"), true, 1, 1, 0, 0, _T("After DCDC-USB \"boots\" in AUTOMOTIVE mode IGN is cancelled for this time"), _T("[sec]")}, 39 | {14, 1, _T("AUTOMOTIVE_THUMP_TIMEOUT"), true, 1, 1, 0, 0, _T("THUMP timeout, switching off the audio amplifier during motherboard startup/shutdown"), _T("[sec]")}, 40 | 41 | {3, 1, _T("DELAY_BEFORE_PSU_STARTUP"), true, 1, 1, 0, 0, _T("Initial startup delay to avoid re-cranking problems"), _T("[s]")}, 42 | {4, 1, _T("MIN_VIN_VOLTAGE_AT_STARTUP"), true, 2, 0.1558, 0, 0, _T("Input voltage STARTUP ZONE treshold "), _T("[V]")}, 43 | {5, 1, _T("MIN_VIN_VOLTAGE_WHILE_RUNNING"), true, 2, 0.1558, 0, 0, _T("Input voltage RUNNING ZONE treshold "), _T("[V]")}, 44 | {6, 1, _T("MAX_ALLOWED_VIN_VOLTAGE"), false, 2, 0.1558, 0, 0, _T("Input voltage, HIGH SHUTDOWN treshold [35V]"), _T("[V]")}, 45 | 46 | {63, 1, _T("MIN_VIN_VOLTAGE_DEEP_DISCHARGE"), true, 2, 0.1558, 0, 0, _T("Minimum VIN voltage measured during off delay"), _T("[V]")}, 47 | 48 | {7, 1, _T("ON_PULSE_DELAY"), true, 1, 1, 0, 0, _T("Delay between output is ON and startup pulse is sent\n(v4.3+)"), _T("[s]")}, 49 | // { 8, 1, _T("Min. limit for Voltage") , true, 2, 0.1558,0,0 , _T("MIN voltage treshold"), _T("[V]") }, 50 | {9, 1, _T("REGULATOR_OFFSET"), true, 1, 1, 0, 0, _T("Regulator offset (firmware version >= v2.0)"), _T("")}, 51 | {10, 2, _T("PSW_PUSH_DOWN_TIME"), true, 1, 10, 0, 0, _T("How long the PSW button is pressed down"), _T("[ms]")}, 52 | //{11, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 53 | // { 12, 1, _T("Emergency timeout") , true, 1, 1,0,0 , _T("Delay"), _T("[s]") }, 54 | {13, 1, _T("CONFIGURATION_FLAGS"), true, 9, 1, 0, 0, _T("Configuration flags: bit0=Regulator Enabled/Disabled(v2.0+)\nbit1=Power cycle On/Off(v2.1+)\nbit2=On pulse enable/disable bit3=Off pulse enable/disable(v3.1+)\nbit4=USB sense enable/disable(v4.0+)\nbit5=Ignition pulse enable/disable(v4.2+)"), _T("")}, 55 | {15, 1, _T("MAX_REGULATION_STEP_NUMBER"), true, 1, 1, 0, 0, _T("Maximum allowed regulation step number (0-255) (firmware version >= v2.0)"), _T("")}, 56 | 57 | {16, 2, _T("OFF_DELAY_TIME_0"), false, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 0 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 58 | //{17, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 59 | {18, 2, _T("HARD_OFF_TIME_0"), false, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 0 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 60 | //{19, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 61 | {20, 2, _T("OFF_DELAY_TIME_1"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 1 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 62 | //{21, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 63 | {22, 2, _T("HARD_OFF_TIME_1"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 1 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 64 | //{23, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 65 | {24, 2, _T("OFF_DELAY_TIME_2"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 2 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 66 | //{25, 0, _T("FILLER") , true, 1, 1 , _T(""), _T("") }, 67 | {26, 2, _T("HARD_OFF_TIME_2"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 2 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 68 | //{27, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 69 | {28, 2, _T("OFF_DELAY_TIME_3"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 3 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 70 | //{29, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 71 | 72 | {32, 2, _T("HARD_OFF_TIME_3"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 3 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 73 | //{33, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 74 | {34, 2, _T("OFF_DELAY_TIME_4"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 4 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 75 | //{35, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 76 | {36, 2, _T("HARD_OFF_TIME_4"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 4 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 77 | //{37, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 78 | {38, 2, _T("OFF_DELAY_TIME_5"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 5 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 79 | //{39, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 80 | {40, 2, _T("HARD_OFF_TIME_5"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 5 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 81 | //{41, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 82 | {42, 2, _T("OFF_DELAY_TIME_6"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 6 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 83 | //{43, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 84 | {44, 2, _T("HARD_OFF_TIME_6"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 6 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 85 | //{45, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 86 | 87 | {48, 2, _T("OFF_DELAY_TIME_7"), true, 3, 1, 0, 0, _T("Time between IGN OFF to PSW OFF impulse in Time Configuration 7 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 88 | //{49, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 89 | {50, 2, _T("HARD_OFF_TIME_7"), true, 3, 1, 0, 0, _T("Time Between PSW OFF to Output OFF,Hardware OFF in Time Configuration 7 (max. 17:59:59 or Never)"), _T("[hh:mm:ss]")}, 90 | //{51, 0, _T("FILLER") , true, 1, 1,0,0 , _T(""), _T("") }, 91 | 92 | {46, 1, _T("UPS_MODE_SHUTDOWN_TIME"), true, 1, 1, 0, 0, _T("After OFF impulse is sent wait \"UPS Mode: Shutdown Time\" till Output OFF,Hardware OFF"), _T("[sec]")}, 93 | {47, 1, _T("UPS_MODE_IGNITION_OFF_TIME"), true, 1, 1, 0, 0, _T("If IGN is OFF for \"UPS Mode: Ignition OFF time\" time the PSU will send OFF impulse"), _T("[sec]")}, 94 | 95 | {60, 1, _T("UPS_MODE_IGNITION_ON"), true, 2, 0.1558, 0, 0, _T("PSU will be ON if IGN>\"UPS Mode: Ignition ON\" (and VIN>\"UPS Mode: VIn Good\")"), _T("[V]")}, 96 | {61, 1, _T("UPS_MODE_IGNITION_OFF"), true, 2, 0.1558, 0, 0, _T("PSU will be OFF if IGN<\"UPS Mode: Ignition OFF\" for \"UPS Mode: Ignition OFF time\" seconds"), _T("[V]")}, 97 | {62, 1, _T("UPS_MODE_VIN_GOOD"), true, 2, 0.1558, 0, 0, _T("PSU will be ON if VIN>\"UPS Mode: VIn Good\" (and IGN>\"UPS Mode: Ignition ON\")"), _T("[V]")}, 98 | }; 99 | 100 | double HIDDCDCUSB::GetVOut(unsigned char data) 101 | { 102 | double rpot = ((double)data) * DCDCUSB_CT_RP / (double)257 + DCDCUSB_CT_RW; 103 | double voltage = (double)80 * ((double)1 + DCDCUSB_CT_R1 / (rpot + DCDCUSB_CT_R2)); 104 | voltage = floor(voltage); 105 | return voltage / 100; 106 | } 107 | 108 | unsigned char HIDDCDCUSB::ConvertVoltageToChar(double vout) 109 | { 110 | if (vout < 5) 111 | vout = 5; 112 | 113 | if (vout > 25) 114 | vout = 25; 115 | 116 | double rpot = (double)0.8 * DCDCUSB_CT_R1 / (vout - (double)0.8) - DCDCUSB_CT_R2; 117 | double result = (257 * (rpot - DCDCUSB_CT_RW) / DCDCUSB_CT_RP); 118 | 119 | if (result < 0) 120 | result = 0; 121 | if (result > 255) 122 | result = 255; 123 | 124 | return (unsigned char)result; 125 | } 126 | 127 | HIDDCDCUSB::HIDDCDCUSB(USBHID *d) : HIDInterface(d) 128 | { 129 | m_ulSettingsAddr = DCDCUSB_SETTINGS_ADDR_START; 130 | } 131 | 132 | HIDDCDCUSB::~HIDDCDCUSB() 133 | { 134 | } 135 | 136 | ATXMSG *HIDDCDCUSB::GetMessages() 137 | { 138 | return g_DCDCUSB_memMessages; 139 | } 140 | 141 | double HIDDCDCUSB::GetConstant(int i) 142 | { 143 | return 1.0; 144 | } 145 | 146 | unsigned int *HIDDCDCUSB::GetTermistorConsts() 147 | { 148 | return g_DCDCUSB_memTerm; 149 | } 150 | 151 | void HIDDCDCUSB::printValues() 152 | { 153 | fprintf(stdout, "Mode: %d %s\n", m_nMode, m_strMode); 154 | fprintf(stdout, " Configured Voltage Ouput: %.02f\n", m_fVOutSet); 155 | fprintf(stdout, " Voltage Config: %d\n V In: %.02f\n V Ign: %.02f\n V Out: %.02f\n", m_nVoltageCfg, m_fVIn, m_fIgn, m_fVOut); 156 | fprintf(stdout, " Power Switch: %d\n Output: %d\n Aux V In: %d\n", m_bPowerSwitch, m_bOutput, m_bAuxVin); 157 | fprintf(stdout, " Version: %d.%d\n State: 0x%02x\n", m_nVerMajor, m_nVerMinor, m_nState); 158 | fprintf(stdout, " Voltage (flags): %s\n Status 1 (flags): %s\n Status 2 (flags): %s\n", m_strFlagsVoltage, m_strFlagsStatus1, m_strFlagsStatus2); 159 | fprintf(stdout, " Timer (flags): %s\n Timer Config: 0x%02x\n Voltage Config: %s\n", m_strFlagsTimer, m_nTimeCfg, m_strVoltCfg); 160 | fprintf(stdout, " Timer Wait: %s\n Timer V Out: %s\n Timer PW Switch: %s\n", m_strTimerWait, m_strTimerVout, m_strTimerPwSwitch); 161 | fprintf(stdout, " Timer V Aux: %s\n Timer Off Delay: %s\n Timer Hard Off: %s\n", m_strTimerVAux, m_strTimerOffDelay, m_strTimerHardOff); 162 | } 163 | 164 | void HIDDCDCUSB::parseMessage(unsigned char *msg) 165 | { 166 | if (!msg) 167 | return; 168 | 169 | switch (msg[0]) 170 | { 171 | case DCDCUSB_INTERNAL_MESG: 172 | { 173 | switch (msg[1]) 174 | { 175 | case DCDCUSB_INTERNAL_MESG_DISCONNECTED: 176 | { 177 | fprintf(stderr, "DCDCUSB DEVICE DISCONNECTED!"); 178 | } 179 | break; 180 | } 181 | } 182 | break; 183 | case DCDCUSB_RECV_ALL_VALUES: 184 | { 185 | m_nState = msg[2]; 186 | m_nTimeCfg = (msg[1] >> 5) & 0x7; 187 | m_nVoltageCfg = (msg[1] >> 2) & 0x7; 188 | 189 | float val; 190 | //VIN 191 | m_fVIn = (float)msg[3] * (float)0.1558; 192 | 193 | //Ign 194 | m_fIgn = (float)msg[4] * (float)0.1558; 195 | 196 | //VOut 197 | m_fVOut = (float)msg[5] * (float)0.1170; 198 | 199 | int status1 = msg[6]; 200 | if (status1 & 0x4) 201 | m_bPowerSwitch = true; 202 | else 203 | m_bPowerSwitch = false; 204 | 205 | if (status1 & 0x8) 206 | m_bOutput = true; 207 | else 208 | m_bOutput = false; 209 | 210 | if (status1 & 0x10) 211 | m_bAuxVin = true; 212 | else 213 | m_bAuxVin = false; 214 | 215 | char2bin(m_strFlagsStatus1, msg[6]); 216 | char2bin(m_strFlagsStatus2, msg[7]); 217 | char2bin(m_strFlagsVoltage, msg[8]); 218 | char2bin(m_strFlagsTimer, msg[9]); 219 | 220 | m_nScriptPointer = msg[10]; 221 | 222 | convertOneValue2String(m_strTimerWait, 2, 11, 3, 1); 223 | convertOneValue2String(m_strTimerVout, 2, 13, 3, 1); 224 | convertOneValue2String(m_strTimerVAux, 2, 15, 3, 1); 225 | convertOneValue2String(m_strTimerPwSwitch, 2, 17, 3, 1); 226 | convertOneValue2String(m_strTimerOffDelay, 2, 19, 3, 1); 227 | convertOneValue2String(m_strTimerHardOff, 2, 21, 3, 1); 228 | 229 | m_bVersion = msg[23]; 230 | m_nVerMajor = (msg[23] >> 5) & 0x07; 231 | m_nVerMinor = msg[23] & 0x1F; 232 | m_nMode = (msg[1]) & 0x3; 233 | 234 | switch ((msg[1]) & 0x3) 235 | { 236 | case 0: 237 | strcpy(m_strMode, "(Dumb)"); 238 | break; 239 | case 1: 240 | strcpy(m_strMode, "(Automotive)"); 241 | break; 242 | case 2: 243 | strcpy(m_strMode, "(Script)"); 244 | break; 245 | case 3: 246 | strcpy(m_strMode, "(UPS)"); 247 | break; 248 | } 249 | } 250 | break; 251 | case DCDCUSB_CMD_IN: 252 | { 253 | if (msg[1] != 0) 254 | { 255 | if (msg[2] == DCDCUSB_CMD_READ_REGULATOR_STEP) 256 | fprintf(stdout, "Regulator: undefined"); 257 | else 258 | fprintf(stderr, "Error %d for message %02X", msg[1], msg[2]); 259 | } 260 | else 261 | { 262 | switch (msg[2]) 263 | { 264 | case DCDCUSB_CMD_WRITE_VOUT: 265 | case DCDCUSB_CMD_READ_VOUT: 266 | case DCDCUSB_CMD_INC_VOUT: 267 | case DCDCUSB_CMD_DEC_VOUT: 268 | { 269 | m_fVOutSet = HIDDCDCUSB::GetVOut(msg[3]); 270 | } 271 | break; 272 | case DCDCUSB_CMD_READ_REGULATOR_STEP: 273 | { 274 | fprintf(stdout, "Regulator Step: %d", msg[3]); 275 | } 276 | break; 277 | } 278 | } 279 | } 280 | break; 281 | case DCDCUSB_MEM_READ_IN: 282 | { 283 | //TX[24]:A1 C0 3F 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 284 | //RX[24]:A2 C0 3F 00 10 26 24 32 05 26 23 E0 AA 00 03 00 32 0A 00 AA AA 00 00 01 285 | memcpy(m_chPackages + (m_ulSettingsAddr - DCDCUSB_SETTINGS_ADDR_START), msg + 5, 16); 286 | } 287 | break; 288 | } 289 | } 290 | 291 | float HIDDCDCUSB::convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier) 292 | { 293 | double value = -1; 294 | 295 | if (nLen == 1) 296 | { 297 | value = (double)buffer[nIndex] * dMultiplier; 298 | } 299 | else 300 | { 301 | value = (double)((((int)buffer[nIndex]) << 8) | buffer[nIndex + 1]) * dMultiplier; 302 | } 303 | 304 | switch (nReadMode) 305 | { 306 | case 5: 307 | { 308 | if (nLen == 1) 309 | value = (double)((char)buffer[nIndex]) * dMultiplier; 310 | else 311 | value = (double)((((int)((char)buffer[nIndex])) << 8) | buffer[nIndex + 1]) * dMultiplier; 312 | } 313 | break; 314 | 315 | case 7: 316 | { 317 | //no multiplier - voltage value calculated with formula 318 | value = HIDDCDCUSB::GetVOut(buffer[nIndex]); 319 | } 320 | break; 321 | } 322 | 323 | return (float)value; 324 | } 325 | 326 | bool HIDDCDCUSB::readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4) 327 | { 328 | bool ok = false; 329 | c1 = 0; 330 | c2 = 0; 331 | 332 | double val = 0; 333 | 334 | switch (nReadMode) 335 | { 336 | case 3: 337 | { //hh:mm:ss 338 | if (strcmp(str, "Never") == 0) 339 | { 340 | val = 0xFFFF; 341 | ok = true; 342 | } 343 | else if ((strlen(str) == 8) && (str[2] == ':') && (str[5] == ':')) 344 | { 345 | _TCHAR *end = NULL; 346 | char temps[10]; 347 | str_left(temps, str, 2); 348 | int hh = _tcstol(temps, &end, 10); 349 | if ((end != temps) && (hh >= 0) && (hh < 18)) 350 | { 351 | str_mid(temps, str, 3, 2); 352 | int mm = _tcstol(temps, &end, 10); 353 | if ((end != temps) && (mm >= 0) && (mm < 60)) 354 | { 355 | str_right(temps, str, 2); 356 | int ss = _tcstol(temps, &end, 10); 357 | 358 | if ((end != temps) && (ss >= 0) && (ss < 60)) 359 | { 360 | val = hh * 3600 + mm * 60 + ss; 361 | ok = true; 362 | } 363 | } 364 | } 365 | } 366 | } 367 | break; 368 | case 4: 369 | { //"signed" float 370 | if (strlen(str) != 0) 371 | { 372 | bool negative = false; 373 | char temps[10]; 374 | char temps2[10]; 375 | 376 | if (str[0] == '-') 377 | { 378 | str_right(temps, str, strlen(str) - 1); 379 | str = temps; 380 | negative = true; 381 | } 382 | 383 | _TCHAR *end = NULL; 384 | str_left(temps2, str, 8); 385 | val = _tcstod(temps2, &end); 386 | 387 | if ((end != temps2)) 388 | { 389 | ok = true; 390 | 391 | val /= dMultiplier; 392 | if (val < 0) 393 | val = 0; 394 | double rem = val - (int)val; 395 | unsigned long uval = (unsigned long)val; 396 | if (rem >= 0.5) 397 | uval += 1; 398 | 399 | if (uval > 0x7F) 400 | uval = 0x7F; 401 | 402 | c1 = 0; 403 | c2 = (unsigned char)uval; 404 | if (negative) 405 | c2 |= 0x80; 406 | } 407 | } 408 | } 409 | break; 410 | case 6: 411 | { 412 | val = 0xFF; 413 | ok = true; 414 | } 415 | break; 416 | case 7: 417 | { 418 | _TCHAR *end = NULL; 419 | char temps[10]; 420 | str_left(temps, str, 8); 421 | val = _tcstod(temps, &end); 422 | 423 | if ((val < 5) || (val > 25.53)) 424 | { 425 | ok = false; 426 | } 427 | else 428 | { 429 | c1 = 0; 430 | c2 = ConvertVoltageToChar(val); 431 | ok = true; 432 | } 433 | } 434 | break; 435 | case 8: 436 | { 437 | if (strcmp(str, "Never") == 0) 438 | { 439 | val = (double)0xFFFF * dMultiplier; 440 | ok = true; 441 | } 442 | else 443 | { 444 | TCHAR *end = NULL; 445 | char temps[10]; 446 | str_left(temps, str, 8); 447 | val = _tcstod(temps, &end); 448 | if (end != temps) 449 | ok = true; 450 | } 451 | } 452 | break; 453 | case 9: 454 | { 455 | c1 = 0; 456 | c2 = bin2char(str, &ok); 457 | } 458 | break; 459 | case 1: 460 | //normal read - integer 461 | case 2: 462 | case 5: 463 | default: 464 | { //normal read - float 465 | _TCHAR *end = NULL; 466 | char temps[10]; 467 | str_left(temps, str, 8); 468 | val = _tcstod(temps, &end); 469 | 470 | // CString err; 471 | // err.Format("Convert: (%f) (%d) (%s)",val, errno, str.Left(8)); 472 | // AfxMessageBox(err); 473 | 474 | if (end != temps) 475 | ok = true; 476 | } 477 | } 478 | 479 | if (ok) 480 | { 481 | if ((nReadMode != 4) && (nReadMode != 7) && (nReadMode != 9)) 482 | { 483 | val /= dMultiplier; 484 | 485 | if (nReadMode != 5) 486 | { //unsigned 487 | if (val < 0) 488 | val = 0; 489 | double rem = val - (int)val; 490 | unsigned long uval = (unsigned long)val; 491 | if (rem >= 0.5) 492 | uval += 1; 493 | 494 | if (len == 1) 495 | { 496 | if (uval > 0xFF) 497 | uval = 0xFF; 498 | 499 | c1 = 0; 500 | c2 = (unsigned char)uval; 501 | } 502 | else 503 | { 504 | if (uval > 0xFFFF) 505 | uval = 0xFFFF; 506 | 507 | c1 = (unsigned char)((((unsigned int)uval) >> 8) & 0xFF); 508 | c2 = (unsigned char)(((unsigned int)uval) & 0xFF); 509 | } 510 | } 511 | else 512 | { 513 | double rem = -val + (int)val; 514 | long uval = (long)val; 515 | if (rem >= 0.5) 516 | uval += 1; 517 | 518 | if (len == 1) 519 | { 520 | if (uval > 127) 521 | uval = 127; 522 | if (uval < -128) 523 | uval = -128; 524 | 525 | c1 = 0; 526 | c2 = (char)uval; 527 | } 528 | else 529 | { 530 | if (uval > 32767) 531 | uval = 32767; 532 | if (uval < -32768) 533 | uval = -32768; 534 | 535 | c1 = (char)((((int)uval) >> 8) & 0xFF); 536 | c2 = (char)(((int)uval) & 0xFF); 537 | } 538 | } 539 | } 540 | } 541 | 542 | //fprintf(stderr, "readOneValue: readMode: %d c1: 0x%02x c2: 0x%02x\n", nReadMode, c1, c2); 543 | 544 | return ok; 545 | } 546 | 547 | void HIDDCDCUSB::convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier) 548 | { 549 | destination[0] = 0; //empty string 550 | double value = 0; 551 | 552 | if (nLen == 1) 553 | { 554 | value = (double)m_chPackages[nIndex] * dMultiplier; 555 | } 556 | else 557 | { 558 | value = (double)((((int)m_chPackages[nIndex]) << 8) | m_chPackages[nIndex + 1]) * dMultiplier; 559 | } 560 | 561 | switch (nReadMode) 562 | { 563 | case 2: 564 | sprintf(destination, "%.2f", (float)value); 565 | break; 566 | case 3: 567 | { 568 | unsigned int ivalue = (unsigned int)value; 569 | if (ivalue == 0xFFFF) 570 | strcpy(destination, "Never"); 571 | else 572 | sprintf(destination, "%02d:%02d:%02d", ivalue / 3600, (ivalue / 60) % 60, ivalue % 60); 573 | } 574 | break; 575 | case 4: 576 | { 577 | double dvalue = (m_chPackages[nIndex] & 0x7f) * dMultiplier; 578 | 579 | if ((m_chPackages[nIndex] & 0x80) != 0) 580 | sprintf(destination, "-%.3f", (float)dvalue); 581 | else 582 | sprintf(destination, "%.3f", (float)value); 583 | } 584 | break; 585 | case 5: 586 | { 587 | if (nLen == 1) 588 | value = (double)((char)m_chPackages[nIndex]) * dMultiplier; 589 | else 590 | value = (double)((((int)((char)m_chPackages[nIndex])) << 8) | m_chPackages[nIndex + 1]) * dMultiplier; 591 | 592 | sprintf(destination, "%d", (int)value); 593 | } 594 | break; 595 | case 6: 596 | { 597 | strcpy(destination, "-"); 598 | } 599 | break; 600 | case 7: 601 | { //no multiplier - voltage value calcualted with formula 602 | sprintf(destination, "%.3f", HIDDCDCUSB::GetVOut(m_chPackages[nIndex])); 603 | } 604 | break; 605 | case 8: 606 | { 607 | if (nLen == 1) 608 | { 609 | if (m_chPackages[nIndex] == 0xFF) 610 | strcpy(destination, "Never"); 611 | else 612 | sprintf(destination, "%d", (int)value); 613 | } 614 | else 615 | { 616 | if ((m_chPackages[nIndex] == 0xFF) && (m_chPackages[nIndex + 1] == 0xFF)) 617 | strcpy(destination, "Never"); 618 | else 619 | sprintf(destination, "%d", (int)value); 620 | } 621 | } 622 | break; 623 | case 9: 624 | char2bin(destination, m_chPackages[nIndex]); 625 | break; 626 | case 1: 627 | default: 628 | { 629 | sprintf(destination, "%d", (int)value); 630 | } 631 | } 632 | 633 | //DBGOutput("convertOneValue2String %d %s %f [%x][%x]\n",nIndex,destination,(float)value,(int)m_chPackages[nIndex],(int)m_chPackages[nIndex+1]); 634 | } 635 | 636 | bool HIDDCDCUSB::setVariableData(int mesg_no, char *str) 637 | { 638 | int len = GetMessages()[mesg_no].nLen; 639 | 640 | if (len != 0) 641 | { 642 | unsigned char c1 = 0; 643 | unsigned char c2 = 0; 644 | unsigned char c3 = 0; 645 | unsigned char c4 = 0; 646 | 647 | if (readOneValue(str, GetMessages()[mesg_no].nReadMode, GetMessages()[mesg_no].dMultiplier, len, c1, c2, c3, c4)) 648 | { 649 | switch (len) 650 | { 651 | case 1: 652 | m_chPackages[GetMessages()[mesg_no].nIndex] = c2; 653 | break; 654 | case 2: 655 | m_chPackages[GetMessages()[mesg_no].nIndex] = c1; 656 | m_chPackages[GetMessages()[mesg_no].nIndex + 1] = c2; 657 | break; 658 | case 4: 659 | m_chPackages[GetMessages()[mesg_no].nIndex] = c1; 660 | m_chPackages[GetMessages()[mesg_no].nIndex + 1] = c2; 661 | m_chPackages[GetMessages()[mesg_no].nIndex + 2] = c3; 662 | m_chPackages[GetMessages()[mesg_no].nIndex + 3] = c4; 663 | break; 664 | } 665 | return 1; 666 | } 667 | else 668 | return 0; 669 | } 670 | return 1; 671 | } 672 | 673 | unsigned char HIDDCDCUSB::getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment) 674 | { 675 | if ((cnt < 0) || (cnt >= DCDCUSB_MAX_MESSAGE_CNT)) 676 | return 0; 677 | 678 | if (HIDDCDCUSB::GetMessages()[cnt].nLen == 0) 679 | return 0; 680 | 681 | if (name) 682 | strcpy(name, HIDDCDCUSB::GetMessages()[cnt].strName); 683 | if (unit) 684 | strcpy(unit, HIDDCDCUSB::GetMessages()[cnt].strUnit); 685 | if (comment) 686 | strcpy(comment, HIDDCDCUSB::GetMessages()[cnt].strText); 687 | 688 | if (value) 689 | { 690 | convertOneValue2String(value, HIDDCDCUSB::GetMessages()[cnt].nLen, 691 | HIDDCDCUSB::GetMessages()[cnt].nIndex, 692 | HIDDCDCUSB::GetMessages()[cnt].nReadMode, 693 | HIDDCDCUSB::GetMessages()[cnt].dMultiplier); 694 | } 695 | 696 | return HIDDCDCUSB::GetMessages()[cnt].nReadMode; 697 | } 698 | 699 | void HIDDCDCUSB::restartUPS() 700 | { 701 | } 702 | 703 | void HIDDCDCUSB::restartUPSInBootloaderMode() 704 | { 705 | } 706 | 707 | void HIDDCDCUSB::setVOutVolatile(char *param) { 708 | 709 | if (!param) 710 | return; 711 | 712 | double voltage; 713 | char *end, temps[10]; 714 | unsigned char val; 715 | 716 | voltage = strtod(param, &end); 717 | fprintf(stderr, "Setting VOut voltage to: %lf\n", voltage); 718 | val = ConvertVoltageToChar(voltage); 719 | 720 | sendMessage(DCDCUSB_CMD_OUT, 3, DCDCUSB_CMD_WRITE_VOUT, val, 0); 721 | } 722 | 723 | void HIDDCDCUSB::setVOutVolatile(float vout) 724 | { 725 | unsigned char val = ConvertVoltageToChar(vout); 726 | sendMessage(DCDCUSB_CMD_OUT, 3, DCDCUSB_CMD_WRITE_VOUT, val, 0); 727 | } 728 | 729 | void HIDDCDCUSB::incDecVOutVolatile(unsigned char inc) 730 | { 731 | } 732 | 733 | void HIDDCDCUSB::GetStatus() 734 | { 735 | unsigned char recv[32]; 736 | int ret; 737 | 738 | sendMessage(DCDCUSB_GET_ALL_VALUES, 0); 739 | recvMessage(recv); 740 | parseMessage(recv); 741 | 742 | sendMessage(DCDCUSB_CMD_OUT, 3, DCDCUSB_CMD_READ_VOUT, 0, 0); 743 | recvMessage(recv); 744 | parseMessage(recv); 745 | } 746 | 747 | void HIDDCDCUSB::ReadConfigurationMemory() 748 | { 749 | unsigned char recv[32]; 750 | 751 | m_ulSettingsAddr = DCDCUSB_SETTINGS_ADDR_START; 752 | memset(m_chPackages, 0, DCDCUSB_SETTINGS_PACKS * 16); 753 | 754 | while (m_ulSettingsAddr < DCDCUSB_SETTINGS_ADDR_END) 755 | { 756 | int ret = sendMessage(DCDCUSB_MEM_READ_OUT, 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x10); 757 | recvMessage(recv); 758 | parseMessage(recv); 759 | m_ulSettingsAddr += 16; 760 | } 761 | } 762 | 763 | void HIDDCDCUSB::EraseConfigurationMemory() 764 | { 765 | unsigned char recv[32]; 766 | int ret; 767 | 768 | m_ulSettingsAddr = DCDCUSB_SETTINGS_ADDR_START; 769 | sendMessage(DCDCUSB_MEM_ERASE, 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x40); 770 | 771 | int retries = 5; 772 | while ((ret = recvMessage(recv) <= 0) && retries > 0) 773 | { 774 | retries--; 775 | usleep(500); 776 | fprintf(stderr, "Erase 0x%02x retry %d/5\n", recv[0], retries); 777 | } 778 | 779 | if (retries <= 0) 780 | { 781 | fprintf(stderr, "Error waiting for erase operation to finish\n"); 782 | } 783 | else 784 | { 785 | fprintf(stderr, "Successfully erased (0x%02x) configuration memory\n", recv[0]); 786 | } 787 | } 788 | 789 | void HIDDCDCUSB::WriteConfigurationMemory() 790 | { 791 | unsigned char recv[32]; 792 | int ret; 793 | 794 | m_ulSettingsAddr = DCDCUSB_SETTINGS_ADDR_START; 795 | while (m_ulSettingsAddr < DCDCUSB_SETTINGS_ADDR_END) 796 | { 797 | sendMessageWithBuffer(DCDCUSB_MEM_WRITE_OUT, 16, m_chPackages + (m_ulSettingsAddr - DCDCUSB_SETTINGS_ADDR_START), 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x10); 798 | ret = recvMessage(recv); 799 | 800 | if (ret <= 0) 801 | { 802 | fprintf(stderr, "Error (%d, 0x%02x) writing configuration variables , aborting ...\n", ret, recv[0]); 803 | break; 804 | } 805 | else 806 | { 807 | //fprintf(stderr, "Wrote page 0x%lx of configuration\n", m_ulSettingsAddr); 808 | } 809 | m_ulSettingsAddr += 16; 810 | } 811 | } 812 | 813 | bool HIDDCDCUSB::executeCommand(char *cmdexpr) { 814 | fprintf(stdout, "Executing command and params: %s\n", cmdexpr); 815 | struct EXEC *exec = parseCommand(cmdexpr); 816 | bool executed = false; 817 | 818 | if ((strcmp(exec->cmd, "set_vout") == 0) && (exec->params_count > 0)) { 819 | setVOutVolatile(exec->params[0]); 820 | executed = true; 821 | } else { 822 | fprintf(stderr, "Unknown command: %s\n", exec->cmd); 823 | } 824 | 825 | free(exec); 826 | return executed; 827 | } -------------------------------------------------------------------------------- /src/lib/HIDDCDCUSB.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ifndef _HIDDCDCUSB_H_ 4 | #define _HIDDCDCUSB_H_ 5 | 6 | #include "HIDInterface.h" 7 | #include "usbhid.h" 8 | 9 | #define MAX_BUF 500 10 | 11 | class HIDGraphics; 12 | 13 | #define STATUS_OK 0x00 14 | #define STATUS_ERASE 0x01 15 | #define STATUS_WRITE 0x02 16 | #define STATUS_READ 0x03 17 | #define STATUS_ERROR 0xff 18 | 19 | #define DCDCUSB_SETTINGS_ADDR_START 0x003FC0 20 | #define DCDCUSB_SETTINGS_ADDR_END 0x004000 21 | #define DCDCUSB_SETTINGS_PACKS 4 22 | 23 | #define DCDCUSB_GET_ALL_VALUES 0x81 24 | #define DCDCUSB_RECV_ALL_VALUES 0x82 25 | #define DCDCUSB_CMD_OUT 0xB1 26 | #define DCDCUSB_CMD_IN 0xB2 27 | #define DCDCUSB_MEM_READ_OUT 0xA1 28 | #define DCDCUSB_MEM_READ_IN 0xA2 29 | #define DCDCUSB_MEM_WRITE_OUT 0xA3 30 | #define DCDCUSB_MEM_WRITE_IN 0xA4 31 | #define DCDCUSB_MEM_ERASE 0xA5 32 | 33 | #define DCDCUSB_INTERNAL_MESG 0xFF 34 | #define DCDCUSB_INTERNAL_MESG_DISCONNECTED 0x01 35 | 36 | #define DCDCUSB_CMD_SET_AUX_WIN 0x01 37 | #define DCDCUSB_CMD_SET_PW_SWITCH 0x02 38 | #define DCDCUSB_CMD_SET_OUTPUT 0x03 39 | #define DCDCUSB_CMD_WRITE_VOUT 0x06 40 | #define DCDCUSB_CMD_READ_VOUT 0x07 41 | #define DCDCUSB_CMD_INC_VOUT 0x0C 42 | #define DCDCUSB_CMD_DEC_VOUT 0x0D 43 | #define DCDCUSB_CMD_LOAD_DEFAULTS 0x0E 44 | #define DCDCUSB_CMD_SCRIPT_START 0x10 45 | #define DCDCUSB_CMD_SCRIPT_STOP 0x11 46 | #define DCDCUSB_CMD_SLEEP 0x12 47 | #define DCDCUSB_CMD_READ_REGULATOR_STEP 0x13 48 | 49 | //For reading out memory 50 | #define DCDCUSB_TYPE_CODE_MEMORY 0x00 51 | #define DCDCUSB_TYPE_EPROM_EXTERNAL 0x01 52 | #define DCDCUSB_TYPE_EPROM_INTERNAL 0x02 53 | #define DCDCUSB_TYPE_CODE_SPLASH 0x03 54 | 55 | #define DCDCUSB_FLASH_REPORT_ERASE_MEMORY 0xF2 // AddressLo : AddressHi : AddressUp (anywhere inside the 64 byte-block to be erased) 56 | #define DCDCUSB_FLASH_REPORT_READ_MEMORY 0xF3 // AddressLo : AddressHi : AddressUp : Data Length (1...32) 57 | #define DCDCUSB_FLASH_REPORT_WRITE_MEMORY 0xF4 // AddressLo : AddressHi : AddressUp : Data Length (1...32) : Data.... 58 | #define DCDCUSB_KEYBD_REPORT_ERASE_MEMORY 0xB2 // same as F2 but in keyboard mode 59 | #define DCDCUSB_KEYBD_REPORT_READ_MEMORY 0xB3 // same as F3 but in keyboard mode 60 | #define DCDCUSB_KEYBD_REPORT_WRITE_MEMORY 0xB4 // same as F4 but in keyboard mode 61 | #define DCDCUSB_KEYBD_REPORT_MEMORY 0x41 // response to b3,b4 62 | 63 | #define IN_REPORT_EXT_EE_DATA 0x31 64 | #define OUT_REPORT_EXT_EE_READ 0xA1 65 | #define OUT_REPORT_EXT_EE_WRITE 0xA2 66 | 67 | #define IN_REPORT_INT_EE_DATA 0x32 68 | #define OUT_REPORT_INT_EE_READ 0xA3 69 | #define OUT_REPORT_INT_EE_WRITE 0xA4 70 | 71 | ///// MEASUREMENT CONSTANTS 72 | #define DCDCUSB_CT_RW (double)75 73 | #define DCDCUSB_CT_R1 (double)49900 74 | #define DCDCUSB_CT_R2 (double)1500 75 | #define DCDCUSB_CT_RP (double)10000 76 | 77 | #define CHECK_CHAR (unsigned char)0xAA //used for line/write check 78 | 79 | #define DCDCUSB_MAX_MESSAGE_CNT 64 80 | 81 | ///// 82 | class HIDDCDCUSB : public HIDInterface 83 | { 84 | 85 | public: 86 | HIDDCDCUSB(USBHID *d); 87 | virtual ~HIDDCDCUSB(); 88 | 89 | void parseMessage(unsigned char *msg); 90 | void printValues(); 91 | void printConfiguration(); 92 | bool executeCommand(char *cmdexpr); 93 | 94 | bool readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4); 95 | float convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier); 96 | void convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier); 97 | bool setVariableData(int mesg_no, char *str); 98 | ATXMSG *GetMessages(); 99 | double GetConstant(int i); 100 | unsigned int *GetTermistorConsts(); 101 | int GetMessageIdxByName(const char *name); 102 | unsigned char getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment); 103 | void restartUPS(); 104 | void restartUPSInBootloaderMode(); 105 | 106 | void GetStatus(); 107 | void ReadConfigurationMemory(); 108 | void EraseConfigurationMemory(); 109 | void WriteConfigurationMemory(); 110 | 111 | 112 | 113 | private: 114 | int m_nVoltageCfg; 115 | float m_fVIn; 116 | float m_fIgn; 117 | float m_fVOut; 118 | float m_fVOutSet; 119 | bool m_bPowerSwitch; 120 | bool m_bOutput; 121 | bool m_bAuxVin; 122 | bool m_bVersion; 123 | 124 | int m_nScriptPointer; 125 | unsigned char m_nVerMajor; 126 | unsigned char m_nVerMinor; 127 | int m_nMode; 128 | int m_nState; 129 | int m_nTimeCfg; 130 | 131 | char m_strFlagsVoltage[256]; 132 | char m_strFlagsStatus1[256]; 133 | char m_strFlagsStatus2[256]; 134 | char m_strFlagsTimer[256]; 135 | char m_strVoltCfg[256]; 136 | char m_strMode[256]; 137 | char m_strTimerWait[256]; 138 | char m_strTimerVout[256]; 139 | char m_strTimerPwSwitch[256]; 140 | char m_strFlashPointer[256]; 141 | char m_strTimerVAux[256]; 142 | char m_strTimerOffDelay[256]; 143 | char m_strTimerHardOff[256]; 144 | char m_editRegulatorSteps[256]; 145 | 146 | double GetVOut(unsigned char data); 147 | unsigned char ConvertVoltageToChar(double vout); 148 | void setVOutVolatile(char *param); 149 | void setVOutVolatile(float vout); 150 | void incDecVOutVolatile(unsigned char inc); 151 | 152 | }; 153 | 154 | #endif 155 | -------------------------------------------------------------------------------- /src/lib/HIDInterface.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nicu Pavel 3 | * Copyright (c) 2020 Mini-Box.com 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "HIDInterface.h" 15 | #include "HArray.h" 16 | 17 | #define OPENUPS2_CMD_OUT 0xB1 18 | 19 | 20 | HIDInterface::HIDInterface(USBHID *hidDevice) { 21 | d = hidDevice; 22 | memset(m_chPackages, 0, SETTINGS_PACKS * 16); 23 | } 24 | 25 | HIDInterface::~HIDInterface() { 26 | 27 | } 28 | 29 | void HIDInterface::printConfiguration(bool withComments) 30 | { 31 | int var_max = 256; 32 | char name[256]; 33 | char unit[64]; 34 | char value[256]; 35 | char comment[1024]; 36 | 37 | for (int i = 0; i < var_max; i++) 38 | { 39 | if (getUPSVariableData(i, name, value, unit, comment)) 40 | { 41 | if (withComments) { 42 | fprintf(stdout, "%d. %s: %s # %s %s\n", i, name, value, unit, comment); 43 | fprintf(stdout, "%s\n", "---------------------------------------------------------------------------------------------------------------"); 44 | } else { 45 | fprintf(stdout, "%s=%s\n", name, value); 46 | } 47 | } 48 | } 49 | } 50 | 51 | int HIDInterface::sendMessageWithBuffer(unsigned char cType, unsigned int buflen, unsigned char* buffer, unsigned int len, ...) 52 | { 53 | HArray mesg(buflen + len + 1); 54 | mesg.getBuf()[0] = cType; 55 | 56 | va_list args; 57 | va_start(args, len); 58 | unsigned int cnt = 0; 59 | unsigned char i = va_arg(args, unsigned int); 60 | 61 | while (cnt < len) 62 | { 63 | mesg.getBuf()[1+cnt] = i; 64 | cnt++; 65 | if (cnt < len) 66 | i = va_arg(args, unsigned int); 67 | } 68 | 69 | va_end(args); 70 | 71 | memcpy(mesg.getBuf() + 1 + len, buffer, buflen); 72 | 73 | int ret = d->writeInterrupt(mesg.getBuf(), mesg.length(), true); 74 | //fprintf(stderr, "[0x%02x] written %d/%d\n", cType, ret, len + 1); 75 | return ret; 76 | } 77 | 78 | int HIDInterface::sendMessage(unsigned char cType, unsigned int len, ...) 79 | { 80 | HArray mesg(len + 1); 81 | //HArray mesg(24); 82 | mesg.getBuf()[0] = cType; 83 | 84 | va_list args; 85 | va_start(args, len); 86 | unsigned int cnt = 0; 87 | 88 | unsigned char i = va_arg(args, unsigned int); 89 | while (cnt < len) 90 | { 91 | mesg.getBuf()[1 + cnt] = i; 92 | cnt++; 93 | if (cnt < len) 94 | i = va_arg(args, unsigned int); 95 | } 96 | va_end(args); 97 | 98 | int ret = d->writeInterrupt(mesg.getBuf(), mesg.length(), true); 99 | //fprintf(stderr, "[0x%02x] written %d/%d\n", cType, ret, len + 1); 100 | return ret; 101 | } 102 | 103 | int HIDInterface::sendCommand(unsigned char command, unsigned char value) 104 | { 105 | return sendMessage(COMMON_CMD_OUT, 3, command, value, 0); // OpenUPS, OpenUPS2 and NUCUPS share same CMD_OUT value 106 | } 107 | int HIDInterface::sendCommandEx(unsigned char command, unsigned char value1, unsigned char value2) 108 | { 109 | return sendMessage(COMMON_CMD_OUT, 3, command, value1, value2); 110 | } 111 | 112 | int HIDInterface::recvMessage(unsigned char *buffer) 113 | { 114 | int ret = d->readInterrupt(buffer); 115 | 116 | if (ret <= 0 ) { 117 | fprintf(stderr, "Read error [0x%02x]: %d\n", buffer[0], ret); 118 | } 119 | return ret; 120 | } 121 | 122 | int HIDInterface::recvMessage(unsigned char *buffer, unsigned int len) 123 | { 124 | int ret = d->readInterrupt(buffer, len); 125 | 126 | if (ret <= 0 ) { 127 | fprintf(stderr, "Read error [0x%02x]: %d/%d\n", buffer[0], ret, len); 128 | } 129 | return ret; 130 | } 131 | 132 | int HIDInterface::GetMessageIdxByName(const char* name) 133 | { 134 | if (!name) 135 | return -1; 136 | 137 | for (int i = 0;i < MAX_MESSAGE_CNT; i++) 138 | { 139 | ATXMSG msg = GetMessages()[i]; 140 | //fprintf(stderr, "GetMessage %d: %s nLen: %d cmp: %d\n", i, msg.strName, msg.nLen, strcasecmp(msg.strName, name)); 141 | if (msg.nLen != 0) 142 | if (strcasecmp(msg.strName, name) == 0) 143 | return i; 144 | } 145 | 146 | return -1; 147 | } 148 | 149 | int HIDInterface::varsToFile(const char *filename, bool withComments) { 150 | if (!filename) { 151 | return -1; 152 | } 153 | 154 | FILE *f = fopen(filename, "w"); 155 | 156 | if (!f) { 157 | return -2; 158 | } 159 | 160 | int var_max = 256; 161 | char name[256]; 162 | char unit[64]; 163 | char value[256]; 164 | char comment[1024]; 165 | 166 | for (int i = 0; i < var_max; i++) 167 | { 168 | if (getUPSVariableData(i, name, value, unit, comment)) 169 | { 170 | if (withComments) { 171 | // Replace \r \n with comment #, assumes windows style line break 172 | char *p = comment; 173 | while (p && *p != '\0') { 174 | if (*p == '\r') { 175 | if (*(p + 1) == '\n') { 176 | *p = '\n'; 177 | *(p + 1) = '#'; 178 | } 179 | } 180 | p++; 181 | } 182 | fprintf(f, "# %s %s %s\n\n", name, unit, comment); 183 | } 184 | fprintf(f, "%s=%s\n", name, value); 185 | } 186 | } 187 | fclose(f); 188 | return 0; 189 | } 190 | 191 | int HIDInterface::fileToVars(const char *filename) { 192 | if (!filename) { 193 | return -1; 194 | } 195 | 196 | FILE *f = fopen(filename, "r"); 197 | 198 | if (!f) { 199 | fprintf(stderr, "Failed to open %s for writting\n", filename); 200 | return -2; 201 | } 202 | 203 | int ret; 204 | char name[256]; 205 | char val[256]; 206 | char buf[1024]; 207 | 208 | #define MAX_LINE 1024 209 | char line[MAX_LINE]; 210 | int len; 211 | int lineno = 0, last = 0, vars = 0; 212 | 213 | while (fgets(line, MAX_LINE, f) != NULL) { 214 | len = strlen(line) - 1; 215 | if (line[len] != '\n' && !feof(f)) { 216 | fprintf(stderr, "Line %d too long\n", lineno); 217 | fclose(f); 218 | return -3; 219 | } 220 | lineno++; 221 | 222 | /* Remove \n and spaces from the end */ 223 | while ((len >= 0) && ((line[len]=='\n') || (isspace(line[len])))) { 224 | line[len] = 0 ; 225 | len--; 226 | } 227 | 228 | if (len < 0) { 229 | len = 0; 230 | continue; 231 | } 232 | if (sscanf(line, "%32[^=]=%32[^\n]%*c", name, val) == 2){ 233 | //fprintf(stdout, "Found var: %s value: %s\n", name, val); 234 | int idx; 235 | idx = GetMessageIdxByName(name); 236 | if (idx >= 0) { 237 | if (setVariableData(idx, val)) { 238 | //fprintf(stdout, "Succesfully converted %s to %s\n", name, val); 239 | } else { 240 | fprintf(stderr, "Error converting %s to %s\n", name, val); 241 | } 242 | } else { 243 | fprintf(stderr, "Variable '%s' unknown\n", name); 244 | } 245 | vars++; 246 | } 247 | } 248 | fprintf(stdout, "Found %d vars\n", vars); 249 | fclose(f); 250 | 251 | return 0; 252 | } 253 | 254 | struct EXEC* HIDInterface::parseCommand(char *cmdexpr) { 255 | if (!cmdexpr) 256 | return NULL; 257 | 258 | struct EXEC *exec = (struct EXEC *) malloc (sizeof (struct EXEC)); 259 | unsigned int idx = 0; 260 | char *token; 261 | 262 | while ((token = strsep(&cmdexpr, CMD_DELIM))) { 263 | if (idx == 0) { 264 | strncpy(exec->cmd, token, MAX_CMD_LEN); 265 | exec->cmd[MAX_CMD_LEN] = '\0'; 266 | fprintf(stdout, "Found command: %s\n", exec->cmd); 267 | } else { 268 | strncpy(exec->params[idx - 1], token, MAX_PARAM_LEN); 269 | exec->params[idx - 1][MAX_PARAM_LEN] = '\0'; 270 | fprintf(stdout, "Found param %d: %s\n", idx, exec->params[idx - 1]); 271 | } 272 | idx++; 273 | } 274 | exec->params_count = idx; 275 | return exec; 276 | } 277 | 278 | bool HIDInterface::executeCommand(char *cmdexpr) { 279 | fprintf(stderr, "Commands not implemented !\n"); 280 | return false; 281 | } -------------------------------------------------------------------------------- /src/lib/HIDInterface.h: -------------------------------------------------------------------------------- 1 | #ifndef _HIDINTERFACE_H_ 2 | #define _HIDINTERFACE_H_ 3 | 4 | #include "usbhid.h" 5 | 6 | #define COMMON_CMD_OUT 0xB1 7 | #define COMMON_CMD_IN 0xB2 8 | #define SETTINGS_PACKS 64 9 | #define DBG_LEN 25 //4 + 17 + 4 10 | #define MAX_MESSAGE_CNT 256 11 | #define MAX_CMD_LEN 32 12 | #define MAX_PARAM_LEN 32 13 | #define MAX_CMD_PARAMS 16 14 | #define CMD_DELIM ":" 15 | 16 | struct ATXMSG 17 | { 18 | unsigned int nIndex; 19 | unsigned int nLen; 20 | const char* strName; 21 | bool bEnabled; // enabled to write or just to read 22 | int nReadMode; // 1=normal, 2=float, 3=hh:mm:ss 23 | double dMultiplier; 24 | double dLimitMin; 25 | double dLimitMax; 26 | const char* strText; // description/comment 27 | const char* strUnit; // measurement unit 28 | }; 29 | typedef ATXMSG _ATXMSG; 30 | 31 | struct UVP 32 | { 33 | unsigned char nCVR_1; 34 | unsigned char nCVR_2; 35 | double fVoltage; 36 | }; 37 | 38 | struct EXEC 39 | { 40 | char cmd[MAX_CMD_LEN + 1]; 41 | char params[MAX_CMD_PARAMS][MAX_PARAM_LEN + 1]; 42 | unsigned int params_count; 43 | }; 44 | 45 | class HIDInterface { 46 | public: 47 | HIDInterface(USBHID *d); 48 | virtual ~HIDInterface(); 49 | 50 | virtual void GetStatus() = 0; 51 | virtual void ReadConfigurationMemory() = 0; 52 | virtual void EraseConfigurationMemory() = 0; 53 | virtual void WriteConfigurationMemory() = 0; 54 | 55 | int sendMessageWithBuffer(unsigned char cType, unsigned int buflen, unsigned char* buffer, unsigned int len, ...); 56 | int sendMessage(unsigned char cType, unsigned int len, ...); 57 | int sendCommand(unsigned char command, unsigned char value); 58 | int sendCommandEx(unsigned char command, unsigned char value1, unsigned char value2); 59 | int recvMessage(unsigned char *buffer); 60 | int recvMessage(unsigned char *buffer, unsigned int len); 61 | int GetMessageIdxByName(const char* name); 62 | int varsToFile(const char *filename, bool withComments); 63 | int fileToVars(const char *filename); 64 | void printConfiguration(bool withComments); 65 | struct EXEC* parseCommand(char *cmdexpr); 66 | 67 | virtual bool executeCommand(char *cmdexpr); 68 | virtual void parseMessage(unsigned char *msg) = 0; 69 | virtual void printValues() = 0; 70 | virtual float convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier) = 0; 71 | virtual bool readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4) = 0; 72 | virtual void convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier) = 0; 73 | virtual bool setVariableData(int mesg_no, char *str) = 0; 74 | virtual ATXMSG* GetMessages() = 0; 75 | virtual double GetConstant(int i) = 0; 76 | virtual unsigned int* GetTermistorConsts() = 0; 77 | virtual unsigned char getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment) = 0; 78 | virtual void restartUPS() = 0; 79 | virtual void restartUPSInBootloaderMode() = 0; 80 | 81 | unsigned long m_ulSettingsAddr; 82 | unsigned char m_chPackages[SETTINGS_PACKS * 16]; 83 | 84 | USBHID *d; 85 | }; 86 | 87 | #endif // _HIDINTERFACE_H_ -------------------------------------------------------------------------------- /src/lib/HIDNUCUPS.h: -------------------------------------------------------------------------------- 1 | #ifndef _HIDNUCUPS_H_ 2 | #define _HIDINUCUPS_H_ 3 | 4 | #include "usbhid.h" 5 | #include "util.h" 6 | #include "HIDInterface.h" 7 | 8 | #define NUC_OUT_REPORT_IO_DATA 0x81 9 | #define NUC_IN_REPORT_IO_DATA 0x82 10 | #define NUC_OUT_REPORT_IO_DATA2 0x83 11 | #define NUC_IN_REPORT_IO_DATA2 0x84 12 | #define NUC_OUT_REPORT_IO_DATA3 0x85 13 | #define NUC_IN_REPORT_IO_DATA3 0x86 14 | #define NUC_OUT_REPORT_IO_DATA4 0x87 15 | #define NUC_IN_REPORT_IO_DATA4 0x88 16 | #define NUC_OUT_REPORT_IO_DATA5 0x89 17 | #define NUC_IN_REPORT_IO_DATA5 0x8A 18 | 19 | #define NUC_CMD_OUT 0xB1 20 | #define NUC_CMD_IN 0xB2 21 | #define NUC_MEM_READ_OUT 0xA1 22 | #define NUC_MEM_READ_IN 0xA2 23 | #define NUC_MEM_WRITE_OUT 0xA3 24 | #define NUC_MEM_WRITE_IN 0xA4 25 | #define NUC_MEM_ERASE 0xA5 26 | 27 | #define NUC_ENTER_BOOTLOADER_OUT 0xA9 28 | #define NUC_ENTER_BOOTLOADER_IN 0xAA 29 | 30 | #define INTERNAL_MESG 0xFF 31 | #define INTERNAL_MESG_DISCONNECTED 0x01 32 | 33 | //commands 34 | #define DCMD_RESTART_NUC 0xAA 35 | 36 | //For reading out memory 37 | #define TYPE_CODE_MEMORY 0x00 38 | #define TYPE_EPROM_EXTERNAL 0x01 39 | #define TYPE_EPROM_INTERNAL 0x02 40 | #define TYPE_CODE_SPLASH 0x03 41 | 42 | #define FLASH_REPORT_ERASE_MEMORY 0xF2 // AddressLo : AddressHi : AddressUp (anywhere inside the 64 byte-block to be erased) 43 | #define FLASH_REPORT_READ_MEMORY 0xF3 // AddressLo : AddressHi : AddressUp : Data Length (1...32) 44 | #define FLASH_REPORT_WRITE_MEMORY 0xF4 // AddressLo : AddressHi : AddressUp : Data Length (1...32) : Data.... 45 | #define KEYBD_REPORT_ERASE_MEMORY 0xB2 // same as F2 but in keyboard mode 46 | #define KEYBD_REPORT_READ_MEMORY 0xB3 // same as F3 but in keyboard mode 47 | #define KEYBD_REPORT_WRITE_MEMORY 0xB4 // same as F4 but in keyboard mode 48 | #define KEYBD_REPORT_MEMORY 0x41 // response to b3,b4 49 | 50 | #define IN_REPORT_EXT_EE_DATA 0x31 51 | #define OUT_REPORT_EXT_EE_READ 0xA1 52 | #define OUT_REPORT_EXT_EE_WRITE 0xA2 53 | 54 | #define IN_REPORT_INT_EE_DATA 0x32 55 | #define OUT_REPORT_INT_EE_READ 0xA3 56 | #define OUT_REPORT_INT_EE_WRITE 0xA4 57 | 58 | ///// MEASUREMENT CONSTANTS 59 | #define NUC_CT_RW (double)75 60 | #define NUC_CT_RP (double)5000 61 | #define NUC_CT_R1_VOUT (double)56200 62 | #define NUC_CT_R2_VOUT (double)2740 63 | #define NUC_CT_V_FEEDBACK_OUT (double)1.2 64 | 65 | #define CHECK_CHAR (unsigned char)0xAA //used for line/write check 66 | 67 | #define MAX_MESSAGE_CNT 256 68 | 69 | #define TERMISTOR_CONSTS 34 70 | 71 | #define NUC_SETTINGS_ADDR_START 0x003000 72 | #define NUC_SETTINGS_ADDR_END 0x003100 73 | #define NUC_SETTINGS_PACKS 16 74 | 75 | 76 | class HIDNUCUPS: public HIDInterface { 77 | public: 78 | HIDNUCUPS(USBHID *d); 79 | ~HIDNUCUPS(); 80 | 81 | void GetStatus(); 82 | void ReadConfigurationMemory(); 83 | void EraseConfigurationMemory(); 84 | void WriteConfigurationMemory(); 85 | void parseMessage(unsigned char *msg); 86 | void printValues(); 87 | float convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier); 88 | bool readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4); 89 | bool readOneValue(int mesg_no, char* str, int nReadMode, double dMultiplier, int len, double dMin, double dMax, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4); 90 | 91 | void convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier); 92 | bool setVariableData(int mesg_no, char *str); 93 | ATXMSG* GetMessages(); 94 | double GetConstant(int i); 95 | unsigned int* GetTermistorConsts(); 96 | unsigned int GetSpecialConstants(unsigned int type, unsigned int cnt); 97 | unsigned char getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment); 98 | void restartUPS(); 99 | void restartUPSInBootloaderMode(); 100 | 101 | private: 102 | unsigned int m_nInput; 103 | unsigned int m_nOutput; 104 | unsigned int m_nChargerFlags; 105 | unsigned int m_nStateFlags; 106 | unsigned int m_nShutdownFlags; 107 | 108 | float m_fVIn; 109 | float m_fIOut; 110 | float m_fVOut; 111 | float m_fVIgnition; 112 | float m_fPOut; 113 | float m_fTemperature[4]; 114 | float m_fBatVoltage[4]; 115 | unsigned char m_fCellBalanceOn[4]; 116 | unsigned char m_fCellDetected[4]; 117 | float m_fBatOverallVoltage; 118 | float m_fBatPack; 119 | float m_fIChgDchg; 120 | 121 | unsigned char m_nVerMajor; 122 | unsigned char m_nVerMinor; 123 | 124 | unsigned char m_bDbgOn;//debug messages should be requested 125 | 126 | unsigned char m_nState;//offline,usb,batpowered,vinpowered 127 | unsigned char m_bDBG[32]; 128 | unsigned char m_bDBG2[32]; 129 | unsigned char m_bDBG3[32]; 130 | 131 | unsigned int m_nTimer[10]; 132 | unsigned int m_nStateMachine[5]; 133 | unsigned int m_nChgTimer[5]; 134 | 135 | unsigned char m_chChargeEndedCondition; 136 | unsigned char m_chBatteryLevel; 137 | 138 | unsigned char m_chMode; 139 | 140 | unsigned int m_nCPUUsage; 141 | 142 | const char *SM_UPS[16] = { "INIT", 143 | "LPWR", 144 | "OFF", 145 | "WAIT_IGNITION_ON_TO_OUTPUT_ON", 146 | "OUTPUT_ON", 147 | "WAIT_OUTPUT_ON_TO_MOBPULSE_ON", 148 | "MOBPULSE_ON", 149 | "ON", 150 | "WAIT_IGNITION_OFF_TO_MOBPULSE_OFF", 151 | "WAIT_HARDOF", 152 | "OUTPUT_OFF", 153 | "BUCKBOOST_ON", 154 | "MOBPULSE_OFF", 155 | "ENTER_LOWPOWER", 156 | "UNKNOWN", 157 | "UNKNOWN"}; 158 | 159 | 160 | const char *SM_AFE[8] = { "IDLE", 161 | "INIT", 162 | "GAINSREAD", 163 | "UPDATE", 164 | "NORMAL", 165 | "SHIP01", 166 | "SHIP10", 167 | "SHIPMODE"}; 168 | 169 | 170 | 171 | const char *SM_CHG[16] = { "IDLE", 172 | "INIT", 173 | "CONDITION", 174 | "START", 175 | "PRECHARGE_CC", 176 | "WAIT_BULK_CC", 177 | "BULK_CC", 178 | "BULK_CV", 179 | "BULK_END", 180 | "FLOAT", 181 | "UNKNOWN", 182 | "UNKNOWN", 183 | "UNKNOWN", 184 | "UNKNOWN", 185 | "UNKNOWN", 186 | "END"}; 187 | 188 | 189 | const char *SM_DTCT[16] = {"IDLE", 190 | "STOP_BALANCE", 191 | "START", 192 | "WMEASCYCLCOMPL", 193 | "START_AGAIN", 194 | "WMEASCYCLCOMPL_AGAIN", 195 | "CALC", 196 | "UNKNOWN", 197 | "UNKNOWN", 198 | "UNKNOWN", 199 | "UNKNOWN", 200 | "UNKNOWN", 201 | "UNKNOWN", 202 | "UNKNOWN", 203 | "UNKNOWN", 204 | "END"}; 205 | 206 | 207 | 208 | 209 | const char *SM_LOWP[4] = { "OFF", 210 | "ON", 211 | "STANDBY", 212 | "SHIP"}; 213 | 214 | 215 | 216 | 217 | 218 | }; 219 | 220 | #endif // _HIDNUCUPS_H_ -------------------------------------------------------------------------------- /src/lib/HIDOpenUPS.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nicu Pavel 3 | * Copyright (c) 2020 Mini-Box.com 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | */ 7 | 8 | #include "util.h" 9 | #include "HIDOpenUPS.h" 10 | 11 | #include 12 | 13 | double g_OpenUPS_memConstants[]= 14 | { 15 | 0.03545,//Vin //0 16 | 0.02571,//Vout //1 17 | 0.00857,//Vbat+chg+cell //2 18 | 12.411, //A chg Hi range //3 19 | 0.8274, //A chg Low range //4 20 | 16.113 //A discharge //5 21 | }; 22 | 23 | ATXMSG g_OpenUPS_memMessages[MAX_MESSAGE_CNT] = 24 | { 25 | {67, 1, _T("OPENUPSMODE") , true,17, 1, 0, 0 , _T("OpenUPS Mode\r\n0-Auto restart when Input Power is Present=YES\r\n1-Auto restart when Input Power is Present=NO"), _T("[-]") }, 26 | {28, 4, _T("CAPACITY") , true,16, 1, 0, 0 , _T("Battery Capacity.\r\nDefault 7000mAh"), _T("[mAh]") }, 27 | {70, 1, _T("CELLS") , true, 1, 1, 0, 0 , _T("Number of configured cells to charge/balance\r\nDefault is 1."), _T("[pcs]") }, 28 | {80, 2, _T("MOB_ONOFF_TOUT") , true, 1, 10, 0, 0 , _T("The powerswitch on the motherboard(if connected) will be shorted this period to turn the Motherboard ON or OFF\r\nDefault is 500ms"), _T("[mS]") }, 29 | 30 | { 0, 1, _T("UPS_CONFIG") , true,14, 1, 0, 0 , _T("Configuration register. Used for enabling disabling modules. LSB bit is b0.\r\nb6- Stop impulse\t\tb5- Start impulse\r\nb4- Coulomb counter\tb3- A/D Low pass Filter module\r\nb2- Balance module\t\tb1- Charge module\r\nb0- Output module\r\nDefault is all enabled"), _T("[bits]") }, 31 | {100,1, _T("UPS_CONFIG2") , true,14, 1, 0, 0 , _T("Configuration register (Firmware V1.4+). Used for enabling disabling modules. LSB bit is b0.\r\nbit0: if bit is set and running on battery and measured output power> 8) & 0xFF, 0x00, 0x10); 233 | recvMessage(recv); 234 | parseMessage(recv); 235 | m_ulSettingsAddr += 16; 236 | } 237 | } 238 | 239 | void HIDOpenUPS::EraseConfigurationMemory() 240 | { 241 | unsigned char recv[32]; 242 | int ret; 243 | 244 | m_ulSettingsAddr = OPENUPS_SETTINGS_ADDR_START; 245 | sendMessage(OPENUPS_MEM_ERASE, 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x40); 246 | 247 | int retries = 5; 248 | while ((ret = recvMessage(recv) <= 0) && retries > 0) { 249 | retries--; 250 | usleep(500); 251 | fprintf(stderr, "Erase 0x%02x retry %d/5\n", recv[0], retries); 252 | } 253 | 254 | if (retries <= 0) { 255 | fprintf(stderr, "Error waiting for erase operation to finish\n"); 256 | } else { 257 | fprintf(stderr, "Successfully erased (0x%02x) configuration memory\n", recv[0]); 258 | } 259 | } 260 | 261 | void HIDOpenUPS::WriteConfigurationMemory() 262 | { 263 | unsigned char recv[32]; 264 | int ret; 265 | 266 | m_ulSettingsAddr = OPENUPS_SETTINGS_ADDR_START; 267 | while (m_ulSettingsAddr < OPENUPS_SETTINGS_ADDR_END) 268 | { 269 | sendMessageWithBuffer(OPENUPS_MEM_WRITE_OUT, 16, m_chPackages+(m_ulSettingsAddr-OPENUPS_SETTINGS_ADDR_START), 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x10); 270 | ret = recvMessage(recv); 271 | 272 | if (ret <= 0 || recv[0] != OPENUPS_MEM_WRITE_IN) { 273 | fprintf(stderr, "Error (%d, 0x%02x) writing configuration variables , aborting ...\n", ret, recv[0]); 274 | break; 275 | } else { 276 | fprintf(stderr, "Wrote page 0x%lx of configuration\n", m_ulSettingsAddr); 277 | } 278 | m_ulSettingsAddr += 16; 279 | } 280 | } 281 | 282 | void HIDOpenUPS::parseMessage(unsigned char *msg) 283 | { 284 | if (!msg) 285 | return; 286 | 287 | switch (msg[0]) 288 | { 289 | case OPENUPS_RECV_ALL_VALUES: 290 | { 291 | m_nVerMajor = (msg[31] >> 4) & 0x0F; 292 | m_nVerMinor = msg[31] & 0x0F; 293 | 294 | m_fVIN = convertOneValue2Float(msg, 2, 1, 20, GetConstant(0)); 295 | m_fVOut = convertOneValue2Float(msg, 2, 3, 20, GetConstant(1)); 296 | m_fVBat = convertOneValue2Float(msg, 2, 5, 2, GetConstant(2)); 297 | 298 | for (int i=0;i<6;i++) 299 | m_fVCell[i] = convertOneValue2Float(msg, 2, 7+2*i, 2, GetConstant(2)); 300 | 301 | for (int i=0;i<8;i++) 302 | { 303 | m_bCheck23[i] = (((msg[23] >> i)&1) == 1); 304 | m_bCheck24[i] = (((msg[24] >> i)&1) == 1); 305 | m_bCheck25[i] = (((msg[25] >> i)&1) == 1); 306 | } 307 | m_nOtherState[4] = msg[23]; 308 | m_nOtherState[5] = msg[24]; 309 | m_nOtherState[6] = msg[25]; 310 | 311 | m_fCCharge = convertOneValue2Float(msg, 2, 19, 2, GetConstant(4)/(double)1000); 312 | 313 | if (m_bCheck24[6]) 314 | { 315 | m_nState = 1; 316 | 317 | m_fCDischarge = convertOneValue2Float(msg, 2, 21, 2, GetConstant(5)/(double)1000); 318 | m_fCIn = 0; 319 | } 320 | else if (m_bCheck24[5]) 321 | { 322 | m_nState = 2; 323 | 324 | double chg_current = convertOneValue2Float(msg, 2, 19, 2, GetConstant(4)/(double)1000); 325 | double vbat = convertOneValue2Float(msg, 2, 5, 2, GetConstant(2)); 326 | double vin = convertOneValue2Float(msg, 2, 1, 20, GetConstant(0)); 327 | double outbuckboost_input_current = convertOneValue2Float(msg, 2, 21, 2, GetConstant(5)/(double)1000); 328 | 329 | m_fCIn = chg_current * vbat / (vin * ETA_CHG) + outbuckboost_input_current; 330 | m_fCDischarge = 0; 331 | } 332 | else 333 | {//only usb 334 | m_nState = 3; 335 | 336 | m_fCDischarge = 0; 337 | m_fCIn = 0; 338 | } 339 | 340 | m_fTemperature = convertOneValue2Float(msg, 2, 26, 15, 1); 341 | }break; 342 | case OPENUPS_CLOCK_IN: 343 | { 344 | m_nYear = 2000+bcd2hex(msg[2]); 345 | m_nMonth = bcd2hex(msg[3]); 346 | m_nDay = bcd2hex(msg[4]); 347 | 348 | m_nHour = bcd2hex(msg[6]); 349 | m_nMin = bcd2hex(msg[7]); 350 | m_nSec = bcd2hex(msg[8]); 351 | 352 | m_nCapacity = msg[12]; 353 | m_nRTE = msg[17]; 354 | m_nRTE = (m_nRTE << 8) | msg[16]; 355 | 356 | m_nOtherState[0] = msg[9]; //upsstate 357 | m_nOtherState[1] = msg[10];//charger state 358 | m_nOtherState[2] = msg[11];//out state 359 | m_nOtherState[3] = msg[15];//battery on 360 | }break; 361 | case OPENUPS_RECV_ALL_VALUES_2: 362 | { 363 | m_fOutputPower = convertOneValue2Float(msg, 4, 1, 16, 0.000001); 364 | }break; 365 | 366 | case OPENUPS_MEM_READ_IN: 367 | { 368 | memcpy(m_chPackages + (m_ulSettingsAddr - OPENUPS_SETTINGS_ADDR_START), msg + 5, 16); 369 | /* 370 | fprintf(stderr, "%02lx %02lx", m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF); 371 | for (int len = 0; len < 16; len++) 372 | fprintf(stderr, " %02x", msg[5 + len]); 373 | fprintf(stderr, "\n"); 374 | */ 375 | } 376 | break; 377 | } 378 | } 379 | 380 | float HIDOpenUPS::convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier) 381 | { 382 | double value = -1; 383 | 384 | if (nLen == 1) 385 | value = (double)buffer[nIndex] * dMultiplier; 386 | else if (nLen == 2) 387 | value = (double)( (((int)buffer[nIndex+1] ) << 8)|buffer[nIndex]) * dMultiplier; 388 | else if (nLen == 4) 389 | value = (double)( (((int)buffer[nIndex+3] ) << 24) | (((int)buffer[nIndex+2] ) << 16) | (((int)buffer[nIndex+1] ) << 8) | buffer[nIndex]) * dMultiplier; 390 | 391 | switch (nReadMode) 392 | { 393 | case 10: 394 | { 395 | if (nLen == 1) 396 | value = (double)buffer[nIndex] * GetConstant(dMultiplier); 397 | else 398 | value = (double)( (((int)buffer[nIndex+1] ) << 8)|buffer[nIndex]) * GetConstant(dMultiplier); 399 | }break; 400 | case 15: 401 | { 402 | unsigned int termistor = 0; 403 | termistor = buffer[nIndex+1]; 404 | termistor = (termistor << 8) | buffer[nIndex]; 405 | 406 | if (termistor <= GetTermistorConsts()[0]) 407 | value = -40; 408 | else if (termistor >= GetTermistorConsts()[TERMISTOR_CONSTS-1]) 409 | value = 125; 410 | else 411 | { 412 | int pos = -1; 413 | for (int i=TERMISTOR_CONSTS-1;i>=0;i--) 414 | { 415 | if (termistor >= GetTermistorConsts()[i]) 416 | { 417 | pos = i; 418 | break; 419 | } 420 | } 421 | 422 | if (termistor == GetTermistorConsts()[pos]) 423 | value = pos*5-40; 424 | else 425 | { 426 | int t1 = pos*5-40; 427 | int t2 = (pos+1)*5-40; 428 | 429 | unsigned int d1 = GetTermistorConsts()[pos]; 430 | unsigned int d2 = GetTermistorConsts()[pos+1]; 431 | 432 | float dtemp = ((float)termistor - (float)d1)*((float)t2-(float)t1)/((float)d2-(float)d1); 433 | 434 | int temp = ceil(dtemp) + t1; 435 | 436 | value = temp; 437 | } 438 | } 439 | }break; 440 | } 441 | 442 | return value; 443 | } 444 | 445 | bool HIDOpenUPS::readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4) 446 | { 447 | bool ok = false; 448 | c1 = 0; 449 | c2 = 0; 450 | 451 | double val = 0; 452 | 453 | switch (nReadMode) 454 | { 455 | case 3: 456 | {//hh:mm:ss 457 | if (strcmp(str, "Never") == 0) 458 | { 459 | val = 0xFFFF; 460 | ok = true; 461 | } 462 | else if ((strlen(str) == 8) && (str[2]==':') && (str[5]==':')) 463 | { 464 | char* end = NULL; 465 | char temp[10]; 466 | str_left(temp, str, 2); 467 | int hh = _tcstol(temp, &end, 10); 468 | if ((end != temp ) && (hh>=0) && (hh<18)) 469 | { 470 | str_mid(temp, str, 3,2); 471 | int mm = _tcstol(temp, &end, 10); 472 | if ((end != temp) && (mm>=0) && (mm<60)) 473 | { 474 | str_right(temp, str, 2); 475 | int ss = _tcstol(temp, &end, 10); 476 | 477 | if ((end != temp) && (ss>=0) && (ss<60)) 478 | { 479 | val = hh*3600+mm*60+ss; 480 | ok = true; 481 | } 482 | } 483 | } 484 | } 485 | }break; 486 | case 4: 487 | {//"signed" float 488 | if (strlen(str) != 0) 489 | { 490 | bool negative = false; 491 | char* end = NULL; 492 | char temp[10]; 493 | 494 | if (str[0] == '-') 495 | { 496 | str_right(temp, str, strlen(str) - 1); 497 | str = temp; 498 | negative = true; 499 | } 500 | str_left(temp, str, 8); 501 | val = _tcstod(temp, &end); 502 | 503 | if (end != temp) 504 | { 505 | ok = true; 506 | 507 | val /= dMultiplier; 508 | if (val < 0) val = 0; 509 | double rem = val - (int) val; 510 | unsigned long uval = (unsigned long)val; 511 | if (rem >= 0.5) uval += 1; 512 | 513 | if (uval > 0x7F) uval = 0x7F; 514 | 515 | c1 = 0; 516 | c2 = (unsigned char)uval; 517 | if (negative) c2 |= 0x80; 518 | } 519 | } 520 | }break; 521 | case 6: 522 | { 523 | val = 0xFF; 524 | ok = true; 525 | }break; 526 | case 7: 527 | { 528 | char* end = NULL; 529 | char temp[10]; 530 | str_left(temp, str, 8); 531 | val = _tcstod(temp, &end); 532 | 533 | c2 = 0; 534 | c1 = GetDataVOut(val); 535 | ok = true; 536 | }break; 537 | case 8: 538 | { 539 | if (strcmp(str, "Never") == 0) 540 | { 541 | val = (double)0xFFFF * dMultiplier; 542 | ok = true; 543 | } 544 | else 545 | { 546 | char* end = NULL; 547 | char temp[10]; 548 | 549 | str_left(temp, str, 8); 550 | val = _tcstod(temp, &end); 551 | if (end != temp) ok = true; 552 | } 553 | }break; 554 | case 9: 555 | { 556 | char* end = NULL; 557 | char temp[10]; 558 | str_left(temp, str, 8); 559 | val = _tcstod(temp, &end); 560 | 561 | c1 = 0; 562 | c2 = GetDataVBat(val); 563 | ok = true; 564 | }break; 565 | case 11: 566 | { 567 | int cnt = atoi(str); 568 | if ((cnt>=0) && (cnt<32)) 569 | { 570 | c1 = GetUVPs()[cnt].nCVR_2; 571 | c2 = GetUVPs()[cnt].nCVR_1; 572 | ok = true; 573 | } 574 | }break; 575 | case 12: 576 | case 13: 577 | { 578 | c1 = 0; 579 | c2 = atoi(str); 580 | ok = true; 581 | }break; 582 | case 14: 583 | { 584 | c1 = 0; 585 | c2 = bin2char(str, &ok); 586 | }break; 587 | case 15: 588 | { 589 | unsigned int termistor = 0; 590 | 591 | int temp = atoi(str); 592 | if (temp <= -40) termistor = GetTermistorConsts()[0]; 593 | else if (temp >= 125) termistor = GetTermistorConsts()[TERMISTOR_CONSTS-1]; 594 | else 595 | { 596 | int pos = (temp + 40) / 5; 597 | int temp_dif = (temp + 40) % 5; 598 | 599 | if (temp_dif == 0) 600 | termistor = GetTermistorConsts()[pos]; 601 | else 602 | { 603 | unsigned int d1 = GetTermistorConsts()[pos]; 604 | unsigned int d2 = GetTermistorConsts()[pos+1]; 605 | 606 | termistor = d1 + temp_dif * (d2-d1) / 5; 607 | } 608 | } 609 | 610 | c1 = (unsigned char)(((unsigned int)termistor) & 0xFF); 611 | c2 = (unsigned char)((((unsigned int)termistor)>>8) & 0xFF); 612 | ok = true; 613 | }break; 614 | case 16: 615 | { 616 | TCHAR* end = NULL; 617 | 618 | val = _tcstod(str, &end); 619 | 620 | if ((val != 0) && (end != str)) 621 | { 622 | val = ceil(val / dMultiplier); 623 | unsigned int ival = (unsigned int) val; 624 | 625 | c1 = (unsigned char)( ival & 0xFF); 626 | c2 = (unsigned char)((ival>>8 ) & 0xFF); 627 | c3 = (unsigned char)((ival>>16) & 0xFF); 628 | c4 = (unsigned char)((ival>>24) & 0xFF); 629 | ok = true; 630 | } 631 | }break; 632 | case 17: 633 | { 634 | char* end = NULL; 635 | char temp[10]; 636 | str_left(temp, str, 8); 637 | val = _tcstod(temp, &end); 638 | if (end != temp) ok = true; 639 | if ((val != 0)&&(val != 1)) ok = false; 640 | 641 | }break; 642 | case 1: 643 | //normal read - integer 644 | case 2: 645 | case 5: 646 | default: 647 | {//normal read - float 648 | char* end = NULL; 649 | char temp[10]; 650 | str_left(temp, str, 8); 651 | val = _tcstod(temp, &end); 652 | if (end != temp) ok = true; 653 | } 654 | } 655 | 656 | if (ok) 657 | { 658 | if ((nReadMode != 4)&&(nReadMode != 7)&&(nReadMode != 9)&&(nReadMode != 11)&&(nReadMode != 12)&&(nReadMode != 13)&&(nReadMode != 14)&&(nReadMode != 15)&&(nReadMode != 16)) 659 | { 660 | if (nReadMode == 10) 661 | val /= GetConstant(dMultiplier); 662 | else 663 | val /= dMultiplier; 664 | 665 | if (nReadMode!=5) 666 | {//unsigned 667 | if (val < 0) val = 0; 668 | double rem = val - (int) val; 669 | unsigned long uval = (unsigned long)val; 670 | if (rem >= 0.5) uval += 1; 671 | 672 | if (len == 1) 673 | { 674 | if (uval > 0xFF) uval = 0xFF; 675 | 676 | c1 = 0; 677 | c2 = (unsigned char)uval; 678 | } 679 | else 680 | { 681 | if (uval > 0xFFFF) uval = 0xFFFF; 682 | 683 | c1 = (unsigned char)(((unsigned int)uval) & 0xFF); 684 | c2 = (unsigned char)((((unsigned int)uval)>>8) & 0xFF); 685 | } 686 | } 687 | else 688 | { 689 | double rem = -val + (int) val; 690 | long uval = (long)val; 691 | if (rem >= 0.5) uval += 1; 692 | 693 | if (len == 1) 694 | { 695 | if (uval > 127) uval = 127; 696 | if (uval <-128) uval = -128; 697 | 698 | c1 = 0; 699 | c2 = (char)uval; 700 | } 701 | else 702 | { 703 | if (uval > 32767) uval = 32767; 704 | if (uval <-32768) uval = -32768; 705 | 706 | c1 = (char)(((int)uval) & 0xFF); 707 | c2 = (char)((((int)uval)>>8) & 0xFF); 708 | } 709 | } 710 | } 711 | } 712 | 713 | return ok; 714 | } 715 | 716 | void HIDOpenUPS::convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier) 717 | { 718 | destination[0] = 0; //empty string 719 | double value = 0; 720 | 721 | if (nLen == 1) 722 | value = (double)m_chPackages[nIndex] * dMultiplier; 723 | else if (nLen == 2) 724 | value = (double)( (((int)m_chPackages[nIndex+1] ) << 8)|m_chPackages[nIndex]) * dMultiplier; 725 | else if (nLen == 4) 726 | value = (double)( (((int)m_chPackages[nIndex+3] ) << 24) | (((int)m_chPackages[nIndex+2] ) << 16) | (((int)m_chPackages[nIndex+1] ) << 8) | m_chPackages[nIndex]) * dMultiplier; 727 | 728 | switch (nReadMode) 729 | { 730 | case 2: sprintf(destination, "%f", (float)value); break; 731 | case 20: sprintf(destination, "%.2f", (float)value); break; 732 | case 10: 733 | { 734 | if (nLen == 1) 735 | value = (double)m_chPackages[nIndex] * GetConstant(dMultiplier); 736 | else if (nLen == 2) 737 | value = (double)( (((int)m_chPackages[nIndex+1] ) << 8)|m_chPackages[nIndex]) * GetConstant(dMultiplier); 738 | else if (nLen == 4) 739 | value = (double)( (((int)m_chPackages[nIndex+3] ) << 24) | (((int)m_chPackages[nIndex+2] ) << 16) | (((int)m_chPackages[nIndex+1] ) << 8) | m_chPackages[nIndex]) * GetConstant(dMultiplier); 740 | sprintf(destination, "%f", (float)value); 741 | }break; 742 | case 11: 743 | { 744 | int pos = -1; 745 | for (int i=0;i<32;i++) 746 | if ( (GetUVPs()[i].nCVR_1 == m_chPackages[nIndex+1]) 747 | &&(GetUVPs()[i].nCVR_2 == m_chPackages[nIndex])) 748 | pos = i; 749 | 750 | sprintf(destination, "%d", pos); 751 | }break; 752 | case 12: 753 | case 13: 754 | sprintf(destination, "%d", m_chPackages[nIndex]); 755 | break; 756 | case 14: 757 | char2bin(destination, m_chPackages[nIndex]); 758 | break; 759 | case 15: 760 | { 761 | unsigned int termistor = 0; 762 | termistor = m_chPackages[nIndex+1]; 763 | termistor = (termistor << 8) | m_chPackages[nIndex]; 764 | 765 | if (termistor <= GetTermistorConsts()[0]) 766 | sprintf(destination, "%s", "-40"); 767 | else if (termistor >= GetTermistorConsts()[TERMISTOR_CONSTS-1]) 768 | sprintf(destination, "%s", "125"); 769 | else 770 | { 771 | int pos = -1; 772 | for (int i=TERMISTOR_CONSTS-1;i>=0;i--) 773 | { 774 | if (termistor >= GetTermistorConsts()[i]) 775 | { 776 | pos = i; 777 | break; 778 | } 779 | } 780 | 781 | if (termistor == GetTermistorConsts()[pos]) 782 | sprintf(destination, "%d", pos * 5-40); 783 | else 784 | { 785 | int t1 = pos*5-40; 786 | int t2 = (pos+1)*5-40; 787 | 788 | unsigned int d1 = GetTermistorConsts()[pos]; 789 | unsigned int d2 = GetTermistorConsts()[pos+1]; 790 | 791 | float dtemp = ((float)termistor - (float)d1)*((float)t2-(float)t1)/((float)d2-(float)d1); 792 | 793 | int temp = ceil(dtemp) + t1; 794 | 795 | sprintf(destination, "%d", temp); 796 | } 797 | } 798 | }break; 799 | case 16: 800 | {//4 byte value 801 | if (nLen == 1) 802 | value = (double)m_chPackages[nIndex]; 803 | else if (nLen == 2) 804 | value = (double)( (((int)m_chPackages[nIndex+1] ) << 8)|m_chPackages[nIndex]); 805 | else if (nLen == 4) 806 | value = (double)( (((int)m_chPackages[nIndex+3] ) << 24) | (((int)m_chPackages[nIndex+2] ) << 16) | (((int)m_chPackages[nIndex+1] ) << 8) | m_chPackages[nIndex]); 807 | 808 | value = value * dMultiplier; 809 | 810 | if (dMultiplier == 1) 811 | sprintf(destination, "%.0f", (float)value); 812 | else 813 | sprintf(destination, "%.2f", (float)value); 814 | }break; 815 | case 17: 816 | { 817 | sprintf(destination, "%d", (int)value); 818 | }break; 819 | case 3: 820 | { 821 | unsigned int ivalue = (unsigned int)value; 822 | if (ivalue == 0xFFFF) 823 | sprintf(destination, "%s", "Never"); 824 | else 825 | sprintf(destination, "%02d:%02d:%02d" 826 | , ivalue/3600 827 | , (ivalue/60)%60 828 | , ivalue % 60 829 | ); 830 | }break; 831 | case 4: 832 | { 833 | double dvalue = (m_chPackages[nIndex] & 0x7f) * dMultiplier; 834 | if ((m_chPackages[nIndex] & 0x80)!=0) 835 | dvalue *= -1; 836 | 837 | sprintf(destination, "%f", (float)dvalue); 838 | }break; 839 | case 5: 840 | { 841 | if (nLen == 1) 842 | value = (double)((char)m_chPackages[nIndex]) * dMultiplier; 843 | else 844 | value = (double)( (((int)((char)m_chPackages[nIndex+1]) ) << 8)|m_chPackages[nIndex]) 845 | * dMultiplier; 846 | sprintf(destination, "%d", (int)value); 847 | }break; 848 | case 6: 849 | { 850 | sprintf(destination, "%s", "-"); 851 | }break; 852 | case 7: 853 | {//no multiplier - voltage value calcualted with formula 854 | sprintf(destination, "%f", GetVoltageVOut(m_chPackages[nIndex])); 855 | }break; 856 | case 8: 857 | { 858 | if (nLen == 1) 859 | { 860 | if (m_chPackages[nIndex] == 0xFF) 861 | sprintf(destination, "%s", "Never"); 862 | else 863 | sprintf(destination, "%d", (int)value); 864 | } 865 | else 866 | { 867 | if ((m_chPackages[nIndex] == 0xFF) && (m_chPackages[nIndex+1] == 0xFF)) 868 | sprintf(destination, "%s", "Never"); 869 | else 870 | sprintf(destination, "%d", (int)value); 871 | } 872 | }break; 873 | case 9: 874 | {//no multiplier - voltage value calcualted with formula 875 | sprintf(destination, "%f", GetVoltageVBat(m_chPackages[nIndex], m_chPackages[nIndex+1])); 876 | }break; 877 | case 1: 878 | default: 879 | { 880 | sprintf(destination, "%d", (int)value); 881 | } 882 | } 883 | 884 | } 885 | 886 | bool HIDOpenUPS::setVariableData(int mesg_no, char *str) 887 | { 888 | int len = GetMessages()[mesg_no].nLen; 889 | 890 | if (len !=0) 891 | { 892 | unsigned char c1 = 0; 893 | unsigned char c2 = 0; 894 | unsigned char c3 = 0; 895 | unsigned char c4 = 0; 896 | 897 | if (readOneValue(str 898 | ,GetMessages()[mesg_no].nReadMode 899 | ,GetMessages()[mesg_no].dMultiplier 900 | ,len 901 | ,c1, c2, c3, c4)) 902 | { 903 | switch (len) 904 | { 905 | case 1: 906 | m_chPackages[GetMessages()[mesg_no].nIndex] = c2; 907 | break; 908 | case 2: 909 | m_chPackages[GetMessages()[mesg_no].nIndex] = c1; 910 | m_chPackages[GetMessages()[mesg_no].nIndex+1] = c2; 911 | break; 912 | case 4: 913 | m_chPackages[GetMessages()[mesg_no].nIndex] = c1; 914 | m_chPackages[GetMessages()[mesg_no].nIndex+1] = c2; 915 | m_chPackages[GetMessages()[mesg_no].nIndex+2] = c3; 916 | m_chPackages[GetMessages()[mesg_no].nIndex+3] = c4; 917 | break; 918 | } 919 | return true; 920 | } 921 | else 922 | { 923 | return false; 924 | } 925 | } 926 | return false; 927 | } 928 | 929 | unsigned char HIDOpenUPS::getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment) 930 | { 931 | if ((cnt < 0) || (cnt >= MAX_MESSAGE_CNT)) 932 | return 0; 933 | 934 | if (GetMessages()[cnt].nLen == 0) 935 | return 0; 936 | 937 | if (name) 938 | strcpy(name, GetMessages()[cnt].strName); 939 | if (unit) 940 | strcpy(unit, GetMessages()[cnt].strUnit); 941 | if (comment) 942 | strcpy(comment, GetMessages()[cnt].strText); 943 | 944 | if (value) 945 | { 946 | convertOneValue2String(value, GetMessages()[cnt].nLen, 947 | GetMessages()[cnt].nIndex, 948 | GetMessages()[cnt].nReadMode, 949 | GetMessages()[cnt].dMultiplier); 950 | } 951 | 952 | return GetMessages()[cnt].nReadMode; 953 | } 954 | 955 | void HIDOpenUPS::restartUPS() 956 | { 957 | sendCommand(OPENUPS_DCMD_RESTART_UPS, 1); 958 | } 959 | 960 | void HIDOpenUPS::restartUPSInBootloaderMode() 961 | { 962 | 963 | } 964 | 965 | double HIDOpenUPS::GetVoltageVOut(unsigned char data) 966 | { 967 | double rpot = ((double)data) * CT_RP / (double)257 + CT_RW; 968 | double voltage = (double)80 * ( (double)1 + CT_R1_VOUT/(rpot+CT_R2_VOUT)); 969 | voltage = floor(voltage); 970 | return voltage/100; 971 | } 972 | 973 | unsigned char HIDOpenUPS::GetDataVOut(double vout) 974 | { 975 | if (vout < 0.9) return (unsigned char)0xff;//low limit 976 | 977 | double rpot = (double)0.8 * CT_R1_VOUT / (vout - (double)0.8) - CT_R2_VOUT; 978 | double result = (257 * (rpot-CT_RW) / CT_RP); 979 | 980 | if (result<0) result = 0; 981 | if (result>255) result = 255; 982 | 983 | return (unsigned char)result; 984 | } 985 | 986 | double HIDOpenUPS::GetVoltageVBat(unsigned char rp1, unsigned rp2) 987 | { 988 | double voltage = ( (double)1 + CT_R1_VBAT / ((double)(rp1*CT_LSB_RP1)+(double)(rp2*CT_LSB_RP2)+CT_R2_VBAT)) * (double)123; 989 | voltage = floor(voltage); 990 | return voltage/100; 991 | } 992 | 993 | unsigned short HIDOpenUPS::GetDataVBat(double vout) 994 | { 995 | if (vout < 1.24) return 0x7fff;//low limit 996 | 997 | double rpot = ((double)1.23 * (CT_R1_VBAT + CT_R2_VBAT) - vout * CT_R2_VBAT) / (vout - (double)1.23); 998 | 999 | int r1 = (int) (rpot / CT_LSB_RP1); 1000 | r1 -= 6;//leave something to R2 1001 | if (r1<0) r1 = 0; 1002 | else if (r1>127) r1 = 127; 1003 | 1004 | double remainder = rpot - (double)r1*CT_LSB_RP1; 1005 | int r2 = (int) (remainder / CT_LSB_RP2); 1006 | if (r2<0) r2 = 0; 1007 | else if (r2>255) r2 = 255; 1008 | 1009 | unsigned short result = (r1 << 8)|r2; 1010 | return (unsigned short)result; 1011 | } 1012 | -------------------------------------------------------------------------------- /src/lib/HIDOpenUPS.h: -------------------------------------------------------------------------------- 1 | #ifndef _HIDOPENUPS_H_ 2 | #define _HIDOPENUPS_H_ 3 | 4 | #include "HIDInterface.h" 5 | #include "usbhid.h" 6 | 7 | #include "HArray.h" 8 | 9 | #define ETA_CHG (double)0.90 10 | 11 | #define STATUS_OK 0x00 12 | #define STATUS_ERASE 0x01 13 | #define STATUS_WRITE 0x02 14 | #define STATUS_READ 0x03 15 | #define STATUS_ERROR 0xff 16 | 17 | #define OPENUPS_GET_ALL_VALUES 0x81 18 | #define OPENUPS_RECV_ALL_VALUES 0x82 19 | #define OPENUPS_CLOCK_OUT 0x83 20 | #define OPENUPS_CLOCK_IN 0x84 21 | #define OPENUPS_GET_ALL_VALUES_2 0x85 22 | #define OPENUPS_RECV_ALL_VALUES_2 0x86 23 | #define OPENUPS_CMD_OUT 0xB1 24 | #define OPENUPS_CMD_IN 0xB2 25 | #define OPENUPS_MEM_READ_OUT 0xA1 26 | #define OPENUPS_MEM_READ_IN 0xA2 27 | #define OPENUPS_MEM_WRITE_OUT 0xA3 28 | #define OPENUPS_MEM_WRITE_IN 0xA4 29 | #define OPENUPS_MEM_ERASE 0xA5 30 | 31 | #define OPENUPS_ENTER_CALIBRATION_OUT 0xA9 32 | #define OPENUPS_ENTER_CALIBRATION_IN 0xAA 33 | 34 | #define INTERNAL_MESG 0xFF 35 | #define INTERNAL_MESG_DISCONNECTED 0x01 36 | 37 | //commands 38 | #define OPENUPS_DCMD_3V3LP 0x01 39 | #define OPENUPS_DCMD_ENABLE_VINPATH 0x02 40 | #define OPENUPS_DCMD_ENABLE_BATTERYPATH 0x03 41 | #define OPENUPS_DCMD_ENABLE_OUTPUT 0x04 42 | #define OPENUPS_DCMD_PWM_OUT 0x05 43 | #define OPENUPS_DCMD_PSW 0x06 44 | #define OPENUPS_DCMD_ENABLE_CHARGER 0x07 45 | #define OPENUPS_DCMD_PWM_CHARGER 0x08 46 | #define OPENUPS_DCMD_CHG_FB 0x09 47 | #define OPENUPS_DCMD_BULK_CHARGE 0x0A 48 | 49 | #define OPENUPS_DCMD_CELL1_DISCHARGE 0x11 50 | #define OPENUPS_DCMD_CELL2_DISCHARGE 0x12 51 | #define OPENUPS_DCMD_CELL3_DISCHARGE 0x13 52 | #define OPENUPS_DCMD_CELL4_DISCHARGE 0x14 53 | #define OPENUPS_DCMD_CELL5_DISCHARGE 0x15 54 | #define OPENUPS_DCMD_CELL6_DISCHARGE 0x16 55 | 56 | #define OPENUPS_DCMD_SPI_CS_AD 0x21 57 | #define OPENUPS_DCMD_SPI_CS_VBAT 0x22 58 | #define OPENUPS_DCMD_SPI_CS_TEMP 0x23 59 | #define OPENUPS_DCMD_SPI_CS_VOUT 0x24 60 | #define OPENUPS_DCMD_SPI_CLK 0x25 61 | #define OPENUPS_DCMD_SPI_DATAOUT 0x26 62 | 63 | #define OPENUPS_DCMD_SPI_WRITE_DATA_VOL_VOUT 0x30 64 | #define OPENUPS_DCMD_SPI_READ_DATA_VOL_VOUT 0x31 65 | #define OPENUPS_DCMD_SPI_INC_VOL_WIPER_VOUT 0x32 66 | #define OPENUPS_DCMD_SPI_DEC_VOL_WIPER_VOUT 0x33 67 | #define OPENUPS_DCMD_SPI_VOUT_STAT 0x34 68 | #define OPENUPS_DCMD_SPI_VOUT_TCON 0x35 69 | 70 | #define OPENUPS_DCMD_SPI_READ_AD_CHANNEL 0x36 71 | 72 | #define OPENUPS_DCMD_SPI_WRITE_DATA_VOL_VCHG 0x40 73 | #define OPENUPS_DCMD_SPI_READ_DATA_VOL_VCHG 0x41 74 | //#define OPENUPS_DCMD_SPI_INC_VOL_WIPER_VCHG 0x42 75 | //#define OPENUPS_DCMD_SPI_DEC_VOL_WIPER_VCHG 0x43 76 | #define OPENUPS_DCMD_I2C_INC_VOL_WIPER_VCHG_ROUGH 0x45 77 | #define OPENUPS_DCMD_I2C_DEC_VOL_WIPER_VCHG_ROUGH 0x46 78 | #define OPENUPS_DCMD_I2C_INC_VOL_WIPER_VCHG_FINE 0x47 79 | #define OPENUPS_DCMD_I2C_DEC_VOL_WIPER_VCHG_FINE 0x48 80 | 81 | #define OPENUPS_DCMD_LED 0x50 82 | 83 | #define OPENUPS_DCMD_SET_UVP_LOW 0x70 84 | #define OPENUPS_DCMD_SET_UVP_HIGH 0x71 85 | 86 | #define OPENUPS_DCMD_SET_OUTPUT_FREQUENCY 0x72 87 | #define OPENUPS_DCMD_SET_CHARGE_FREQUENCY 0x73 88 | 89 | #define OPENUPS_DCMD_RESTART_UPS 0xAA 90 | 91 | //For reading out memory 92 | #define TYPE_CODE_MEMORY 0x00 93 | #define TYPE_EPROM_EXTERNAL 0x01 94 | #define TYPE_EPROM_INTERNAL 0x02 95 | #define TYPE_CODE_SPLASH 0x03 96 | 97 | #define FLASH_REPORT_ERASE_MEMORY 0xF2 // AddressLo : AddressHi : AddressUp (anywhere inside the 64 byte-block to be erased) 98 | #define FLASH_REPORT_READ_MEMORY 0xF3 // AddressLo : AddressHi : AddressUp : Data Length (1...32) 99 | #define FLASH_REPORT_WRITE_MEMORY 0xF4 // AddressLo : AddressHi : AddressUp : Data Length (1...32) : Data.... 100 | #define KEYBD_REPORT_ERASE_MEMORY 0xB2 // same as F2 but in keyboard mode 101 | #define KEYBD_REPORT_READ_MEMORY 0xB3 // same as F3 but in keyboard mode 102 | #define KEYBD_REPORT_WRITE_MEMORY 0xB4 // same as F4 but in keyboard mode 103 | #define KEYBD_REPORT_MEMORY 0x41 // response to b3,b4 104 | 105 | #define IN_REPORT_EXT_EE_DATA 0x31 106 | #define OUT_REPORT_EXT_EE_READ 0xA1 107 | #define OUT_REPORT_EXT_EE_WRITE 0xA2 108 | 109 | #define IN_REPORT_INT_EE_DATA 0x32 110 | #define OUT_REPORT_INT_EE_READ 0xA3 111 | #define OUT_REPORT_INT_EE_WRITE 0xA4 112 | 113 | ///// MEASUREMENT CONSTANTS 114 | #define CT_RW (double)75 115 | #define CT_RP (double)5000 116 | #define CT_R1_VOUT (double)27000//24900 117 | #define CT_R2_VOUT (double)750 118 | 119 | #define CT_R1_VBAT (double)150000 120 | #define CT_R2_VBAT (double)4990 121 | #define CT_RP1_VBAT (double)50000 122 | #define CT_RP2_VBAT (double)5000 123 | #define CT_LSB_RP1 (double)(CT_RP1_VBAT/129) 124 | #define CT_LSB_RP2 (double)(CT_RP2_VBAT/257) 125 | 126 | #define CHECK_CHAR (unsigned char)0xAA //used for line/write check 127 | 128 | #define MAX_MESSAGE_CNT 256 129 | 130 | #define TERMISTOR_CONSTS 34 131 | 132 | #define OPENUPS_SETTINGS_ADDR_START 0x007800 133 | #define OPENUPS_SETTINGS_ADDR_END 0x007C00 134 | #define OPENUPS_SETTINGS_ADDR_CALIBR_START 0x0078D0 135 | #define OPENUPS_SETTINGS_ADDR_CALIBR_END 0x007900 136 | #define OPENUPS_SETTINGS_PACKS 64 137 | #define OPENUPS_SCRIPTS_PACKS 4 138 | #define OPENUPS_SCRIPT_START_ADDR 0x3C00//3F80 139 | #define OPENUPS_SCRIPT_END_ADDR 0x3BF0 140 | 141 | 142 | class HIDOpenUPS : public HIDInterface 143 | { 144 | public: 145 | HIDOpenUPS(USBHID *d); 146 | virtual ~HIDOpenUPS(); 147 | 148 | void GetStatus(); 149 | void ReadConfigurationMemory(); 150 | void EraseConfigurationMemory(); 151 | void WriteConfigurationMemory(); 152 | void parseMessage(unsigned char *msg); 153 | void printValues(); 154 | float convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier); 155 | bool readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4); 156 | void convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier); 157 | bool setVariableData(int mesg_no, char *str); 158 | UVP* GetUVPs(); 159 | ATXMSG* GetMessages(); 160 | double GetConstant(int i); 161 | unsigned int* GetTermistorConsts(); 162 | unsigned char getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment); 163 | void restartUPS(); 164 | void restartUPSInBootloaderMode(); 165 | 166 | double GetVoltageVOut(unsigned char data); 167 | unsigned char GetDataVOut(double vout); 168 | double GetVoltageVBat(unsigned char rp1, unsigned rp2); 169 | unsigned short GetDataVBat(double vout); 170 | 171 | private: 172 | float m_fVIN; 173 | float m_fVBat; 174 | float m_fVOut; 175 | float m_fCCharge; 176 | float m_fCDischarge; 177 | float m_fCIn; 178 | float m_fTemperature; 179 | float m_fVCell[6]; 180 | bool m_bCheck23[8]; 181 | bool m_bCheck24[8]; 182 | bool m_bCheck25[8]; 183 | 184 | unsigned char m_nVerMajor; 185 | unsigned char m_nVerMinor; 186 | 187 | unsigned char m_nState; 188 | 189 | unsigned int m_nYear; 190 | unsigned int m_nMonth; 191 | unsigned int m_nDay; 192 | 193 | unsigned int m_nHour; 194 | unsigned int m_nMin; 195 | unsigned int m_nSec; 196 | 197 | unsigned int m_nCapacity; 198 | unsigned int m_nRTE; 199 | 200 | float m_fOutputPower; 201 | 202 | unsigned char m_nOtherState[7]; 203 | }; 204 | 205 | #endif 206 | -------------------------------------------------------------------------------- /src/lib/HIDOpenUPS2.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nicu Pavel 3 | * Copyright (c) 2020 Mini-Box.com 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | */ 7 | 8 | #include "util.h" 9 | #include "HIDOpenUPS2.h" 10 | 11 | #include 12 | 13 | double g_OpenUPS2_memConstants[] = 14 | { 15 | 0.001, //Vin //0 16 | 0.001, //Vout //1 17 | 0.001, //Vbat+chg //2 18 | 0.001, //A chg Hi range //3 19 | 0.001, //A chg Low range //4 20 | 0.001, //A discharge //5 21 | 0.001 //battery 22 | }; 23 | 24 | ATXMSG g_OpenUPS2_memMessages[MAX_MESSAGE_CNT] = 25 | { 26 | {67, 1, _T("OPENUPSMODE"), true, 17, 1, 0, 0, _T("OPENUPS mode\r\n0-Autorestart when input is present=yes\t(UPS)\r\n1-Autorestart when input is present=no\t(LAPTOP)\r\n2-Energy Pack mode\t\t\t(ON/OFF)"), _T("[-]")}, 27 | {28, 4, _T("CAPACITY"), true, 16, 1, 0, 0, _T("Battery Capacity.\r\nDefault 1500mAh"), _T("[mAh]")}, 28 | {80, 2, _T("MOB_ONOFF_TOUT"), true, 1, 10, 0, 0, _T("The powerswitch on the motherboard(if connected) will be shorted this period to turn the Motherboard ON or OFF\r\nDefault is 500ms"), _T("[mS]")}, 29 | {66, 1, _T("UPS_BUTTON_ON_TOUT"), true, 1, 10, 0, 0, _T("The pushbutton connected on the P10 header must be shorted this period to be considered as pressed.\r\nDefault 100ms."), _T("[mS]")}, 30 | 31 | {0, 1, _T("UPS_CONFIG"), true, 14, 1, 0, 0, _T("Configuration register. Used for enabling disabling modules.0-disabled;1-enabled\r\nbit7:reserved\r\nbit6:reserved\r\nbit5:reserved\r\nbit4:Enable No Battery Mode (FW 1.4+)\r\nbit3:reserved\r\nbit2:Enable temperature compensated charge algorithm\r\nbit1:Enable shutdown from battery if system was shut down from OS sensed by USB\r\nbit0:Enable output voltage settings directly from OUT_VOLTAGE parameter. If disabled output voltage is set by configuration switch on the back side of the PCBA."), _T("[bit7..bit0]")}, 32 | {100, 1, _T("UPS_CONFIG2"), true, 14, 0, 0, 1, _T("Configuration register.Used for enabling disabling modules.0-disabled;1-enabled\r\nbit7:reserved\r\nbit6:reserved\r\nbit5:reserved\r\nbit4:reserved\r\nbit3:reserved\r\nbit2:reserved\r\nbit1:Enable Ship mode, consumption is less than 1uA. Unit can be waked up only by input power presence.\r\nbit0:Enable Sleep mode, consumption is 530uA. Unit can be waked up by button or input power presence.\r\nThe combination of bit1 ,bit0 sets the configurable low power modes\r\n01: Sleep mode CPU OFF (530uA)\r\n10: Ship mode CPU OFF(1uA)\r\n11 or 00: Standby mode CPU ON(15mA) ==> Ship mode CPU OFF(1uA)"), _T("[bit7..bit0]")}, 33 | 34 | // { 1, 1, _T("UPS_INIT_DELAY_TOUT") , true, 1, 1, 0, 0 , _T("Initial delay before starting the UPS\r\nDefault is 1 sec."), _T("[s]") }, 35 | // { 2, 2, _T("UPS_VIN_MAX_SHUTDOWN") , true,10, 0, 0, 0 , _T("Max allowed input voltage. In case input voltage exceeds predefined value shutdown will be initiated.\r\nDefault is 25V."), _T("[V]") }, 36 | {4, 2, _T("UPS_VIN_MIN_START"), true, 10, 0, 0, 0, _T("If input voltage is above this threshold the UPS will start and take power from the input.\r\nDefault is 11V."), _T("[V]")}, 37 | // { 6, 2, _T("UPS_VIN_MIN_STOP") , true,10, 0, 0, 0 , _T("If input voltage is below this threshold the UPS will try to run on battery.\r\nDefault is 6V."), _T("[V]") }, 38 | {8, 2, _T("UPS_VCELL_MIN_START"), true, 10, 6, 0, 0, _T("If Vin is not present and all the battery cells are above this threshold the UPS can start and runs on battery\r\nDefault is 3V."), _T("[V]")}, 39 | {10, 2, _T("UPS_VCELL_MIN_STOP"), true, 10, 6, 0, 0, _T("If VIN is not present and one of the battery cells is less than this threshold during the time period specified by UPS_VBAT_UVP_OFF_TOUT parameter the UPS will initiate shut down procedure.\r\nDefault is 2.8V"), _T("[V]")}, 40 | /**/ {16, 2, _T("UPS_VCELL_MIN_HARD_STOP"), true, 10, 6, 0, 0, _T("If VIN is not present and one of the battery cells is less than this threshold the UPS will instantly shut down to preserve battery.\r\nDefault is 2V "), _T("[V]")}, 41 | {12, 2, _T("UPS_VBAT_UVP_OFF_TOUT"), true, 1, 1, 0, 0, _T("During this period battery cells are checked against UPS_VCELL_MIN_STOP. If cell voltage exceeds UPS_VCELL_MIN_STOP the timer is rearmed so it can filter unwanted noise in the system.\r\nDefault is 5 sec."), _T("[s]")}, 42 | {14, 2, _T("UPS_HARDOFF_TOUT"), true, 1, 1, 0, 0, _T("After UPS_VBAT_UVP_OFF_TOUT passed motherboard is signaled to shut down. The UPS will wait this period so that the Motherboard can shut down gracefully, than cut power and enter deep sleep. This period should not be too long to prevent battery drain.\r\nDefault is 60 sec."), _T("[s]")}, 43 | 44 | {101, 2, _T("UPS_VBAT_SLEEP_TOUT"), true, 3, 1, 0, 0, _T("Deep sleep timeout..If system is running on battery and this period has elapsed with no input power applied, then the UPS will initiate shut down procedure. \"Never\" is allowed as value (to disable this feature).\r\nDefault is \"Never\"."), _T("[HH:MM:SS]")}, 45 | 46 | //moved up {16, 2, _T("UPS_VCELL_MIN_HARD_STOP") , true,10, 6, 0, 0 , _T("If VIN is not present and one of the battery cells is less than this threshold the UPS will instantly shut down to preserve battery.\r\nDefault is 2V "), _T("[V]") }, 47 | // {18, 2, _T("UPS_SWITCHOVER_VBAT_TOUT") , true, 1, 10, 0, 0 , _T("After UPS switches to battery, can switch back to Vin only after this time ellapses\r\nDefault is 1000 ms"), _T("[ms]") }, 48 | // {20, 2, _T("UPS_SWITCHOVER_VIN_TOUT") , true, 1, 1, 0, 0 , _T("After UPS switches to input, can switch back to battery only after this time ellapses\r\nDefault is 1 ms"), _T("[ms]") }, 49 | {22, 2, _T("DCHG_IMAX"), true, 10, 5, 0, 0, _T("Max allowed discharge current. In case discharge current exceeds this threshold shutdown will be initiated.\r\nDefault is 10 A."), _T("[A]")}, 50 | {24, 1, _T("AFE_OLV"), true, 40, 1, 0, 0, _T("Advanced parameter.\r\nAFE Overload Voltage treshold configuration register.\r\nDefault is 00."), _T("[hex]")}, 51 | {25, 1, _T("AFE_OLD"), true, 40, 1, 0, 0, _T("Advanced parameter.\r\nAFE Overload Delay time configuration register.\r\nDefault is 00."), _T("[hex]")}, 52 | {26, 1, _T("AFE_SCC"), true, 40, 1, 0, 0, _T("Advanced parameter.\r\nAFE Short Circuit In Charge configuration register.\r\nDefault is 50."), _T("[hex]")}, 53 | {27, 1, _T("AFE_SCD"), true, 40, 1, 0, 0, _T("Advanced parameter.\r\nAFE Short Circuit In Discharge configuration register.\r\nDefault is 50."), _T("[hex]")}, 54 | // moved up {28, 4, _T("CAPACITY") , true,16, 1, 0, 0 , _T("Battery Capacity.\r\nDefault 3400mAh"), _T("[mAh]") }, 55 | 56 | //moved down {32, 2, _T("BAL_ENABLE_TOUT") , true,1, 5, 0, 0 , _T("Balancing enable timeout.\r\nDefault is 2 min."), _T("[min]") }, 57 | //moved down {34, 2, _T("BAL_DISABLE_TOUT") , true,1, 5, 0, 0 , _T("Balancing disable timeout.\r\nDefault is 2 min."), _T("[min]") }, 58 | {36, 2, _T("CHG_VCOND"), true, 10, 6, 0, 0, _T("Conditioning/Pre-charge voltage. Charge current is limited until cell voltage exceeds this value and for at least CHG_TCOND time.\r\nDefault is 3V."), _T("[V]")}, 59 | {38, 2, _T("CHG_TCOND"), true, 1, 1, 0, 0, _T("Conditioning/Precharge time. Charge current is limited until cell voltage exceeds CHG_VCOND value and it is applied during this time.\r\nDefault is 30 sec."), _T("[s]")}, 60 | // {40, 2, _T("CHG_IBULK") , true,10, 3, 0, 0 , _T("Fast charge current limit (constant current mode)\r\nDefault is 1750mA."), _T("[mA]") }, 61 | {42, 2, _T("CHG_BULK_STOP_VOLTAGE"), true, 10, 6, 0, 0, _T("Maximum allowed bulk charge voltage/cell during constant current/constant voltage charging\r\nDefault is 3.5[V/cell]"), _T("[V/cell]")}, 62 | {71, 1, _T("CHG_HYSTERESIS"), true, 10, 6, 0, 0, _T("An over-voltage value (CHG_BULK_STOP_VOLTAGE+CHG_HYSTERESIS ) that it is allowed when charging.\r\nIf one of the cells exceeds this value charging is immediately stopped.\r\nDefault is 100mV/cell."), _T("[V/cell]")}, 63 | //moved down {44, 2, _T("OUT_FOLLOW_OFFSET") , true,30, 10, 0, 0 , _T("-"), _T("[V]") }, 64 | // {46, 2, _T("CHG_IMIN") , true,10, 3, 0, 0 , _T("If charge current in CV mode is less than this value\r\nPbSO4: enter maintanence mode and apply the float charge voltage(CHG_START_VOLTAGE)\r\nLiFePO4: cut off the charge voltage\r\nDefault is 290mA"), _T("[mA]") }, 65 | 66 | {96, 2, _T("CHG_GLOBAL_TOUT"), true, 1, 0.5, 0, 0, _T("Global charge timeout.\r\nDefault is 180 min."), _T("[min]")}, 67 | // {98, 2, _T("CHG_IFLOAT") , true,10, 3, 0, 0 , _T("Charge current limit in float charge mode for PbSO4 batteries (Firmware v1.3+)"), _T("[mA]") }, 68 | {94, 2, _T("CHG_TOPPING_TIMER"), true, 1, 1, 0, 0, _T("For Lithium based batteries after an overvoltage condition is detected for a cell a resting period is set by this timer before applying a small topping charge in case other cells are still not charged.\r\nDefault is 18000s."), _T("[s]")}, 69 | 70 | {48, 2, _T("CHG_START_VOLTAGE"), true, 10, 6, 0, 0, _T("If cell voltage is below this value charging can be started.\r\nDefault is 3.32V/cell"), _T("[V/cell]")}, 71 | {50, 1, _T("CHG_BAT_TYPE"), true, 1, 1, 0, 0, _T("The battery chemistry to be charged.\r\n1-LiFePO4"), _T("")}, 72 | {51, 2, _T("CHG_TEMP_COLD"), true, 15, 1, 0, 0, _T("COLD temperature treshold for temperature compensated charge current regulation\r\nDefault 5�C"), _T("[�C]")}, 73 | {53, 2, _T("CHG_TEMP_COOL"), true, 15, 1, 0, 0, _T("COOL temperature treshold for temperature compensated charge current regulation\r\nDefault 10�C"), _T("[�C]")}, 74 | {55, 2, _T("CHG_TEMP_WARM"), true, 15, 1, 0, 0, _T("WARM temperature treshold for temperature compensated charge current regulation\r\nDefault 50�C"), _T("[�C]")}, 75 | {57, 2, _T("CHG_TEMP_HOT"), true, 15, 1, 0, 0, _T("HOT temperature treshold for temperature compensated charge current regulation\r\nDefault 55�C"), _T("[�C]")}, 76 | //moved down {59, 1, _T("OUT_STARTVOLTAGE_OFFSET") , true, 1, 1, 0, 0 , _T("Soft start output voltage offset"), _T("[nr]") }, 77 | 78 | {60, 2, _T("BAL_VCELL_MIN"), true, 10, 6, 0, 0, _T("Balancing is allowed if cell voltages are above this value.\r\nDefault is 3.32V"), _T("[V]")}, 79 | {62, 1, _T("BAL_VCELL_DIFF_START"), true, 10, 6, 0, 0, _T("If the voltage difference between cells exceeds this value start balancing the cells.\r\nDefault is 70mV."), _T("[V]")}, 80 | {63, 1, _T("BAL_VCELL_DIFF_STOP"), true, 10, 6, 0, 0, _T("If the voltage difference between cells is less than this value stop balancing the cells.\r\nDefault is 40mV."), _T("[V]")}, 81 | /* {32, 2, _T("BAL_ENABLE_TOUT"), true, 1, 5, 0, 0, _T("Balancing enable timeout (FW 1.5+)\r\nDefault 72000 min."), _T("[min]")}, */ 82 | /* {34, 2, _T("BAL_DISABLE_TOUT"), true, 1, 5, 0, 0, _T("Balancing disable timeout (FW 1.5+)\r\nDefault 1440 min."), _T("[min]")}, */ 83 | 84 | {64, 2, _T("OUT_VOLTAGE"), true, /*7*/ 10, 1, 0, 0, _T("The output voltage. Bit0 in UPS_CONFIG parameter should be set to �1� in order this parameter has effect.\r\nDefault is 12V."), _T("[V]")}, 85 | /**/ {59, 1, _T("OUT_STARTVOLTAGE_OFFSET"), true, 1, 1, 0, 0, _T("Soft start output voltage offset"), _T("[nr]")}, 86 | //moved up {66, 1, _T("UPS_BUTTON_ON_TOUT") , true, 1, 10, 0, 0 , _T(""), _T("[]") }, 87 | //moved up {67, 1, _T("OPENUPSMODE") , true,17, 1, 0, 0 , _T("OpenUPS Mode\r\n0-Auto restart when Input Power is Present=YES\r\n1-Auto restart when Input Power is Present=NO"), _T("[-]") }, 88 | // {68, 1, _T("OUT_REGULATOR_OFFSET") , true, 1, 1, 0, 0 , _T("Regulator offset"), _T("[step]") }, 89 | {69, 1, _T("OUT_MAX_REGULATOR_STEP"), true, 1, 1, 0, 0, _T("Maximum allowed regulation step number for output module (0-255)\r\nDefault 255."), _T("[step]")}, 90 | //removed {70, 1, _T("CELLS") , true, 1, 1, 0, 0 , _T("Number of configured cells to charge/balance\r\nDefault is 4."), _T("[pcs]") }, 91 | //moved up {71, 1, _T("CHG_HYSTERESIS") , true,10, 2, 0, 0 , _T("An overvoltage value (CHG_BULK_STOP_VOLTAGE +CHG_HYSTERESIS ) that it is allowed when charging.If one of the cells exceeds this value charging is imediately stopped.\r\nDefault is 200mV/cell."), _T("[V]") }, 92 | //removed {72, 4, _T("POUT_LO") , true,16, 0.000001, 0, 0 , _T("Output power low treshold for motherboard alive sensing.If output power is lower than this treshold shut down impulse is NOT sent to the motherboard.\r\nDefault is 2W."), _T("[W]") }, 93 | //removed {76, 4, _T("POUT_HI") , true,16, 0.000001, 0, 0 , _T("Output power high treshold for motherboard alive sensing. If output power is higher than this treshold shut down impulse is sent to the motherboard.\r\nDefault is 6W."), _T("[W]") }, 94 | //removed {44, 2, _T("OUT_FOLLOW_OFFSET") , true,30, 10, 0, 0 , _T("Offset for adaptive output regulation.\r\nDefault is 1V."), _T("[V]") }, 95 | 96 | //moved up {80, 2, _T("MOB_ONOFF_TOUT") , true, 1, 10, 0, 0 , _T("The powerswitch on the motherboard(if connected) will be shorted this period to turn the Motherboard ON or OFF\r\nDefault is 500ms"), _T("[mS]") }, 97 | {82, 2, _T("OCV_SOC0"), true, 10, 6, 0, 0, _T("Open Circuit Voltage State Of Charge detection for initial 0% fuel gauge estimation.\r\nDefault is 3.1V"), _T("[V]")}, 98 | {84, 2, _T("OCV_SOC10"), true, 10, 6, 0, 0, _T("Open Circuit Voltage State Of Charge detection for initial 10% fuel gauge estimation.\r\nDefault is 3.2V"), _T("[V]")}, 99 | {86, 2, _T("OCV_SOC25"), true, 10, 6, 0, 0, _T("Open Circuit Voltage State Of Charge detection for initial 25% fuel gauge estimation.\r\nDefault is 3.25V"), _T("[V]")}, 100 | {88, 2, _T("OCV_SOC50"), true, 10, 6, 0, 0, _T("Open Circuit Voltage State Of Charge detection for initial 50% fuel gauge estimation.\r\nDefault is 3.30V"), _T("[V]")}, 101 | {90, 2, _T("OCV_SOC75"), true, 10, 6, 0, 0, _T("Open Circuit Voltage State Of Charge detection for initial 75% fuel gauge estimation.\r\nDefault is 3.32V"), _T("[V]")}, 102 | {92, 2, _T("OCV_SOC100"), true, 10, 6, 0, 0, _T("Open Circuit Voltage State Of Charge detection for initial 100% fuel gauge estimation.\r\nDefault is 3.35V"), _T("[V]")}, 103 | //moved up {94, 2, _T("CHG_TOPPING_TIMER") , true, 1, 1, 0, 0 , _T("For Lithium based batteries after an overvoltage condition is detected for a cell a resting period is set by this timer before applying a small topping charge in case other cells are still not charged.\r\nDefault is 1800 sec."), _T("[s]") }, 104 | 105 | //moved up {96, 2, _T("CHG_GLOBAL_TOUT") , true, 1, 0.5, 0, 0 , _T("Global charge timeout (Firmware v1.3+)"), _T("[min]") }, 106 | //deleted {98, 2, _T("CHG_IFLOAT") , true,10, 3, 0, 0 , _T("Charge current limit in float charge mode (Firmware v1.3+)"), _T("[mA]") }, 107 | //moved up {100,1, _T("UPS_CONFIG2") , true,14, 1, 0, 0 , _T("Configuration register (Firmware V1.4+). Used for enabling disabling modules. LSB bit is b0.\r\nbit0: if bit is set and running on battery and measured output power> 4) & 0x0F; 216 | m_nVerMinor = msg[31] & 0x0F; 217 | 218 | m_fVIN = convertOneValue2Float(msg, 2, 1, 20, HIDOpenUPS2::GetConstant(0)); 219 | m_fVOut = convertOneValue2Float(msg, 2, 3, 20, HIDOpenUPS2::GetConstant(1)); 220 | m_fVBat = convertOneValue2Float(msg, 2, 5, 20, HIDOpenUPS2::GetConstant(6)); 221 | 222 | for (i = 0; i < 3; i++) 223 | m_fVCell[i] = convertOneValue2Float(msg, 2, 7 + 2 * i, 20, HIDOpenUPS2::GetConstant(6)); 224 | 225 | for (i = 0; i < 8; i++) 226 | { 227 | m_bCheck23[i] = ((msg[23] >> i) & 1); 228 | m_bCheck24[i] = ((msg[24] >> i) & 1); 229 | m_bCheck25[i] = ((msg[25] >> i) & 1); 230 | } 231 | 232 | m_fCCharge = convertOneValue2Float(msg, 2, 19, 2, (double)0.001); 233 | m_fCDischarge = convertOneValue2Float(msg, 2, 21, 2, (double)0.001); 234 | 235 | if (m_bCheck24[6]) 236 | m_nState = 1; 237 | else if (m_bCheck24[5]) 238 | m_nState = 2; 239 | else 240 | m_nState = 3; //only usb 241 | 242 | m_fTemperature[0] = convertOneValue2Float(msg, 2, 13, 15, 1); 243 | m_fTemperature[1] = convertOneValue2Float(msg, 2, 15, 15, 1); 244 | m_fTemperature[2] = convertOneValue2Float(msg, 2, 17, 15, 1); 245 | 246 | m_fVDuty = convertOneValue2Float(msg, 2, 26, 20, (double)0.0009765625); 247 | 248 | m_bVOutPot = 255 - msg[28]; 249 | m_bConfigSwitch = msg[29]; 250 | } 251 | break; 252 | case OPENUPS2_CLOCK_IN: 253 | { 254 | int i; 255 | 256 | if ((m_nVerMajor >= 1) && (m_nVerMinor >= 4)) 257 | { 258 | m_nShutdownType = msg[7]; 259 | m_nShutdownType = (m_nShutdownType << 8) | msg[6]; 260 | } 261 | else 262 | m_nShutdownType = 0; 263 | 264 | m_bStateUPS = msg[9]; 265 | m_bStateCHG = msg[10]; 266 | m_bStateDBG = msg[11]; 267 | m_bCapacity = msg[12]; 268 | 269 | for (i = 0; i < 3; i++) 270 | m_bBatOn[i] = ((msg[15] >> i) & 1); 271 | 272 | m_nRTE = msg[17]; 273 | m_nRTE = (m_nRTE << 8) | msg[16]; 274 | 275 | m_bUPSMode = msg[25]; 276 | 277 | for (i = 0; i < 4; i++) 278 | m_bDBG[i] = msg[28 + i]; 279 | } 280 | break; 281 | case OPENUPS2_MEM_READ_IN: 282 | { 283 | memcpy(m_chPackages + (m_ulSettingsAddr - OPENUPS2_SETTINGS_ADDR_START), msg + 5, 16); 284 | /* 285 | fprintf(stderr, "%02lx %02lx", m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF); 286 | for (int len = 0; len < 16; len++) 287 | fprintf(stderr, " %02x", msg[5 + len]); 288 | fprintf(stderr, "\n"); 289 | */ 290 | } 291 | break; 292 | } 293 | } 294 | 295 | float HIDOpenUPS2::convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier) 296 | { 297 | double value = -1; 298 | 299 | if (nLen == 1) 300 | value = (double)buffer[nIndex] * dMultiplier; 301 | else if (nLen == 2) 302 | value = (double)((((int)buffer[nIndex + 1]) << 8) | buffer[nIndex]) * dMultiplier; 303 | else if (nLen == 4) 304 | value = (double)((((int)buffer[nIndex + 3]) << 24) | (((int)buffer[nIndex + 2]) << 16) | (((int)buffer[nIndex + 1]) << 8) | buffer[nIndex]) * dMultiplier; 305 | 306 | switch (nReadMode) 307 | { 308 | case 10: 309 | { 310 | if (nLen == 1) 311 | value = (double)buffer[nIndex] * HIDOpenUPS2::GetConstant((int)dMultiplier); 312 | else 313 | value = (double)((((int)buffer[nIndex + 1]) << 8) | buffer[nIndex]) * HIDOpenUPS2::GetConstant((int)dMultiplier); 314 | } 315 | break; 316 | case 30: 317 | { 318 | if (nLen == 1) 319 | value = (double)buffer[nIndex] * HIDOpenUPS2::GetConstant(6); 320 | else 321 | value = (double)((((int)buffer[nIndex + 1]) << 8) | buffer[nIndex]) * HIDOpenUPS2::GetConstant(6); 322 | } 323 | break; 324 | case 15: 325 | { 326 | unsigned int termistor = 0; 327 | termistor = buffer[nIndex + 1]; 328 | termistor = (termistor << 8) | buffer[nIndex]; 329 | 330 | if (termistor <= HIDOpenUPS2::GetTermistorConsts()[0]) 331 | value = -40; 332 | else if (termistor >= HIDOpenUPS2::GetTermistorConsts()[TERMISTOR_CONSTS - 1]) 333 | value = 125; 334 | else 335 | { 336 | int pos = -1; 337 | for (int i = TERMISTOR_CONSTS - 1; i >= 0; i--) 338 | { 339 | if (termistor >= HIDOpenUPS2::GetTermistorConsts()[i]) 340 | { 341 | pos = i; 342 | break; 343 | } 344 | } 345 | 346 | //if (termistor != HIDOpenUPS2::GetTermistorConsts()[i]) pos--;//latest value which is smaller than my one 347 | 348 | if (termistor == HIDOpenUPS2::GetTermistorConsts()[pos]) 349 | value = pos * 5 - 40; 350 | else 351 | { 352 | int t1 = pos * 5 - 40; 353 | int t2 = (pos + 1) * 5 - 40; 354 | 355 | unsigned int d1 = HIDOpenUPS2::GetTermistorConsts()[pos]; 356 | unsigned int d2 = HIDOpenUPS2::GetTermistorConsts()[pos + 1]; 357 | 358 | float dtemp = ((float)termistor - (float)d1) * ((float)t2 - (float)t1) / ((float)d2 - (float)d1); 359 | 360 | int temp = (int)ceil(dtemp) + t1; 361 | 362 | value = temp; 363 | } 364 | } 365 | } 366 | break; 367 | } 368 | 369 | //DBGOutput("convertOneValue2Float %.3f\n",value); 370 | 371 | return (float)value; 372 | } 373 | 374 | bool HIDOpenUPS2::readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4) 375 | { 376 | bool ok = false; 377 | c1 = 0; 378 | c2 = 0; 379 | 380 | double val = 0; 381 | 382 | switch (nReadMode) 383 | { 384 | case 3: 385 | { //hh:mm:ss 386 | if (_strcmpi(str, "Never") == 0) 387 | { 388 | val = 0xFFFF; 389 | ok = true; 390 | } 391 | else if ((strlen(str) == 8) && (str[2] == ':') && (str[5] == ':')) 392 | { 393 | _TCHAR *end = NULL; 394 | char temps[10]; 395 | 396 | str_left(temps, str, 2); 397 | int hh = _tcstol(temps, &end, 10); 398 | if (((end != str) && (hh >= 0) && (hh < 18))) 399 | { 400 | str_mid(temps, str, 3, 2); 401 | int mm = _tcstol(temps, &end, 10); 402 | if ((end != str) && (mm >= 0) && (mm < 60)) 403 | { 404 | str_right(temps, str, 2); 405 | int ss = _tcstol(temps, &end, 10); 406 | 407 | if (((end != str) && (ss >= 0) && (ss < 60))) 408 | { 409 | val = hh * 3600 + mm * 60 + ss; 410 | ok = true; 411 | } 412 | } 413 | } 414 | } 415 | } 416 | break; 417 | case 4: 418 | { //"signed" float 419 | if (strlen(str) != 0) 420 | { 421 | bool negative = false; 422 | if (str[0] == '-') 423 | { 424 | str = str + 1; 425 | negative = true; 426 | } 427 | 428 | _TCHAR *end = NULL; 429 | val = _tcstod(str, &end); 430 | 431 | if (end != str) 432 | { 433 | ok = true; 434 | 435 | val /= dMultiplier; 436 | if (val < 0) 437 | val = 0; 438 | double rem = val - (int)val; 439 | unsigned long uval = (unsigned long)val; 440 | if (rem >= 0.5) 441 | uval += 1; 442 | 443 | if (uval > 0x7F) 444 | uval = 0x7F; 445 | 446 | c1 = 0; 447 | c2 = (unsigned char)uval; 448 | if (negative) 449 | c2 |= 0x80; 450 | } 451 | } 452 | } 453 | break; 454 | case 6: 455 | { 456 | val = 0xFF; 457 | ok = true; 458 | } 459 | break; 460 | case 7: 461 | { 462 | /*_TCHAR* end = NULL; 463 | val = _tcstod(str, &end); 464 | 465 | c2 = 0; 466 | c1 = HIDOpenUPS2::GetDataVOut(val); 467 | ok = true;*/ 468 | } 469 | break; 470 | case 8: 471 | { 472 | if (_strcmpi(str, "Never") == 0) 473 | { 474 | val = (double)0xFFFF * dMultiplier; 475 | ok = true; 476 | } 477 | else 478 | { 479 | TCHAR *end = NULL; 480 | val = _tcstod(str, &end); 481 | if (end != str) 482 | ok = true; 483 | } 484 | } 485 | break; 486 | case 12: 487 | case 13: 488 | { 489 | c1 = 0; 490 | c2 = atoi(str); 491 | ok = true; 492 | } 493 | break; 494 | case 14: 495 | { 496 | c1 = 0; 497 | c2 = bin2char(str, &ok); 498 | } 499 | break; 500 | case 15: 501 | { 502 | unsigned int termistor = 0; 503 | 504 | int temp = atoi(str); 505 | if (temp <= -40) 506 | termistor = HIDOpenUPS2::GetTermistorConsts()[0]; 507 | else if (temp >= 125) 508 | termistor = HIDOpenUPS2::GetTermistorConsts()[TERMISTOR_CONSTS - 1]; 509 | else 510 | { 511 | int pos = (temp + 40) / 5; 512 | int temp_dif = (temp + 40) % 5; 513 | 514 | if (temp_dif == 0) 515 | termistor = HIDOpenUPS2::GetTermistorConsts()[pos]; 516 | else 517 | { 518 | unsigned int d1 = HIDOpenUPS2::GetTermistorConsts()[pos]; 519 | unsigned int d2 = HIDOpenUPS2::GetTermistorConsts()[pos + 1]; 520 | 521 | termistor = d1 + temp_dif * (d2 - d1) / 5; 522 | } 523 | } 524 | 525 | c1 = (unsigned char)(((unsigned int)termistor) & 0xFF); 526 | c2 = (unsigned char)((((unsigned int)termistor) >> 8) & 0xFF); 527 | ok = true; 528 | } 529 | break; 530 | case 16: 531 | { 532 | TCHAR *end = NULL; 533 | val = _tcstod(str, &end); 534 | 535 | if ((val != 0) && (end != str)) 536 | { 537 | val = ceil(val / dMultiplier); 538 | unsigned int ival = (unsigned int)val; 539 | 540 | c1 = (unsigned char)(ival & 0xFF); 541 | c2 = (unsigned char)((ival >> 8) & 0xFF); 542 | c3 = (unsigned char)((ival >> 16) & 0xFF); 543 | c4 = (unsigned char)((ival >> 24) & 0xFF); 544 | ok = true; 545 | } 546 | } 547 | break; 548 | case 17: 549 | { 550 | _TCHAR *end = NULL; 551 | val = _tcstod(str, &end); 552 | if (end != str) 553 | ok = true; 554 | if ((val < 0) || (val > 255)) 555 | ok = false; 556 | } 557 | break; 558 | case 40: 559 | { 560 | _TCHAR *end = NULL; 561 | val = _tcstol(str, &end, 16); 562 | ok = true; 563 | } 564 | break; //hex 565 | case 1: 566 | //normal read - integer 567 | case 2: 568 | case 9: 569 | case 5: 570 | default: 571 | { //normal read - float 572 | _TCHAR *end = NULL; 573 | val = _tcstod(str, &end); 574 | 575 | if (end != str) 576 | ok = true; 577 | } 578 | } 579 | 580 | if (ok) 581 | { 582 | if ((nReadMode != 4) && (nReadMode != 7) && (nReadMode != 9) && (nReadMode != 11) && (nReadMode != 12) && (nReadMode != 13) && (nReadMode != 14) && (nReadMode != 15) && (nReadMode != 16)) 583 | { 584 | switch (nReadMode) 585 | { 586 | case 10: 587 | val /= HIDOpenUPS2::GetConstant((int)dMultiplier); 588 | break; 589 | case 30: 590 | val /= HIDOpenUPS2::GetConstant(6); 591 | break; 592 | default: 593 | val /= dMultiplier; 594 | } 595 | 596 | if (nReadMode != 5) 597 | { //unsigned 598 | if (val < 0) 599 | val = 0; 600 | double rem = val - (int)val; 601 | unsigned long uval = (unsigned long)val; 602 | if (rem >= 0.5) 603 | uval += 1; 604 | 605 | if (len == 1) 606 | { 607 | if (uval > 0xFF) 608 | uval = 0xFF; 609 | 610 | c1 = 0; 611 | c2 = (unsigned char)uval; 612 | } 613 | else 614 | { 615 | if (uval > 0xFFFF) 616 | uval = 0xFFFF; 617 | 618 | c1 = (unsigned char)(((unsigned int)uval) & 0xFF); 619 | c2 = (unsigned char)((((unsigned int)uval) >> 8) & 0xFF); 620 | } 621 | 622 | //DBGOutput(" uval1=%d %x\n",uval,uval); 623 | } 624 | else 625 | { 626 | double rem = -val + (int)val; 627 | long uval = (long)val; 628 | if (rem >= 0.5) 629 | uval += 1; 630 | 631 | if (len == 1) 632 | { 633 | if (uval > 127) 634 | uval = 127; 635 | if (uval < -128) 636 | uval = -128; 637 | 638 | c1 = 0; 639 | c2 = (char)uval; 640 | } 641 | else 642 | { 643 | if (uval > 32767) 644 | uval = 32767; 645 | if (uval < -32768) 646 | uval = -32768; 647 | 648 | c1 = (char)(((int)uval) & 0xFF); 649 | c2 = (char)((((int)uval) >> 8) & 0xFF); 650 | } 651 | //DBGOutput(" uval2=%d %x\n",uval,uval); 652 | } 653 | } 654 | } 655 | 656 | //DBGOutput("readOneValue %f [%02x][%02x]\n",(float)val,(unsigned int)c2,(unsigned int)c1); 657 | 658 | return ok; 659 | } 660 | 661 | void HIDOpenUPS2::convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier) 662 | { 663 | destination[0] = 0; //empty string 664 | double value = 0; 665 | 666 | if (nLen == 1) 667 | value = (double)m_chPackages[nIndex] * dMultiplier; 668 | else if (nLen == 2) 669 | value = (double)((((int)m_chPackages[nIndex + 1]) << 8) | m_chPackages[nIndex]) * dMultiplier; 670 | else if (nLen == 4) 671 | value = (double)((((int)m_chPackages[nIndex + 3]) << 24) | (((int)m_chPackages[nIndex + 2]) << 16) | (((int)m_chPackages[nIndex + 1]) << 8) | m_chPackages[nIndex]) * dMultiplier; 672 | 673 | switch (nReadMode) 674 | { 675 | case 2: 676 | case 9: 677 | sprintf(destination, "%.3f", (float)value); 678 | break; 679 | case 20: 680 | sprintf(destination, "%.2f", (float)value); 681 | break; 682 | case 10: 683 | { 684 | if (nLen == 1) 685 | value = (double)m_chPackages[nIndex] * HIDOpenUPS2::GetConstant((int)dMultiplier); 686 | else if (nLen == 2) 687 | value = (double)((((int)m_chPackages[nIndex + 1]) << 8) | m_chPackages[nIndex]) * HIDOpenUPS2::GetConstant((int)dMultiplier); 688 | else if (nLen == 4) 689 | value = (double)((((int)m_chPackages[nIndex + 3]) << 24) | (((int)m_chPackages[nIndex + 2]) << 16) | (((int)m_chPackages[nIndex + 1]) << 8) | m_chPackages[nIndex]) * HIDOpenUPS2::GetConstant((int)dMultiplier); 690 | sprintf(destination, "%.3f", (float)value); 691 | } 692 | break; 693 | case 30: 694 | { 695 | if (nLen == 1) 696 | value = (double)m_chPackages[nIndex] * HIDOpenUPS2::GetConstant(6); 697 | else if (nLen == 2) 698 | value = (double)((((int)m_chPackages[nIndex + 1]) << 8) | m_chPackages[nIndex]) * HIDOpenUPS2::GetConstant(6); 699 | else if (nLen == 4) 700 | value = (double)((((int)m_chPackages[nIndex + 3]) << 24) | (((int)m_chPackages[nIndex + 2]) << 16) | (((int)m_chPackages[nIndex + 1]) << 8) | m_chPackages[nIndex]) * HIDOpenUPS2::GetConstant(6); 701 | if (value > dMultiplier) 702 | value = dMultiplier; 703 | sprintf(destination, "%.3f", (float)value); 704 | } 705 | break; 706 | case 12: 707 | case 13: 708 | sprintf(destination, "%d", m_chPackages[nIndex]); 709 | break; 710 | case 14: 711 | char2bin(destination, m_chPackages[nIndex]); 712 | break; 713 | case 15: 714 | { 715 | unsigned int termistor = 0; 716 | termistor = m_chPackages[nIndex + 1]; 717 | termistor = (termistor << 8) | m_chPackages[nIndex]; 718 | 719 | if (termistor <= HIDOpenUPS2::GetTermistorConsts()[0]) 720 | strcpy(destination, "-40"); 721 | else if (termistor >= HIDOpenUPS2::GetTermistorConsts()[TERMISTOR_CONSTS - 1]) 722 | strcpy(destination, "125"); 723 | else 724 | { 725 | int pos = -1; 726 | for (int i = TERMISTOR_CONSTS - 1; i >= 0; i--) 727 | { 728 | if (termistor >= HIDOpenUPS2::GetTermistorConsts()[i]) 729 | { 730 | pos = i; 731 | break; 732 | } 733 | } 734 | 735 | //if (termistor != HIDOpenUPS2::GetTermistorConsts()[i]) pos--;//latest value which is smaller than my one 736 | if (termistor == HIDOpenUPS2::GetTermistorConsts()[pos]) 737 | sprintf(destination, "%d", pos * 5 - 40); 738 | else 739 | { 740 | int t1 = pos * 5 - 40; 741 | int t2 = (pos + 1) * 5 - 40; 742 | 743 | unsigned int d1 = HIDOpenUPS2::GetTermistorConsts()[pos]; 744 | unsigned int d2 = HIDOpenUPS2::GetTermistorConsts()[pos + 1]; 745 | 746 | float dtemp = ((float)termistor - (float)d1) * ((float)t2 - (float)t1) / ((float)d2 - (float)d1); 747 | 748 | int temp = (int)ceil(dtemp) + t1; 749 | 750 | sprintf(destination, "%d", temp); 751 | } 752 | } 753 | } 754 | break; 755 | case 16: 756 | { //4 byte value 757 | if (dMultiplier == 1) 758 | sprintf(destination, "%.0f", (float)value); 759 | else 760 | sprintf(destination, "%.2f", (float)value); 761 | } 762 | break; 763 | case 17: 764 | { 765 | sprintf(destination, "%d", (int)value); 766 | } 767 | break; 768 | case 3: 769 | { 770 | unsigned int ivalue = (unsigned int)value; 771 | if (ivalue == 0xFFFF) 772 | strcpy(destination, "Never"); 773 | else 774 | sprintf(destination, "%02d:%02d:%02d", ivalue / 3600, (ivalue / 60) % 60, ivalue % 60); 775 | } 776 | break; 777 | case 4: 778 | { 779 | double dvalue = (m_chPackages[nIndex] & 0x7f) * dMultiplier; 780 | if ((m_chPackages[nIndex] & 0x80) != 0) 781 | sprintf(destination, "-%.3f", (float)value); 782 | else 783 | sprintf(destination, "%.3f", (float)value); 784 | } 785 | break; 786 | case 5: 787 | { 788 | sprintf(destination, "%d", (int)value); 789 | } 790 | break; 791 | case 6: 792 | { 793 | strcpy(destination, "-"); 794 | } 795 | break; 796 | case 7: 797 | { //no multiplier - voltage value calcualted with formula 798 | //! sprintf(destination, "%.3f", HIDOpenUPS2::GetVoltageVOut(m_chPackages[nIndex])); 799 | } 800 | break; 801 | case 8: 802 | { 803 | if (nLen == 1) 804 | { 805 | if (m_chPackages[nIndex] == 0xFF) 806 | strcpy(destination, "Never"); 807 | else 808 | sprintf(destination, "%d", (int)value); 809 | } 810 | else 811 | { 812 | if ((m_chPackages[nIndex] == 0xFF) && (m_chPackages[nIndex + 1] == 0xFF)) 813 | strcpy(destination, "Never"); 814 | else 815 | sprintf(destination, "%d", (int)value); 816 | } 817 | } 818 | break; 819 | case 40: //hex 820 | if (nLen == 1) 821 | sprintf(destination, "%02x", (int)value); 822 | else if (nLen == 2) 823 | sprintf(destination, "%04x", (int)value); 824 | else if (nLen == 4) 825 | sprintf(destination, "%08x", (int)value); 826 | break; 827 | case 1: 828 | default: 829 | { 830 | sprintf(destination, "%d", (int)value); 831 | } 832 | } 833 | 834 | //DBGOutput("convertOneValue2String %d %s %f [%x][%x]\n",nIndex,destination,(float)value,(int)m_chPackages[nIndex],(int)m_chPackages[nIndex+1]); 835 | } 836 | 837 | bool HIDOpenUPS2::setVariableData(int mesg_no, char *str) 838 | { 839 | int len = HIDOpenUPS2::GetMessages()[mesg_no].nLen; 840 | 841 | if (len != 0) 842 | { 843 | unsigned char c1 = 0; 844 | unsigned char c2 = 0; 845 | unsigned char c3 = 0; 846 | unsigned char c4 = 0; 847 | 848 | if (readOneValue(str, HIDOpenUPS2::GetMessages()[mesg_no].nReadMode, HIDOpenUPS2::GetMessages()[mesg_no].dMultiplier, len, c1, c2, c3, c4)) 849 | { 850 | switch (len) 851 | { 852 | case 1: 853 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex] = c2; 854 | break; 855 | case 2: 856 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex] = c1; 857 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex + 1] = c2; 858 | break; 859 | case 4: 860 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex] = c1; 861 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex + 1] = c2; 862 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex + 2] = c3; 863 | m_chPackages[HIDOpenUPS2::GetMessages()[mesg_no].nIndex + 3] = c4; 864 | break; 865 | } 866 | return 1; 867 | } 868 | else 869 | return 0; 870 | } 871 | return 1; 872 | } 873 | 874 | unsigned char HIDOpenUPS2::getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment) 875 | { 876 | if ((cnt < 0) || (cnt >= MAX_MESSAGE_CNT)) 877 | return 0; 878 | 879 | if (HIDOpenUPS2::GetMessages()[cnt].nLen == 0) 880 | return 0; 881 | 882 | if (name) 883 | strcpy(name, HIDOpenUPS2::GetMessages()[cnt].strName); 884 | if (unit) 885 | strcpy(unit, HIDOpenUPS2::GetMessages()[cnt].strUnit); 886 | if (comment) 887 | strcpy(comment, HIDOpenUPS2::GetMessages()[cnt].strText); 888 | 889 | if (value) 890 | { 891 | convertOneValue2String(value, HIDOpenUPS2::GetMessages()[cnt].nLen, 892 | HIDOpenUPS2::GetMessages()[cnt].nIndex, 893 | HIDOpenUPS2::GetMessages()[cnt].nReadMode, 894 | HIDOpenUPS2::GetMessages()[cnt].dMultiplier); 895 | } 896 | 897 | return HIDOpenUPS2::GetMessages()[cnt].nReadMode; 898 | } 899 | 900 | void HIDOpenUPS2::restartUPS() 901 | { 902 | sendCommand(OPENUPS2_DCMD_RESTART_UPS, 1); 903 | } 904 | 905 | void HIDOpenUPS2::restartUPSInBootloaderMode() 906 | { 907 | sendMessage(OPENUPS2_ENTER_BOOTLOADER_OUT, 2, 0xFA, 0xCD); 908 | } 909 | 910 | void HIDOpenUPS2::setVOutVolatile(float vout) 911 | { 912 | int voltage = (int)(vout * 1000.0);//mV 913 | sendCommandEx(OPENUPS2_DCMD_SPI_WRITE_DATA_VOL_VOUT, (voltage >> 8) & 0xFF, voltage & 0xFF); 914 | } 915 | 916 | void HIDOpenUPS2::incDecVOutVolatile(unsigned char inc) 917 | { 918 | if (inc) // wiper is opposite to vout 919 | sendCommand(OPENUPS2_DCMD_SPI_DEC_VOL_WIPER_VOUT, 0); 920 | else 921 | sendCommand(OPENUPS2_DCMD_SPI_INC_VOL_WIPER_VOUT, 0); 922 | } 923 | 924 | void HIDOpenUPS2::GetStatus() 925 | { 926 | unsigned char recv[32]; 927 | int ret; 928 | 929 | sendMessage(OPENUPS2_GET_ALL_VALUES, 0); 930 | recvMessage(recv); 931 | parseMessage(recv); 932 | 933 | ret = sendMessage(OPENUPS2_GET_ALL_VALUES_2, 0); 934 | recvMessage(recv); 935 | parseMessage(recv); 936 | 937 | ret = sendMessage(OPENUPS2_GET_ALL_VALUES_3, 0); 938 | recvMessage(recv); 939 | parseMessage(recv); 940 | 941 | ret = sendMessage(OPENUPS2_CLOCK_OUT, 0); 942 | recvMessage(recv); 943 | parseMessage(recv); 944 | } 945 | 946 | void HIDOpenUPS2::ReadConfigurationMemory() 947 | { 948 | unsigned char recv[32]; 949 | 950 | m_ulSettingsAddr = OPENUPS2_SETTINGS_ADDR_START; 951 | memset(m_chPackages, 0, SETTINGS_PACKS * 16); 952 | 953 | while (m_ulSettingsAddr < OPENUPS2_SETTINGS_ADDR_END) 954 | { 955 | sendMessage(OPENUPS2_MEM_READ_OUT, 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x10); 956 | recvMessage(recv); 957 | parseMessage(recv); 958 | m_ulSettingsAddr += 16; 959 | } 960 | } 961 | 962 | void HIDOpenUPS2::EraseConfigurationMemory() 963 | { 964 | unsigned char recv[32]; 965 | int ret; 966 | 967 | m_ulSettingsAddr = OPENUPS2_SETTINGS_ADDR_START; 968 | sendMessage(OPENUPS2_MEM_ERASE, 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x40); 969 | 970 | int retries = 5; 971 | while ((ret = recvMessage(recv) <= 0) && retries > 0) { 972 | retries--; 973 | usleep(500); 974 | fprintf(stderr, "Erase 0x%02x retry %d/5\n", recv[0], retries); 975 | } 976 | 977 | if (retries <= 0) { 978 | fprintf(stderr, "Error waiting for erase operation to finish\n"); 979 | } else { 980 | fprintf(stderr, "Successfully erased (0x%02x) configuration memory\n", recv[0]); 981 | } 982 | } 983 | 984 | void HIDOpenUPS2::WriteConfigurationMemory() 985 | { 986 | unsigned char recv[32]; 987 | int ret; 988 | 989 | m_ulSettingsAddr = OPENUPS2_SETTINGS_ADDR_START; 990 | while (m_ulSettingsAddr < OPENUPS2_SETTINGS_ADDR_END) 991 | { 992 | sendMessageWithBuffer(OPENUPS2_MEM_WRITE_OUT, 16, m_chPackages+(m_ulSettingsAddr-OPENUPS2_SETTINGS_ADDR_START), 4, m_ulSettingsAddr & 0xFF, (m_ulSettingsAddr >> 8) & 0xFF, 0x00, 0x10); 993 | ret = recvMessage(recv); 994 | 995 | if (ret <= 0 || recv[0] != OPENUPS2_MEM_WRITE_IN) { 996 | fprintf(stderr, "Error (%d, 0x%02x) writing configuration variables , aborting ...\n", ret, recv[0]); 997 | break; 998 | } else { 999 | //fprintf(stderr, "Wrote page 0x%lx of configuration\n", m_ulSettingsAddr); 1000 | } 1001 | m_ulSettingsAddr += 16; 1002 | } 1003 | } -------------------------------------------------------------------------------- /src/lib/HIDOpenUPS2.h: -------------------------------------------------------------------------------- 1 | #ifndef _HIDOPENUPS2_H_ 2 | #define _HIDOPENUPS2_H_ 3 | 4 | #include "HIDInterface.h" 5 | #include "usbhid.h" 6 | 7 | #include "HArray.h" 8 | #include "HLock.h" 9 | #include "HList.h" 10 | 11 | #define OPENUPS2_MSG_READ 32 12 | #define OPENUPS2_MSG_WRITE 32 13 | 14 | #define MAX_BUF 500 15 | 16 | #define ETA_CHG (double)0.90 17 | 18 | #define STATUS_OK 0x00 19 | #define STATUS_ERASE 0x01 20 | #define STATUS_WRITE 0x02 21 | #define STATUS_READ 0x03 22 | #define STATUS_ERROR 0xff 23 | 24 | #define OPENUPS2_GET_ALL_VALUES 0x81 25 | #define OPENUPS2_RECV_ALL_VALUES 0x82 26 | #define OPENUPS2_CLOCK_OUT 0x83 27 | #define OPENUPS2_CLOCK_IN 0x84 28 | #define OPENUPS2_GET_ALL_VALUES_2 0x85 29 | #define OPENUPS2_RECV_ALL_VALUES_2 0x86 30 | #define OPENUPS2_GET_ALL_VALUES_3 0x87 31 | #define OPENUPS2_RECV_ALL_VALUES_3 0x88 32 | #define OPENUPS2_CMD_OUT 0xB1 33 | #define OPENUPS2_CMD_IN 0xB2 34 | #define OPENUPS2_MEM_READ_OUT 0xA1 35 | #define OPENUPS2_MEM_READ_IN 0xA2 36 | #define OPENUPS2_MEM_WRITE_OUT 0xA3 37 | #define OPENUPS2_MEM_WRITE_IN 0xA4 38 | #define OPENUPS2_MEM_ERASE 0xA5 39 | 40 | #define OPENUPS2_ENTER_BOOTLOADER_OUT 0xA9 41 | #define OPENUPS2_ENTER_BOOTLOADER_IN 0xAA 42 | 43 | #define INTERNAL_MESG 0xFF 44 | #define INTERNAL_MESG_DISCONNECTED 0x01 45 | 46 | //commands 47 | #define OPENUPS2_DCMD_FORCE_PRECHARGE 0x01 48 | #define OPENUPS2_DCMD_ENABLE_CHARGE 0x02 49 | #define OPENUPS2_DCMD_PSW 0x03 50 | #define OPENUPS2_DCMD_RELAY 0x04 51 | #define OPENUPS2_DCMD_ENABLE_OUTPUT 0x05 52 | #define OPENUPS2_DCMD_LDO_EN 0x07 53 | 54 | #define OPENUPS2_DCMD_CELL1_DISCHARGE 0x11 55 | #define OPENUPS2_DCMD_CELL2_DISCHARGE 0x12 56 | #define OPENUPS2_DCMD_CELL3_DISCHARGE 0x13 57 | #define OPENUPS2_DCMD_CELL4_DISCHARGE 0x14 58 | #define OPENUPS2_DCMD_CELL5_DISCHARGE 0x15 59 | #define OPENUPS2_DCMD_CELL6_DISCHARGE 0x16 60 | 61 | #define OPENUPS2_DCMD_SPI_CS_AD 0x21 62 | #define OPENUPS2_DCMD_SPI_CS_VBAT 0x22 63 | #define OPENUPS2_DCMD_SPI_CS_TEMP 0x23 64 | #define OPENUPS2_DCMD_SPI_CS_VOUT 0x24 65 | #define OPENUPS2_DCMD_SPI_CLK 0x25 66 | #define OPENUPS2_DCMD_SPI_DATAOUT 0x26 67 | 68 | #define OPENUPS2_DCMD_SPI_WRITE_DATA_VOL_VOUT 0x30 69 | #define OPENUPS2_DCMD_SPI_READ_DATA_VOL_VOUT 0x31 70 | #define OPENUPS2_DCMD_SPI_INC_VOL_WIPER_VOUT 0x32 71 | #define OPENUPS2_DCMD_SPI_DEC_VOL_WIPER_VOUT 0x33 72 | #define OPENUPS2_DCMD_SPI_VOUT_STAT 0x34 73 | #define OPENUPS2_DCMD_SPI_VOUT_TCON 0x35 74 | 75 | #define OPENUPS2_DCMD_SPI_READ_AD_CHANNEL 0x36 76 | 77 | #define OPENUPS2_DCMD_SPI_WRITE_DATA_VOL_VCHG 0x40 78 | #define OPENUPS2_DCMD_SPI_READ_DATA_VOL_VCHG 0x41 79 | //#define OPENUPS2_DCMD_SPI_INC_VOL_WIPER_VCHG 0x42 80 | //#define OPENUPS2_DCMD_SPI_DEC_VOL_WIPER_VCHG 0x43 81 | #define OPENUPS2_DCMD_I2C_INC_VOL_WIPER_VCHG_ROUGH 0x45 82 | #define OPENUPS2_DCMD_I2C_DEC_VOL_WIPER_VCHG_ROUGH 0x46 83 | #define OPENUPS2_DCMD_I2C_INC_VOL_WIPER_VCHG_FINE 0x47 84 | #define OPENUPS2_DCMD_I2C_DEC_VOL_WIPER_VCHG_FINE 0x48 85 | 86 | #define OPENUPS2_DCMD_LED 0x50 87 | #define OPENUPS2_DCMD_READ_AFE 0x51 88 | #define OPENUPS2_DCMD_WRITE_AFE 0x52 89 | 90 | #define OPENUPS2_DCMD_SET_UVP_LOW 0x70 91 | #define OPENUPS2_DCMD_SET_UVP_HIGH 0x71 92 | 93 | #define OPENUPS2_DCMD_SET_OUTPUT_FREQUENCY 0x72 94 | #define OPENUPS2_DCMD_SET_CHARGE_FREQUENCY 0x73 95 | 96 | #define OPENUPS2_DCMD_RESTART_UPS 0xAA 97 | 98 | //For reading out memory 99 | #define TYPE_CODE_MEMORY 0x00 100 | #define TYPE_EPROM_EXTERNAL 0x01 101 | #define TYPE_EPROM_INTERNAL 0x02 102 | #define TYPE_CODE_SPLASH 0x03 103 | 104 | #define FLASH_REPORT_ERASE_MEMORY 0xF2 // AddressLo : AddressHi : AddressUp (anywhere inside the 64 byte-block to be erased) 105 | #define FLASH_REPORT_READ_MEMORY 0xF3 // AddressLo : AddressHi : AddressUp : Data Length (1...32) 106 | #define FLASH_REPORT_WRITE_MEMORY 0xF4 // AddressLo : AddressHi : AddressUp : Data Length (1...32) : Data.... 107 | #define KEYBD_REPORT_ERASE_MEMORY 0xB2 // same as F2 but in keyboard mode 108 | #define KEYBD_REPORT_READ_MEMORY 0xB3 // same as F3 but in keyboard mode 109 | #define KEYBD_REPORT_WRITE_MEMORY 0xB4 // same as F4 but in keyboard mode 110 | #define KEYBD_REPORT_MEMORY 0x41 // response to b3,b4 111 | 112 | #define IN_REPORT_EXT_EE_DATA 0x31 113 | #define OUT_REPORT_EXT_EE_READ 0xA1 114 | #define OUT_REPORT_EXT_EE_WRITE 0xA2 115 | 116 | #define IN_REPORT_INT_EE_DATA 0x32 117 | #define OUT_REPORT_INT_EE_READ 0xA3 118 | #define OUT_REPORT_INT_EE_WRITE 0xA4 119 | 120 | ///// MEASUREMENT CONSTANTS 121 | #define OPENUPS2_CT_RW (double)75 122 | #define OPENUPS2_CT_RP (double)5000 123 | #define OPENUPS2_CT_R1_VOUT (double)56200 124 | #define OPENUPS2_CT_R2_VOUT (double)2740 125 | #define OPENUPS2_CT_V_FEEDBACK_OUT (double)1.2 126 | 127 | #define CHECK_CHAR (unsigned char)0xAA //used for line/write check 128 | 129 | #define MAX_MESSAGE_CNT 256 130 | 131 | #define TERMISTOR_CONSTS 34 132 | 133 | #define OPENUPS2_SETTINGS_ADDR_START 0x007800 134 | #define OPENUPS2_SETTINGS_ADDR_END 0x007C00 135 | #define OPENUPS2_SETTINGS_ADDR_CALIBR_START 0x0078D0 136 | #define OPENUPS2_SETTINGS_ADDR_CALIBR_END 0x007900 137 | #define OPENUPS2_SETTINGS_PACKS 64 138 | #define OPENUPS2_SCRIPTS_PACKS 4 139 | #define OPENUPS2_SCRIPT_START_ADDR 0x3C00//3F80 140 | #define OPENUPS2_SCRIPT_END_ADDR 0x3BF0 141 | 142 | 143 | class HIDOpenUPS2 : public HIDInterface 144 | { 145 | public: 146 | HIDOpenUPS2(USBHID *d); 147 | virtual ~HIDOpenUPS2(); 148 | 149 | void parseMessage(unsigned char *msg); 150 | void printValues(); 151 | void printConfiguration(); 152 | 153 | bool readOneValue(char *str, int nReadMode, double dMultiplier, int len, unsigned char &c1, unsigned char &c2, unsigned char &c3, unsigned char &c4); 154 | float convertOneValue2Float(unsigned char *buffer, int nLen, int nIndex, int nReadMode, double dMultiplier); 155 | void convertOneValue2String(char *destination, int nLen, int nIndex, int nReadMode, double dMultiplier); 156 | bool setVariableData(int mesg_no, char *str); 157 | ATXMSG* GetMessages(); 158 | double GetConstant(int i); 159 | unsigned int* GetTermistorConsts(); 160 | int GetMessageIdxByName(const char* name); 161 | unsigned char getUPSVariableData(unsigned int cnt, char *name, char *value, char *unit, char *comment); 162 | void restartUPS(); 163 | void restartUPSInBootloaderMode(); 164 | void setVOutVolatile(float vout); 165 | void incDecVOutVolatile(unsigned char inc); 166 | 167 | void GetStatus(); 168 | void ReadConfigurationMemory(); 169 | void EraseConfigurationMemory(); 170 | void WriteConfigurationMemory(); 171 | 172 | 173 | private: 174 | float m_fVIN; 175 | float m_fVBat; 176 | float m_fVOut; 177 | float m_fCCharge; 178 | float m_fCDischarge; 179 | float m_fTemperature[3]; 180 | float m_fVCell[3]; 181 | float m_fVDuty; 182 | unsigned char m_bCheck23[8]; 183 | unsigned char m_bCheck24[8]; 184 | unsigned char m_bCheck25[8]; 185 | 186 | unsigned char m_nVerMajor; 187 | unsigned char m_nVerMinor; 188 | 189 | unsigned char m_nState; //offline,usb,batpowered,vinpowered 190 | 191 | unsigned char m_bStateUPS; 192 | unsigned char m_bStateCHG; 193 | unsigned char m_bStateDBG; 194 | unsigned char m_bCapacity; 195 | unsigned char m_bBatOn[3]; 196 | unsigned int m_nRTE; 197 | unsigned char m_bUPSMode; 198 | 199 | unsigned char m_bVOutPot; 200 | unsigned char m_bConfigSwitch; 201 | 202 | unsigned char m_bDBG[DBG_LEN]; //4 byte + 8 byte + 4 byte 203 | unsigned char m_bDBG2[30]; 204 | 205 | unsigned int m_nShutdownType; //from FW 1.4 206 | 207 | unsigned char m_chStateMachine; 208 | unsigned char m_nLoadCfgStatus; 209 | unsigned char m_nSaveCfgStatus; 210 | }; 211 | 212 | #endif 213 | -------------------------------------------------------------------------------- /src/lib/usbhid.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nicu Pavel 3 | * Copyright (c) 2020 Mini-Box.com 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | */ 7 | 8 | #include "usbhid.h" 9 | #include 10 | #include 11 | #include 12 | 13 | #undef DEBUG_RECV 14 | 15 | USBHID::USBHID(unsigned int vendorid, unsigned int productid, unsigned int max_transfer_size, unsigned int index) 16 | { 17 | this->vendorid = vendorid; 18 | this->productid = productid; 19 | this->index = index; 20 | this->device = NULL; 21 | this->handle = NULL; 22 | this->connected = false; 23 | this->max_transfer_size = max_transfer_size; 24 | 25 | usb_init(); 26 | usb_set_debug(0); 27 | usb_find_busses(); 28 | usb_find_devices(); 29 | } 30 | 31 | USBHID::~USBHID() {} 32 | 33 | struct usb_dev_handle *USBHID::open(void) 34 | { 35 | char buf[65535]; 36 | 37 | this->device = this->find(); 38 | 39 | if (this->device == NULL) 40 | { 41 | fprintf(stderr, "Device [0x%04x: 0x%04x] not detected !\n", this->vendorid, this->productid); 42 | return NULL; 43 | } 44 | this->handle = usb_open(this->device); 45 | int ret = usb_get_driver_np(this->handle, 0, buf, sizeof(buf)); 46 | 47 | if (ret == 0) 48 | { 49 | fprintf(stderr, "interface 0 already claimed by driver \"%s\", attempting to detach it\n", buf); 50 | ret = usb_detach_kernel_driver_np(this->handle, 0); 51 | fprintf(stderr, "usb_detach_kernel_driver_np returned %d\n", ret); 52 | } 53 | usleep(1000); 54 | 55 | ret = usb_claim_interface(this->handle, 0); 56 | if (ret != 0) 57 | { 58 | printf("claim failed with error %d\n", ret); 59 | return NULL; 60 | } 61 | 62 | ret = usb_set_altinterface(this->handle, 0); 63 | 64 | fprintf(stdout, "Product: %s, Manufacturer: %s, Firmware Version: %s\n", this->getProduct(), this->getManufacturer(), this->getSerial()); 65 | 66 | connected = true; 67 | return this->handle; 68 | } 69 | 70 | struct usb_device *USBHID::find(void) 71 | { 72 | struct usb_bus *bus; 73 | unsigned int i = 0; 74 | 75 | for (bus = usb_get_busses(); bus; bus = bus->next) 76 | { 77 | struct usb_device *dev; 78 | for (dev = bus->devices; dev; dev = dev->next) 79 | { 80 | if (dev->descriptor.idVendor == this->vendorid && dev->descriptor.idProduct == this->productid) 81 | { 82 | if (i == this->index) 83 | { 84 | return dev; 85 | } else { 86 | i++; 87 | } 88 | } 89 | } 90 | } 91 | return NULL; 92 | } 93 | 94 | char *USBHID::getProduct() 95 | { 96 | int len; 97 | int BUFLEN = 256; 98 | char *buffer; 99 | 100 | buffer = (char *)malloc(BUFLEN); 101 | 102 | if (buffer == NULL) 103 | return NULL; 104 | 105 | if (this->device->descriptor.iProduct) 106 | { 107 | len = usb_get_string_simple(this->handle, this->device->descriptor.iProduct, buffer, BUFLEN); 108 | 109 | if (len > 0) 110 | return buffer; 111 | } 112 | 113 | free(buffer); 114 | return NULL; 115 | } 116 | 117 | char *USBHID::getManufacturer() 118 | { 119 | int len; 120 | int BUFLEN = 256; 121 | char *buffer; 122 | 123 | buffer = (char *)malloc(BUFLEN); 124 | 125 | if (buffer == NULL) 126 | return NULL; 127 | 128 | if (this->device->descriptor.iManufacturer) 129 | { 130 | len = usb_get_string_simple(this->handle, this->device->descriptor.iManufacturer, buffer, BUFLEN); 131 | 132 | if (len > 0) 133 | return buffer; 134 | } 135 | 136 | free(buffer); 137 | return NULL; 138 | } 139 | 140 | char *USBHID::getSerial() 141 | { 142 | int len; 143 | int BUFLEN = 256; 144 | char *buffer; 145 | 146 | buffer = (char *)malloc(BUFLEN); 147 | 148 | if (buffer == NULL) 149 | return NULL; 150 | 151 | if (this->device->descriptor.iSerialNumber) 152 | { 153 | len = usb_get_string_simple(this->handle, this->device->descriptor.iSerialNumber, buffer, BUFLEN); 154 | 155 | if (len > 0) 156 | return buffer; 157 | } 158 | 159 | free(buffer); 160 | return NULL; 161 | } 162 | 163 | int USBHID::readInterrupt(unsigned char *buff, int size) 164 | { 165 | if (buff == NULL) { 166 | fprintf(stderr, "Invalid read buffer, skipping read\n"); 167 | return -1; 168 | } 169 | 170 | int ret = usb_interrupt_read((usb_dev_handle *)this->handle, USB_ENDPOINT_IN + 1, 171 | reinterpret_cast(buff), size, 172 | USBHID_RECV_TIMEOUT); 173 | 174 | #ifdef DEBUG_RECV 175 | for (int j = 0; j < size; j++) { 176 | fprintf(stderr, " 0x%02x ", buff[j]); 177 | } 178 | fprintf(stderr, "\n"); 179 | #endif 180 | if (ret < 0) 181 | fprintf(stderr, "hid_interrupt_read failed with return code %d\n", ret); 182 | 183 | return ret; 184 | } 185 | 186 | int USBHID::readInterrupt(unsigned char *buff) { 187 | return readInterrupt(buff, max_transfer_size); 188 | } 189 | 190 | int USBHID::writeInterrupt(unsigned char *buff, int size, bool use_transfer_size) 191 | { 192 | if (buff == NULL) { 193 | fprintf(stderr, "Invalid write buffer, skipping write\n"); 194 | return -1; 195 | } 196 | 197 | unsigned char *packet; 198 | if (use_transfer_size) { 199 | if ((packet = (unsigned char*) malloc(max_transfer_size)) == NULL) { 200 | return -2; 201 | } 202 | 203 | if (size > max_transfer_size) { 204 | fprintf(stderr, "Warning: Multi-packet write not implemented !"); 205 | size = max_transfer_size; 206 | } 207 | memset(packet, 0x00, max_transfer_size); 208 | memcpy(packet, buff, size); 209 | size = max_transfer_size; 210 | } else { 211 | packet = buff; 212 | } 213 | 214 | 215 | int ret = usb_interrupt_write((usb_dev_handle *)this->handle, USB_ENDPOINT_OUT + 1, 216 | reinterpret_cast(packet), size, 217 | USBHID_SEND_TIMEOUT); 218 | 219 | if (ret < 0) 220 | fprintf(stderr, "hid_interrupt_write failed with return code %d\n", ret); 221 | 222 | if (use_transfer_size) { 223 | free(packet); 224 | } 225 | 226 | return ret; 227 | } 228 | 229 | bool USBHID::isOpened() { 230 | return connected; 231 | } 232 | 233 | int USBHID::release() 234 | { 235 | int ret = -1; 236 | ret = usb_release_interface(this->handle, 0); 237 | if (ret < 0) 238 | printf("failed to release interface: %d\n", ret); 239 | 240 | return ret; 241 | } 242 | 243 | int USBHID::close() 244 | { 245 | 246 | release(); 247 | int ret = usb_close(this->handle); 248 | 249 | if (ret < 0) 250 | { 251 | fprintf(stderr, "hid_close failed with return code %d\n", ret); 252 | return 1; 253 | } 254 | 255 | connected = false; 256 | return 0; 257 | } 258 | -------------------------------------------------------------------------------- /src/lib/usbhid.h: -------------------------------------------------------------------------------- 1 | #ifndef _USBHID_H_ 2 | #define _USBHID_H_ 3 | 4 | #include 5 | 6 | #define USBHID_RECV_TIMEOUT 1000 7 | #define USBHID_SEND_TIMEOUT 1000 8 | 9 | class USBHID { 10 | public: 11 | USBHID(unsigned int vendorid, unsigned int productid, unsigned int max_transfer_size, unsigned int index); 12 | ~USBHID(); 13 | 14 | struct usb_dev_handle* open(void); 15 | char *getProduct(); 16 | char *getManufacturer(); 17 | char *getSerial(); 18 | bool isOpened(); 19 | int readInterrupt(unsigned char *buff); 20 | int readInterrupt(unsigned char *buff, int size); 21 | int writeInterrupt(unsigned char *buff, int size, bool use_transfer_size); 22 | int close(); 23 | 24 | private: 25 | unsigned int id; 26 | unsigned int vendorid; 27 | unsigned int productid; 28 | unsigned int max_transfer_size; 29 | unsigned int index; 30 | bool connected; 31 | struct usb_device *device; 32 | struct usb_dev_handle *handle; 33 | 34 | struct usb_device *find(void); 35 | int release(); 36 | }; 37 | 38 | #endif //_USBHID_H_ 39 | -------------------------------------------------------------------------------- /src/main.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Author: Nicu Pavel 3 | * Copyright (c) 2020 Mini-Box.com 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | */ 7 | 8 | 9 | #include "devices.h" 10 | #include "version.h" 11 | #include "util.h" 12 | #include "usbhid.h" 13 | #include "HArray.h" 14 | #include "HIDDCDCUSB.h" 15 | #include "HIDOpenUPS.h" 16 | #include "HIDOpenUPS2.h" 17 | #include "HIDNUCUPS.h" 18 | #include "HIDInterface.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | 28 | static const struct deviceId* findDeviceByName(const char *name) 29 | { 30 | for(int i = 0; deviceIds[i].name != NULL; i++) { 31 | if (strcasecmp(name, deviceIds[i].name) == 0) { 32 | return &deviceIds[i]; 33 | } 34 | } 35 | 36 | return NULL; 37 | } 38 | 39 | static int printDeviceCommands(const struct deviceCmd *cmds) 40 | { 41 | int i; 42 | 43 | if (!cmds) { 44 | return 0; 45 | } 46 | fprintf(stderr, "\n"); 47 | for (i = 0; cmds[i].cmd != NULL; i++) { 48 | fprintf(stderr, "\t%s - %s\n", cmds[i].cmd, cmds[i].desc); 49 | } 50 | 51 | return i; 52 | } 53 | 54 | int usage(char *progname) 55 | { 56 | fprintf(stderr, 57 | "Usage: %s []\n" 58 | "Options:\n" 59 | " -t : Select device model (see below)\n" 60 | " -n : Select nth connected device of this model (default 0)\n" 61 | " -i : Write settings from this file. Warning: Will reboot UPS!\n" 62 | " -o : Dump settings to this file\n" 63 | " -c: Add comments for each configuration variable to output file\n" 64 | " -s: Only output status don't read and show configuration variables\n" 65 | " -e : Execute command.\n" 66 | " -r Restart UPS only and exit \n" 67 | " -b Restart UPS to bootloader and exit \n" 68 | "\n", 69 | progname); 70 | 71 | fprintf(stderr, "Known device models:\n"); 72 | for(int i = 0; deviceIds[i].name != NULL; i++) { 73 | fprintf(stderr, " %s \t- %s (vid: 0x%04x pid: 0x%04x)\n", deviceIds[i].name, deviceIds[i].desc, deviceIds[i].vendorid, deviceIds[i].productid); 74 | fprintf(stderr, " Available Commands: "); 75 | if (printDeviceCommands(deviceIds[i].cmds) == 0) { 76 | fprintf(stderr, " None\n"); 77 | }; 78 | } 79 | return 3; 80 | } 81 | 82 | int main(int argc, char **argv) 83 | { 84 | 85 | int ret, c; 86 | char *progname = basename(argv[0]); 87 | char *devicetype = NULL; 88 | char *infile = NULL; 89 | char *outfile = NULL; 90 | bool withComments = false; 91 | bool withConfiguration = true; 92 | bool doReset = false; 93 | bool goBootloader = false; 94 | char *execCmd = NULL; 95 | unsigned long index = 0; 96 | 97 | if (argc < 2) 98 | return usage(progname); 99 | 100 | while ((c = getopt(argc, argv, "t:i:o:e:cshrbn:")) != -1) { 101 | switch (c) { 102 | 103 | case 't': 104 | devicetype = optarg; 105 | break; 106 | case 'i': 107 | infile = optarg; 108 | break; 109 | case 'o': 110 | outfile = optarg; 111 | break; 112 | case 'c': 113 | withComments = true; 114 | break; 115 | case 's': 116 | withConfiguration = false; 117 | break; 118 | case 'e': 119 | execCmd = optarg; 120 | break; 121 | case 'h': 122 | usage(progname); 123 | break; 124 | case 'r': 125 | doReset = true; 126 | break; 127 | case 'b': 128 | goBootloader = true; 129 | break; 130 | case 'n': 131 | errno = 0; 132 | index = strtoul(optarg, NULL, 10); 133 | if (errno != 0) { 134 | perror("error in value for -n"); 135 | return usage(progname); 136 | } 137 | if (index > UINT_MAX) { 138 | fprintf(stderr, "error in value for -n: too big\n"); 139 | return usage(progname); 140 | } 141 | break; 142 | default: 143 | usage(progname); 144 | } 145 | } 146 | 147 | fprintf(stdout, "%s version %s. Device selected: %s\n", progname, VERSION, devicetype); 148 | if (!devicetype) { 149 | fprintf(stderr, "No device type selected !\n"); 150 | return usage(progname); 151 | } 152 | 153 | const struct deviceId *devid = findDeviceByName(devicetype); 154 | 155 | if (devid == NULL) { 156 | fprintf(stderr, "Device '%s' unknown\n", devicetype); 157 | return 1; 158 | } else { 159 | fprintf(stderr, "Selected device %s: %s\n", devid->name, devid->desc); 160 | } 161 | 162 | USBHID *d = new USBHID(devid->vendorid, devid->productid, devid->max_transfer_size, (unsigned int) index); 163 | 164 | d->open(); 165 | if (!d->isOpened()) 166 | { 167 | fprintf(stderr, "Failed to open USB device\n"); 168 | return 2; 169 | } 170 | 171 | HIDInterface *ups; 172 | 173 | if (devid->productid == DCDCUSB_PRODUCT_ID) { 174 | ups = new HIDDCDCUSB(d); 175 | } else if (devid->productid == OPENUPS_PRODUCT_ID) { 176 | ups = new HIDOpenUPS(d); 177 | } else if (devid->productid == OPENUPS2_PRODUCT_ID) { 178 | ups = new HIDOpenUPS2(d); 179 | } else if (devid->productid == NUCUPS_PRODUCT_ID) { 180 | ups = new HIDNUCUPS(d); 181 | } else { 182 | fprintf(stderr, "Unknown product id !"); 183 | d->close(); 184 | return 3; 185 | } 186 | 187 | /* After opening wait 100ms before querying the device */ 188 | usleep(1000*100); 189 | 190 | if (doReset) { 191 | ups->restartUPS(); 192 | fprintf(stdout, "Restarted UPS\n"); 193 | return 0; 194 | } 195 | 196 | if (goBootloader) { 197 | ups->restartUPSInBootloaderMode(); 198 | fprintf(stdout, "Restarted UPS in Bootloader Mode\n"); 199 | return 0; 200 | } 201 | 202 | 203 | ups->GetStatus(); 204 | ups->printValues(); 205 | 206 | if (execCmd) { 207 | if (ups->executeCommand(execCmd)) { 208 | fprintf(stdout, "Command executed.\n"); 209 | ups->GetStatus(); 210 | ups->printValues(); 211 | } 212 | } 213 | 214 | if (withConfiguration) { 215 | fprintf(stdout, "Read configuration\n"); 216 | ups->ReadConfigurationMemory(); 217 | ups->printConfiguration(withComments); 218 | if (outfile) { 219 | ups->varsToFile(outfile, withComments); 220 | fprintf(stdout, "Saved configuration to file: %s\n", outfile); 221 | } 222 | } 223 | 224 | if (infile) { 225 | ups->EraseConfigurationMemory(); 226 | fprintf(stdout, "Erased configuration\n"); 227 | 228 | ups->fileToVars(infile); 229 | fprintf(stdout, "Loaded configuration file: %s\n", infile); 230 | 231 | ups->WriteConfigurationMemory(); 232 | fprintf(stdout, "Wrote configuration\n"); 233 | 234 | //ups->varsToFile("settings.cfg.after", false); 235 | ups->restartUPS(); 236 | fprintf(stdout, "Restarted UPS\n"); 237 | } 238 | 239 | d->close(); 240 | return 0; 241 | } 242 | -------------------------------------------------------------------------------- /src/utils/HArray.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #ifndef _WIN32 3 | #include 4 | #endif 5 | #include "HArray.h" 6 | 7 | 8 | HArray::HArray() 9 | { 10 | m_pArray = NULL;m_nLen = 0; 11 | } 12 | 13 | HArray::HArray(char* array) 14 | { 15 | m_pArray = NULL;m_nLen = 0; 16 | setValue(array); 17 | } 18 | 19 | HArray::HArray(unsigned char* array, int len) 20 | { 21 | m_pArray = NULL;m_nLen = 0; 22 | setValue(array, len); 23 | } 24 | 25 | HArray::HArray(HArray* array) 26 | { 27 | m_pArray = NULL;m_nLen = 0; 28 | setValue(array->getBuf(), array->length()); 29 | } 30 | 31 | /*HArray::HArray(unsigned short* array) 32 | { 33 | m_pArray = NULL;m_nLen = 0; 34 | setValue(array); 35 | }*/ 36 | 37 | HArray::HArray(int len) 38 | { 39 | m_nLen = len; 40 | m_pArray = new unsigned char[len]; 41 | memset(m_pArray, 0, len); 42 | } 43 | 44 | HArray::~HArray() 45 | { 46 | if (m_pArray) delete m_pArray; 47 | } 48 | 49 | void HArray::erase() 50 | { 51 | if (m_pArray) delete m_pArray; 52 | m_pArray = NULL;m_nLen = 0; 53 | } 54 | 55 | bool HArray::equals(HArray* array) 56 | { 57 | if (this->m_nLen != array->length()) return false; 58 | 59 | for (unsigned int i = 0;im_nLen;i++) 60 | if (this->m_pArray[i] != array->getBuf()[i]) return false; 61 | 62 | return true; 63 | } 64 | 65 | bool HArray::equals(HArray* array, unsigned int to) 66 | { 67 | if (this->m_nLen < to) return false; 68 | if (array->length() < to) return false; 69 | 70 | for (unsigned int i = 0;im_pArray[i] != array->getBuf()[i]) return false; 72 | 73 | return true; 74 | } 75 | 76 | bool HArray::equalsSpecial(HArray* array, unsigned int to) 77 | { 78 | if (this->m_nLen < to) return false; 79 | if (array->length() < to) return false; 80 | 81 | for (unsigned int i = 1;im_pArray[i] != array->getBuf()[i]) return false; 83 | 84 | return true; 85 | } 86 | 87 | void HArray::setValue(HArray* array) 88 | { 89 | setValue(array->getBuf(), array->length()); 90 | } 91 | 92 | void HArray::setValue(char* array) 93 | { 94 | if (m_pArray) delete m_pArray; 95 | 96 | m_nLen = strlen(array)+1; 97 | m_pArray = new unsigned char[m_nLen]; 98 | strcpy((char*)m_pArray, array); 99 | } 100 | 101 | /*void HArray::setValue(unsigned short* array) 102 | { 103 | if (m_pArray) delete m_pArray; 104 | 105 | m_nLen = 2*wcslen(array)+2; 106 | m_pArray = new unsigned char[m_nLen]; 107 | wcscpy((unsigned short*)m_pArray, array); 108 | }*/ 109 | 110 | void HArray::setValue(unsigned char* array, int len) 111 | { 112 | if (m_pArray) delete m_pArray; 113 | 114 | m_nLen = len; 115 | if (len>0) 116 | { 117 | m_pArray = new unsigned char[len]; 118 | memcpy(m_pArray, array, len); 119 | } 120 | else m_pArray = NULL; 121 | } 122 | 123 | void HArray::setHIDPkt(unsigned char rid, unsigned int rlen, unsigned int len, ...) 124 | { 125 | if (m_pArray) delete m_pArray; 126 | m_nLen = rlen + 1; 127 | m_pArray = new unsigned char[rlen+1]; 128 | m_pArray[0] = rid; 129 | va_list args; 130 | va_start(args, len); 131 | unsigned int cnt = 0; 132 | #ifdef _WIN32 133 | unsigned char i = va_arg(args, unsigned char); 134 | #else 135 | unsigned char i = va_arg(args, unsigned int); 136 | #endif 137 | while (cntpnext; 25 | delete ptemp; 26 | } 27 | 28 | m_ptmp = m_pend = m_phead = NULL; 29 | m_elements = 0; 30 | 31 | m_lock.unlock(); 32 | } 33 | 34 | bool HList::add( void* elem ) 35 | { 36 | ITEM* ptemp = new ITEM(); 37 | 38 | ptemp->pdata = elem; 39 | ptemp->pnext = NULL; 40 | 41 | if( !m_lock.lock() ) 42 | { 43 | delete ptemp; 44 | return false; 45 | } 46 | if( m_phead == NULL ) 47 | { 48 | m_pend = m_phead = ptemp; 49 | } 50 | else 51 | { 52 | m_pend->pnext = ptemp; 53 | m_pend = ptemp; 54 | } 55 | m_elements++; 56 | m_lock.unlock(); 57 | return true; 58 | } 59 | 60 | bool HList::remove( void* elem ) 61 | { 62 | if( !m_lock.lock() ) 63 | { 64 | return false; 65 | } 66 | bool b = removeWithNoLocking( elem ); 67 | m_lock.unlock(); 68 | return b; 69 | } 70 | 71 | bool HList::removeWithNoLocking( void* elem ) 72 | { 73 | bool bFound = true; 74 | ITEM* ptemp = m_phead; 75 | ITEM* ptmp = NULL; 76 | while( ptemp!=NULL ) 77 | { 78 | if( ptemp->pdata == elem ) 79 | { 80 | break; 81 | } 82 | ptmp = ptemp; 83 | ptemp = ptemp->pnext; 84 | } 85 | if( ptemp == NULL ) //No element was found found 86 | { 87 | bFound = false; 88 | } 89 | else if( m_pend == m_phead ) //List containing just the founded element 90 | { 91 | m_pend = m_phead = NULL; 92 | } 93 | else if( ptemp == m_phead ) //Founded element is the first element 94 | { 95 | m_phead = ptemp->pnext; 96 | } 97 | else if( ptemp == m_pend ) //Founded element is the last element 98 | { 99 | ptmp->pnext = NULL; 100 | m_pend = ptmp; 101 | } 102 | else //Founded element is in the middle of the list 103 | { 104 | ptmp->pnext = ptemp->pnext; 105 | } 106 | if( bFound ) 107 | { 108 | delete ptemp; 109 | m_elements--; 110 | } 111 | return bFound; 112 | } 113 | 114 | void HList::removeElement( ITEM* t, ITEM* t1 ) 115 | { 116 | //head of the list 117 | if (t1==NULL) return; 118 | 119 | m_elements--; 120 | 121 | if( t == NULL ) 122 | { 123 | m_phead = t1->pnext; 124 | //only one element in list 125 | if ((m_phead!=NULL)&&( m_phead->pnext == NULL )) 126 | m_pend = m_phead; 127 | delete t1; 128 | return; 129 | } 130 | 131 | t->pnext = t1->pnext; 132 | 133 | //end of the list 134 | if( t->pnext == NULL ) 135 | { 136 | m_pend = t; 137 | } 138 | delete t1; 139 | } 140 | 141 | bool HList::exist( void* data ) 142 | { 143 | if( !m_lock.lock() ) 144 | { 145 | return false; 146 | } 147 | bool bFound = false; 148 | ITEM* ptemp = m_phead; 149 | while( ptemp != NULL ) 150 | { 151 | if( data == ptemp->pdata ) 152 | { 153 | bFound = true; 154 | break; 155 | } 156 | ptemp = ptemp->pnext; 157 | } 158 | m_lock.unlock(); 159 | return bFound; 160 | } 161 | 162 | bool HList::lock( void ) 163 | { 164 | return m_lock.lock(); 165 | } 166 | 167 | void HList::unlock( void ) 168 | { 169 | m_lock.unlock(); 170 | } 171 | 172 | ITEM* HList::getHead( void ) 173 | { 174 | return m_phead; 175 | } 176 | 177 | void HList::moveToHead( void ) 178 | { 179 | m_ptmp = m_phead; 180 | } 181 | 182 | void* HList::nextElement( void ) 183 | { 184 | void* pdata = NULL; 185 | if( m_ptmp != NULL ) 186 | { 187 | pdata = m_ptmp->pdata; 188 | m_ptmp = m_ptmp->pnext; 189 | } 190 | return pdata; 191 | } 192 | 193 | void* HList::getData( void ) 194 | { 195 | void* pdata = NULL; 196 | if( m_ptmp != NULL ) 197 | { 198 | pdata = m_ptmp->pdata; 199 | m_ptmp = m_ptmp->pnext; 200 | } 201 | return pdata; 202 | } 203 | 204 | void* HList::nextElement( ITEM** t) 205 | { 206 | if (*t == getHead()) moveToHead(); 207 | 208 | void* data = nextElement(); 209 | 210 | *t = m_ptmp; 211 | 212 | return data; 213 | } 214 | -------------------------------------------------------------------------------- /src/utils/HList.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __H_LIST_H__ 3 | #define __H_LIST_H__ 4 | 5 | #include "HLock.h" 6 | 7 | #ifdef HIDAPI_EXPORTS 8 | struct HIDAPI_API Item 9 | #else 10 | struct Item 11 | #endif 12 | { 13 | void* pdata; 14 | struct Item* pnext; 15 | }; 16 | 17 | typedef struct Item ITEM; 18 | 19 | #ifdef HIDAPI_EXPORTS 20 | class HIDAPI_API HList 21 | #else 22 | class HList 23 | #endif 24 | { 25 | public: 26 | HList(); 27 | virtual ~HList(); 28 | inline int& elements( void ){return m_elements;} 29 | bool add( void* elem ); 30 | bool remove( void* elem ); 31 | bool removeWithNoLocking( void* elem ); 32 | bool lock( void ); 33 | void unlock( void ); 34 | void moveToHead( void ); 35 | ITEM* getHead( void ); 36 | bool exist( void* data ); 37 | void* nextElement( void ); 38 | void* nextElement( ITEM** t); 39 | void removeElement( ITEM* parent, ITEM* t ); 40 | void* getData( void ); 41 | 42 | void removeall(); 43 | 44 | private: 45 | 46 | ITEM* m_phead; 47 | ITEM* m_pend; 48 | ITEM* m_ptmp; 49 | HLock m_lock; 50 | int m_elements; 51 | }; 52 | #endif //__H_LIST_H__ 53 | -------------------------------------------------------------------------------- /src/utils/HLock.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "HLock.h" 3 | 4 | HLock::HLock() 5 | { 6 | #ifdef _WIN32 7 | InitializeCriticalSection( &m_mutex ); 8 | #else 9 | m_bUnderDestroy = false; 10 | pthread_mutexattr_t mutexAttr; 11 | pthread_mutexattr_init( &mutexAttr ); 12 | pthread_mutexattr_settype( &mutexAttr, PTHREAD_MUTEX_ERRORCHECK_NP ); 13 | pthread_mutex_init( &m_mutex, &mutexAttr ); 14 | pthread_mutexattr_destroy( &mutexAttr ); 15 | #endif 16 | } 17 | 18 | HLock::~HLock() 19 | { 20 | destroy(); 21 | } 22 | 23 | bool HLock::lock( void ) 24 | { 25 | #ifdef _WIN32 26 | __try 27 | { 28 | EnterCriticalSection( &m_mutex ); 29 | } 30 | __except( 1 ) 31 | { 32 | return false; 33 | } 34 | #else 35 | pthread_mutex_lock( &m_mutex ); 36 | if (m_bUnderDestroy) 37 | { 38 | pthread_mutex_unlock( &m_mutex ); 39 | return false; 40 | } 41 | #endif 42 | return true; 43 | } 44 | 45 | void HLock::unlock( void ) 46 | { 47 | #ifdef _WIN32 48 | __try 49 | { 50 | LeaveCriticalSection( &m_mutex ); 51 | } 52 | __except( 1 ) 53 | { 54 | } 55 | #else 56 | if( !m_bUnderDestroy ) 57 | { 58 | pthread_mutex_unlock( &m_mutex ); 59 | } 60 | #endif 61 | } 62 | 63 | void HLock::destroy( void ) 64 | { 65 | #ifdef _WIN32 66 | __try 67 | { 68 | DeleteCriticalSection( &m_mutex ); 69 | } 70 | __except( 1 ) 71 | { 72 | } 73 | #else 74 | m_bUnderDestroy = true; 75 | pthread_mutex_unlock( &m_mutex ); 76 | #endif 77 | } 78 | -------------------------------------------------------------------------------- /src/utils/HLock.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __H_LOCK_H__ 3 | #define __H_LOCK_H__ 4 | 5 | #ifndef _WIN32 6 | 7 | #include 8 | typedef pthread_mutex_t CRITICAL_SECTION; 9 | #endif 10 | 11 | #ifdef HIDAPI_EXPORTS 12 | class HIDAPI_API HLock 13 | #else 14 | class HLock 15 | #endif 16 | { 17 | public: 18 | HLock(); 19 | virtual ~HLock(); 20 | bool lock( void ); 21 | void unlock( void ); 22 | void destroy( void ); 23 | 24 | private: 25 | CRITICAL_SECTION m_mutex; 26 | #ifndef _WIN32 27 | bool m_bUnderDestroy; 28 | #endif 29 | }; 30 | 31 | #endif //__H_LOCK_H__ 32 | -------------------------------------------------------------------------------- /src/utils/HThread.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | #include "HThread.h" 4 | #include 5 | 6 | #ifndef _WIN32 7 | #define INVALID_HANDLE_VALUE 0 8 | #endif 9 | 10 | const unsigned int HThread::INFINIT_WAIT = UINT_MAX; 11 | 12 | #ifdef _WIN32 13 | DWORD WINAPI runStub( LPVOID mthread ) 14 | #else 15 | void* runStub( void* mthread) 16 | #endif 17 | { 18 | HThread* pThread = static_cast(mthread); 19 | pThread->m_bIsRunning = true; 20 | pThread->m_bExited = false; 21 | pThread->run(); 22 | pThread->m_bIsRunning = false; 23 | pThread->m_bExited = true; 24 | #ifdef _WIN32 25 | return 0; 26 | #else 27 | return NULL; 28 | #endif 29 | } 30 | 31 | HThread::HThread( ) 32 | { 33 | m_bIsRunning = false; 34 | m_bExited = true; 35 | m_thread = INVALID_HANDLE_VALUE; 36 | } 37 | 38 | HThread::~HThread() 39 | { 40 | stop(); 41 | } 42 | 43 | bool HThread::start( void ) 44 | { 45 | if( m_bExited ) 46 | { 47 | m_bIsRunning = true; 48 | m_bExited = false; 49 | 50 | #ifdef _WIN32 51 | DWORD dw; 52 | if( (m_thread = CreateThread( NULL, 4096, runStub, this, 0, &dw )) == INVALID_HANDLE_VALUE ) 53 | { 54 | m_bIsRunning = false; 55 | m_bExited = true; 56 | return false; 57 | } 58 | #else 59 | pthread_attr_t attr; 60 | pthread_attr_init( &attr ); 61 | pthread_attr_setdetachstate( &attr, PTHREAD_CREATE_DETACHED ); 62 | pthread_attr_setschedpolicy( &attr, SCHED_OTHER ); 63 | pthread_attr_setscope( &attr, PTHREAD_SCOPE_SYSTEM ); 64 | if( pthread_create( &m_thread, &attr, runStub, this ) != 0 ) 65 | { 66 | m_thread = INVALID_HANDLE_VALUE; 67 | m_bIsRunning = false; 68 | m_bExited = true; 69 | return false; 70 | } 71 | #endif 72 | } 73 | return true; 74 | } 75 | 76 | bool HThread::stop( unsigned int timeout ) 77 | { 78 | m_bIsRunning = false; 79 | if( !m_bExited ) 80 | { 81 | for( unsigned int i = 0; (i <= timeout/10) || (timeout == INFINIT_WAIT); i++) 82 | { 83 | if( m_bExited ) 84 | { 85 | break; 86 | } 87 | Sleep( 10 ); 88 | } 89 | } 90 | #ifdef _WIN32 91 | if( m_thread != INVALID_HANDLE_VALUE ) 92 | { 93 | CloseHandle( m_thread ); 94 | m_thread = INVALID_HANDLE_VALUE; 95 | } 96 | #else 97 | m_thread = INVALID_HANDLE_VALUE; 98 | #endif 99 | return m_bExited; 100 | } 101 | 102 | void HThread::run( void ) 103 | { 104 | } 105 | 106 | -------------------------------------------------------------------------------- /src/utils/HThread.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __H_THREAD_H__ 3 | #define __H_THREAD_H__ 4 | 5 | 6 | #ifndef _WIN32 7 | #include 8 | typedef pthread_t HANDLE; 9 | #define Sleep(x) 10 | #endif 11 | 12 | #ifdef HIDAPI_EXPORTS 13 | class HIDAPI_API HThread 14 | #else 15 | class HThread 16 | #endif 17 | { 18 | public: 19 | HThread( ); 20 | virtual ~HThread(); 21 | virtual bool start( void ); 22 | virtual bool stop( unsigned int timeout = 5000 ); 23 | inline bool& isRunning( void ) 24 | { 25 | return m_bIsRunning; 26 | } 27 | 28 | protected: 29 | virtual void run( void ); 30 | 31 | private: 32 | #ifdef _WIN32 33 | friend DWORD WINAPI runStub( LPVOID mthread ); 34 | #else 35 | friend void* runStub( void* mthread ); 36 | #endif 37 | 38 | public: 39 | static const unsigned int INFINIT_WAIT; 40 | 41 | private: 42 | bool m_bIsRunning, m_bExited; 43 | HANDLE m_thread; 44 | }; 45 | 46 | #endif //__H_THREAD_H__ 47 | -------------------------------------------------------------------------------- /src/utils/TxFile.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | #include "TxFile.h" 3 | 4 | TxFile::TxFile(const char* file) 5 | { 6 | m_File = NULL; 7 | m_strFile = new char[strlen(file)+1]; 8 | strcpy(m_strFile, file); 9 | } 10 | 11 | TxFile::~TxFile(void) 12 | { 13 | delete m_strFile; 14 | Close(); 15 | } 16 | 17 | int TxFile::Open() 18 | { 19 | if (m_File) 20 | { 21 | fclose(m_File); 22 | m_File = NULL; 23 | } 24 | 25 | m_File = fopen(m_strFile, "rt"); 26 | if (m_File) 27 | { 28 | printf("File %s opened\r\n",m_strFile); 29 | return 0; 30 | } 31 | else 32 | { 33 | printf("File %s could not be opened\r\n",m_strFile); 34 | return 1; 35 | } 36 | } 37 | 38 | void TxFile::Close() 39 | { 40 | if (m_File) 41 | { 42 | fclose(m_File); 43 | m_File = NULL; 44 | } 45 | } 46 | 47 | void TxFile::Reset() 48 | { 49 | if (m_File) 50 | rewind(m_File); 51 | } 52 | 53 | int TxFile::NextTextLine(char* buffer) 54 | { 55 | buffer[0]=0; 56 | if (!m_File) return -1; 57 | 58 | char* res = fgets(m_fileBuff, MAX_LINE_LEN - 1, m_File); 59 | m_fileBuff[MAX_LINE_LEN-1] = 0; 60 | 61 | if (res == NULL) return -1;//eof 62 | 63 | int len = strlen(m_fileBuff); 64 | if (m_fileBuff[len - 1] == 10) m_fileBuff[len - 1] = 0; 65 | len = strlen(m_fileBuff); 66 | if (m_fileBuff[len - 1] == 13) m_fileBuff[len - 1] = 0; 67 | len = strlen(m_fileBuff); 68 | 69 | if (len>0) 70 | { 71 | if (m_fileBuff[0] == '#') 72 | { 73 | return 3; 74 | } 75 | 76 | memcpy(buffer,m_fileBuff,len); 77 | buffer[len]=0; 78 | 79 | return 1; 80 | } 81 | //else thearray->setValue(NULL, 0); 82 | 83 | return 2; 84 | } 85 | 86 | void TxFile::NextArray(HArray* thearray) 87 | { 88 | thearray->erase(); 89 | 90 | int ret = NextLine(thearray); 91 | while ((ret != -1) && (ret != 1)) 92 | ret = NextLine(thearray); 93 | } 94 | 95 | int TxFile::NextLine(HArray* thearray) 96 | { 97 | m_chSpecChar = 0; 98 | m_nSpecValue = 0; 99 | if (!m_File) return -1; 100 | 101 | char* res = fgets(m_fileBuff, MAX_LINE_LEN - 1, m_File); 102 | m_fileBuff[MAX_LINE_LEN-1] = 0; 103 | 104 | if (res == NULL) return -1;//eof 105 | 106 | int len = strlen(m_fileBuff); 107 | if (m_fileBuff[len - 1] == 10) m_fileBuff[len - 1] = 0; 108 | len = strlen(m_fileBuff); 109 | 110 | if (len>0) 111 | { 112 | if (m_fileBuff[0] == '#') 113 | { 114 | //thearray->setValue(NULL, 0); 115 | return 3; 116 | } 117 | else if (m_fileBuff[0] == '$') 118 | { 119 | //thearray->setValue(NULL, 0); 120 | if (len > 1) 121 | m_chSpecChar = m_fileBuff[1]; 122 | if (len > 2) 123 | m_nSpecValue = atoi(m_fileBuff + 2); 124 | return 4; 125 | } 126 | 127 | int pos = 0; 128 | 129 | unsigned char pkg[256]; 130 | int pkg_len =0; 131 | while (possetValue(pkg, pkg_len); 137 | return 1; 138 | } 139 | //else thearray->setValue(NULL, 0); 140 | 141 | return 2; 142 | } 143 | 144 | unsigned char TxFile::getmchar(int pos) 145 | { 146 | char str[3]; 147 | strncpy(str, m_fileBuff+pos, 2); 148 | str[2] = 0; 149 | 150 | return (unsigned char)strtoul(str, NULL, 16); 151 | } -------------------------------------------------------------------------------- /src/utils/TxFile.h: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2009 mini-box.com 3 | * 4 | * Licensed under the terms of the GNU Lesser General Public License v2.1: 5 | * http://www.opensource.org/licenses/lgpl-2.1.php 6 | * 7 | * 8 | * File Authors: 9 | * Barna Csenteri 10 | */ 11 | 12 | #pragma once 13 | 14 | #include "HArray.h" 15 | #define MAX_LINE_LEN 256*2+256 16 | 17 | class TxFile 18 | { 19 | public: 20 | TxFile(const char* file); 21 | virtual ~TxFile(void); 22 | 23 | /** Open the file (if already opened the old one is closed and repoened again)*/ 24 | int Open(); 25 | /** Close the file */ 26 | void Close(); 27 | /** Jumping to the start of the file*/ 28 | void Reset(); 29 | 30 | const char getSpecChar(){return m_chSpecChar;}; 31 | const int getSpecVal(){return m_nSpecValue;}; 32 | const char* getFileBuf(){return m_fileBuff;}; 33 | 34 | /** Reads only hex arrays, ignores the rest*/ 35 | void NextArray(HArray* thearray); 36 | 37 | /** Get one more line from the file 38 | * return: 0 = ok, 1 = eof, 2,3,4... - invalid hex file 39 | */ 40 | int NextLine(HArray* thearray); 41 | 42 | /** Get one more line from the file 43 | * return: 0 = ok, 1 = eof, 2,3,4... - invalid hex file 44 | */ 45 | int NextTextLine(char* buffer); 46 | protected: 47 | unsigned char getmchar(int pos); 48 | 49 | char* m_strFile; 50 | FILE* m_File; 51 | 52 | unsigned char m_byteBuff[256]; 53 | char m_fileBuff[MAX_LINE_LEN]; 54 | 55 | char m_chSpecChar; 56 | int m_nSpecValue; 57 | }; 58 | -------------------------------------------------------------------------------- /src/utils/util.cpp: -------------------------------------------------------------------------------- 1 | #include "util.h" 2 | 3 | unsigned char hex2bcd (unsigned char x) 4 | { 5 | unsigned char y; 6 | y = (x / 10) << 4; 7 | y = y | (x % 10); 8 | return (y); 9 | } 10 | 11 | unsigned char bcd2hex (unsigned char x) 12 | { 13 | unsigned char y; 14 | y = (x >> 4)*10; 15 | y = y + (x & 0x0F); 16 | return (y); 17 | } 18 | 19 | void char2bin(char* destination, unsigned char ch) 20 | { 21 | int cnt = 0; 22 | 23 | for (int i=7;i>=0;i--) 24 | if ((ch>>i)&1) 25 | { 26 | destination[cnt] = '1'; 27 | cnt++; 28 | } 29 | else 30 | { 31 | destination[cnt] = '0'; 32 | cnt++; 33 | } 34 | 35 | destination[cnt] = 0; 36 | } 37 | 38 | unsigned char bin2char(char* str, bool* ok) 39 | { 40 | int len = strlen(str); 41 | 42 | *ok = false; 43 | if (len == 0) 44 | return 0; 45 | 46 | unsigned char value = 0; 47 | 48 | for (int i=0;i 8 | #include 9 | #include 10 | #else 11 | #define TCHAR char 12 | #define _TCHAR char 13 | #define _T(s) s 14 | #define _tcstol strtol 15 | #define _strcmpi strcmp 16 | #define _tcstod strtod 17 | #endif 18 | 19 | #include 20 | #include 21 | #include 22 | 23 | 24 | #define _CRTDBG_MAP_ALLOC 25 | 26 | 27 | unsigned char hex2bcd (unsigned char x); 28 | unsigned char bcd2hex (unsigned char x); 29 | void char2bin(char* destination, unsigned char ch); 30 | unsigned char bin2char(char* str, bool* ok); 31 | 32 | void str_mid(char* dest, char* source, int from, int cnt); 33 | void str_left(char* dest, char* source, int cnt); 34 | void str_right(char* dest, char* source, int cnt); 35 | 36 | #ifdef _DEBUG 37 | #include 38 | void DBGOutput(const char* szFormat, ...); 39 | #else 40 | #define DBGOutput 41 | #endif 42 | 43 | #define TRACE DBGOutput 44 | 45 | #endif //_UTIL_H_ -------------------------------------------------------------------------------- /src/version.h: -------------------------------------------------------------------------------- 1 | #define VERSION "1.0" --------------------------------------------------------------------------------