From: Jan Michel Date: Thu, 29 Dec 2022 17:37:47 +0000 (+0100) Subject: add code for RemotePowerSwitch X-Git-Url: https://jspc29.x-matter.uni-frankfurt.de/git/?a=commitdiff_plain;h=42885118118da2ed269b85e80a119a29f9926d5b;p=avr.git add code for RemotePowerSwitch --- diff --git a/esp32/EthernetUART/RemotePowerSwitch/README.txt b/esp32/EthernetUART/RemotePowerSwitch/README.txt new file mode 100644 index 0000000..886cf48 --- /dev/null +++ b/esp32/EthernetUART/RemotePowerSwitch/README.txt @@ -0,0 +1,30 @@ + **Data format:** *XuuGcRvvvv* + X - command (write: W, read: R, answer: A) + uu - controller (Hex value) + G - group + c - channel + R - register (Hex value) + vvvv - 16 Bit value + + close with a "\n" + e.g. "RF2012FE51\n" + +Board has controller number 0xFF +Group is always 0 +Up to 4 channels can be connected to same interface + + +| Registers | description | +|-----------|--------------------------------------------------------------| +| 0 | Channel ON/OFF | +| 1 | Voltage V_out (RO) | +| 2 | Voltage V_in (RO) | +| 3 | Current C_in (RO) | +| 4 | Save Settings (WO) | 0: read, 1: write +| 5 | [15:4] Firmware, [3..0] number of channels | +| 6 | Current Offset | in ADC LSB (0.125 mV) +| 7 | Current Gain | in mV/A +| 8 | Voltage Divider | in mV/V (ratio times 1000) +| 9 | Overcurrent Limit | in mA +| A | Overvoltage Limit | in mV +| B | Undervoltage Limit | in mV diff --git a/esp32/EthernetUART/RemotePowerSwitch/RemotePowerSwitch.ino b/esp32/EthernetUART/RemotePowerSwitch/RemotePowerSwitch.ino new file mode 100644 index 0000000..23318f9 --- /dev/null +++ b/esp32/EthernetUART/RemotePowerSwitch/RemotePowerSwitch.ino @@ -0,0 +1,611 @@ + /* + +Telnet Port 2323 + +Visual Status via Board LEDs: +ETH Start -> Green LED blink once +Telnet work -> Green LED on +ETH Disconnected/stopped -> Orange LED on +*/ + +void getdata(uint8_t buf); + +// load needed Libaries +#include //for external ADC +#include //for Telnet Server Connection +#include //for I2C Connection +#include //for OLED display driver +#include //for display control +#include //to save settings + + +#define SCREEN_ADDRESS 0x3C //< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32 +Adafruit_SSD1306 display(128, 32, &Wire, -1); + +#define imageWidth 106 +#define imageHeight 32 +const unsigned char logo_bmp[] PROGMEM = { + 0xfc, 0x0f, 0xc0, 0x03, 0xf8, 0x3f, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, + 0xff, 0x80, 0xfc, 0x0f, 0xc0, 0x07, 0xf8, 0x3f, 0xff, 0xfc, 0x0f, 0xff, + 0xff, 0xff, 0xff, 0x00, 0xfc, 0x0f, 0xc0, 0x0f, 0xf0, 0x3f, 0xff, 0xfc, + 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x40, 0xfc, 0x0f, 0xc0, 0x1f, 0xe0, 0x3f, + 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0xc0, 0xfc, 0x0f, 0xc0, 0x3f, + 0xc0, 0x3f, 0xff, 0xfc, 0x0f, 0xff, 0xff, 0xff, 0xf1, 0xc0, 0xfc, 0x0f, + 0xc0, 0x3f, 0x80, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xe7, 0xc0, + 0xfc, 0x0f, 0xc0, 0x7f, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0x8f, 0xc0, 0xfc, 0x0f, 0xc0, 0xfe, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, + 0xff, 0xff, 0x3f, 0xc0, 0xfc, 0x0f, 0xc1, 0xfc, 0x00, 0x3f, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xfc, 0xff, 0xc0, 0xfc, 0x0f, 0xc3, 0xf8, 0x00, 0x3f, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf1, 0xff, 0xc0, 0xfc, 0x0f, 0xc7, 0xf8, + 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0x8f, 0xff, 0xc0, 0xfc, 0x0f, + 0xcf, 0xf0, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xfc, 0x3f, 0xff, 0xc0, + 0xfc, 0x0f, 0xcf, 0xe0, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xe0, 0xff, + 0xff, 0xc0, 0xfc, 0x0f, 0xdf, 0xe0, 0x00, 0x3f, 0xff, 0xf0, 0x0f, 0xfe, + 0x0f, 0xff, 0xff, 0xc0, 0xfc, 0x0f, 0xff, 0xf0, 0x00, 0x3f, 0xff, 0xf0, + 0x0f, 0x80, 0xff, 0xff, 0xff, 0xc0, 0xfc, 0x0f, 0xff, 0xf8, 0x00, 0x3f, + 0xff, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x0f, 0xff, 0xf8, + 0x00, 0x3f, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xff, 0xff, 0xc0, 0xfc, 0x0f, + 0xfd, 0xfc, 0x00, 0x3f, 0xff, 0xf0, 0x0f, 0xf8, 0x1f, 0xff, 0xff, 0xc0, + 0xfc, 0x0f, 0xf8, 0xfc, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xc1, 0xff, + 0xff, 0xc0, 0xfc, 0x0f, 0xf0, 0xfe, 0x00, 0x3f, 0x00, 0x00, 0x0f, 0xff, + 0xf8, 0x7f, 0xff, 0xc0, 0xfc, 0x0f, 0xe0, 0x7f, 0x00, 0x3f, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0x0f, 0xff, 0xc0, 0xfc, 0x0f, 0xe0, 0x7f, 0x00, 0x3f, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xe3, 0xff, 0xc0, 0xfc, 0x0f, 0xc0, 0x3f, + 0x80, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xf8, 0xff, 0xc0, 0xfc, 0x0f, + 0xc0, 0x3f, 0x80, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xfe, 0x3f, 0xc0, + 0xfc, 0x0f, 0xc0, 0x1f, 0xc0, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0x9f, 0xc0, 0xfc, 0x0f, 0xc0, 0x0f, 0xe0, 0x3f, 0x00, 0x00, 0x0f, 0xff, + 0xff, 0xff, 0xc7, 0xc0, 0xfc, 0x0f, 0xc0, 0x0f, 0xe0, 0x3f, 0x00, 0x00, + 0x0f, 0xff, 0xff, 0xff, 0xf3, 0xc0, 0xfc, 0x0f, 0xc0, 0x07, 0xf0, 0x3f, + 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xf9, 0xc0, 0xfc, 0x0f, 0xc0, 0x07, + 0xf0, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfc, 0xc0, 0xfc, 0x0f, + 0xc0, 0x03, 0xf8, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xfe, 0x40, + 0xfc, 0x0f, 0xc0, 0x03, 0xfc, 0x3f, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, + 0xff, 0x00, 0xfc, 0x0f, 0xc0, 0x01, 0xfc, 0x3f, 0x00, 0x00, 0x0f, 0xff, + 0xff, 0xff, 0xff, 0x80}; + + + +#define MAX_SRV_CLIENTS 10 +#define FIRMWARE_VERSION 1 +#define EEPROM_SIZE 0x50 + +#define SDA 5 +#define SCL 32 +#define LED_GREEN 15 +#define LED_YELLOW 2 +#define N0 3 +#define N1 1 +#define N2 33 +#define N3 14 + +Adafruit_ADS1X15 ads[4]; +WiFiServer server(2323); +WiFiClient serverClients[MAX_SRV_CLIENTS]; + +volatile static bool eth_connected = false; +uint8_t rxcnt = 0, txpoint = 0; +uint8_t rxbuf[15]; +uint8_t txbuf[12]; +uint8_t firstrun = 0; +int16_t adc[4][3]; +uint16_t dadc[4][3]; +uint16_t lastdadc[4][3]; +unsigned long lastADCRead = 0; + +int16_t CONF_currentoffset[4] = {0,0,0,0}; // in ADC LSB (0.125 mV) +float CONF_currentgain[4] = {0.8,0.8,0.8,0.8}; // in V/A +float CONF_voltagedivider[4] = {3,3,3,3}; // in V/V +uint8_t CONF_activegroups = 1; // number of active groups +uint8_t CONF_channelon[4] = {0,0,0,0}; // Channel active +uint16_t CONF_overcurrent[4] = {0,0,0,0}; // in mA +uint16_t CONF_overvoltage[4] = {0,0,0,0}; // in mV +uint16_t CONF_undervoltage[4] = {0,0,0,0}; // in mV + + +/***************************************************************** + * Ethernet + *****************************************************************/ +void WiFiEvent(WiFiEvent_t event) { + display_connection_screen(); + switch (event){ + case ARDUINO_EVENT_ETH_START: + //set eth hostname here + digitalWrite(LED_YELLOW,LOW); + digitalWrite(LED_GREEN,HIGH); + delay(500); + digitalWrite(LED_GREEN, LOW); + ETH.setHostname("esp32-ethernet"); + break; + + case ARDUINO_EVENT_ETH_CONNECTED: + digitalWrite(LED_YELLOW,LOW); + digitalWrite(LED_GREEN,HIGH); + break; + + case ARDUINO_EVENT_ETH_GOT_IP: + eth_connected = true; + break; + + case ARDUINO_EVENT_ETH_DISCONNECTED: + digitalWrite(LED_GREEN,LOW); + digitalWrite(LED_YELLOW,HIGH); + eth_connected = false; + break; + + case ARDUINO_EVENT_ETH_STOP: + digitalWrite(LED_GREEN,LOW); + digitalWrite(LED_YELLOW,HIGH); + eth_connected = false; + break; + + default: + break; + } +} + +/***************************************************************** + * Display Screens + *****************************************************************/ + +void display_start_screen() { + display.clearDisplay(); + display.ssd1306_command(SSD1306_SETCONTRAST); + display.ssd1306_command(0); // val=0 := 0% up to val = 255 := 100% + display.setTextSize(1); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.cp437(true); // Use full 256 char 'Code Page 437' font + + display.drawBitmap(0, 0, logo_bmp, imageWidth, imageHeight, SSD1306_WHITE); + display.setCursor(108, 0); + display.write("ETH"); + display.setCursor(108, 8); + display.write("PWR"); + display.setCursor(108, 16); + display.write("SWI"); + display.display(); + } + +void display_connection_screen() { + // show all connection relevant parameters + display.clearDisplay(); + display.setTextSize(1); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.cp437(true); // Use full 256 char 'Code Page 437' font + + display.setCursor(0, 0); + display.write("ETH MAC / IP"); + display.setCursor(25, 8); + display.print(ETH.macAddress()); + display.setCursor(25, 16); + display.print(ETH.localIP()); + + display.display(); +} + +void display_showvalues() { + display.clearDisplay(); + display.setTextSize(1); // Normal 1:1 pixel scale + display.setTextColor(SSD1306_WHITE); // Draw white text + display.cp437(true); // Use full 256 char 'Code Page 437' font + + for (uint8_t i = 0; i < CONF_activegroups; i++) { + display.setCursor(0, i*8); + display.print(dadc[i][0]); + display.print("mA"); + display.setCursor(40, i*8); + display.print(dadc[i][1]); + display.print("mV"); + display.setCursor(80, i*8); + display.print(dadc[i][2]); + display.print("mV"); + } + display.display(); + } + +/***************************************************************** + * Command Handling + *****************************************************************/ + +// convert integer or nibbles into hex value +uint8_t nib_to_hex(uint16_t in, uint8_t nib) { + uint8_t t = (in >> (nib * 4)) & 0xF; + if (t <= 9) { + return t + 0x30; + } + return t - 10 + 0x61; + } + +// convert hex value to integer, assumes valid number +uint8_t hex_to_int(uint8_t h) { + if (h < 0x40) return h - 0x30; + if (h < 0x50) return h - 0x41 + 10; + return h - 0x61 + 10; + } + +//accepts address or forward message +uint8_t is_my_address(uint8_t s) { + if ((rxbuf[1] == 'F' || rxbuf[1] == 'f') && (rxbuf[2] == 'F' || rxbuf[2] == 'f')) { + return 1; + } + else { +// forward_msg(s); + return 0; + } + } + +//Send own reply to Ethernet +void send_answer_buf(uint8_t *d, uint8_t length) { + for(uint8_t i = 0; i < MAX_SRV_CLIENTS; i++) { + if (serverClients[i] && serverClients[i].connected()) { + serverClients[i].write(d, length); + } + } + } + +//compose response string +void send_answer_hex(uint8_t *rxbuf, uint16_t v) { + txbuf[0] = 'A'; + txbuf[1] = rxbuf[1]; + txbuf[2] = rxbuf[2]; + txbuf[3] = rxbuf[3]; + txbuf[4] = rxbuf[4]; + txbuf[5] = rxbuf[5]; + txbuf[6] = nib_to_hex(v, 3); + txbuf[7] = nib_to_hex(v, 2); + txbuf[8] = nib_to_hex(v, 1); + txbuf[9] = nib_to_hex(v, 0); + txbuf[10] = '\n'; + txbuf[11] = 0; + send_answer_buf(txbuf,10); + } + +/***************************************************************** + * Switches + *****************************************************************/ +void set_onoff() { + digitalWrite(N0,1-CONF_channelon[0]); + digitalWrite(N1,1-CONF_channelon[1]); + digitalWrite(N2,1-CONF_channelon[2]); + digitalWrite(N3,1-CONF_channelon[3]); + } + +/***************************************************************** + * ADC functions & Protection + *****************************************************************/ +void get_adc_val() { + for (uint8_t i = 0; i < CONF_activegroups; i++) { + ads[i].setGain(GAIN_ONE); //range 4.096V, 0.125mV/LSB + adc[i][0] = ads[i].readADC_SingleEnded(0); //Current 800 mV/A + adc[i][0] = ads[i].readADC_SingleEnded(0); //Current 800 mV/A + adc[i][1] = ads[i].readADC_SingleEnded(1); //Vout + adc[i][1] = ads[i].readADC_SingleEnded(1); //Vout + adc[i][2] = ads[i].readADC_SingleEnded(2); //Vin + adc[i][2] = ads[i].readADC_SingleEnded(2); //Vin + + lastdadc[i][0] = dadc[i][0]; + lastdadc[i][1] = dadc[i][1]; + lastdadc[i][2] = dadc[i][2]; + dadc[i][0] = (float) (adc[i][0]+CONF_currentoffset[i]) * 0.125 ;// CONF_currentgain[i] ; + dadc[i][1] = (float) adc[i][1] * 0.125 * CONF_voltagedivider[i]; + dadc[i][2] = (float) adc[i][2] * 0.125 * CONF_voltagedivider[i]; + + + if (CONF_overcurrent[i] != 0) { + if (dadc[i][0] > CONF_overcurrent[i] && lastdadc[i][0] > CONF_overcurrent[i]) { + CONF_channelon[i] = 0; + set_onoff(); + } + } + if (CONF_overvoltage[i] != 0) { + if (dadc[i][2] > CONF_overvoltage[i] && lastdadc[i][2] > CONF_overvoltage[i]) { + CONF_channelon[i] = 0; + set_onoff(); + } + } + if (CONF_undervoltage[i] != 0) { + if (dadc[i][2] < CONF_undervoltage[i] && lastdadc[i][2] < CONF_undervoltage[i]) { + CONF_channelon[i] = 0; + set_onoff(); + } + } + } + + display_showvalues(); + } + + + +/***************************************************************** + * EEPROM + *****************************************************************/ +void savesettings() { + EEPROM.write(0x10, CONF_channelon[0]); + EEPROM.write(0x11, CONF_channelon[1]); + EEPROM.write(0x12, CONF_channelon[2]); + EEPROM.write(0x13, CONF_channelon[3]); + EEPROM.write(0x14, CONF_activegroups); + for(uint8_t i = 0; i<4;i++) { + EEPROM.write(0x20+i, CONF_currentoffset[i] & 0xff); + EEPROM.write(0x24+i, CONF_currentoffset[i] >> 8 ); + + uint16_t tmp = CONF_currentgain[i] * 1000; + EEPROM.write(0x30+i, tmp & 0xff); + EEPROM.write(0x34+i, tmp >> 8 ); + + tmp = CONF_voltagedivider[i] * 1000; + EEPROM.write(0x40+i, tmp & 0xff); + EEPROM.write(0x44+i, tmp >> 8 ); + + EEPROM.write(0x28+i, CONF_overcurrent[i] & 0xff); + EEPROM.write(0x2c+i, CONF_overcurrent[i] >> 8 ); + + EEPROM.write(0x38+i, CONF_overvoltage[i] & 0xff); + EEPROM.write(0x3c+i, CONF_overvoltage[i] >> 8 ); + + EEPROM.write(0x48+i, CONF_undervoltage[i] & 0xff); + EEPROM.write(0x4c+i, CONF_undervoltage[i] >> 8 ); + } + EEPROM.commit(); + } + + +void loadsettings() { + CONF_activegroups = EEPROM.read(0x14); + if (CONF_activegroups==0xff || CONF_activegroups==0) CONF_activegroups=1; + + uint16_t tmp; + for(uint8_t i = 0; i<4;i++) { + CONF_channelon[i] = EEPROM.read(0x10+i); + if (CONF_channelon[i]==0xff) CONF_channelon[i]=1; + + tmp = EEPROM.read(0x20+i) | EEPROM.read(0x24+i) << 8; + CONF_currentoffset[i] = tmp; + + tmp = EEPROM.read(0x30+i) | EEPROM.read(0x34+i) << 8; + if (tmp == 0xffff || tmp == 0) tmp = 800; + CONF_currentgain[i] = tmp / 1000.; + + tmp = EEPROM.read(0x40+i) | EEPROM.read(0x44+i) << 8; + if (tmp == 0xffff || tmp == 0) tmp = 1000; + CONF_voltagedivider[i] = tmp / 1000.; + + tmp = EEPROM.read(0x28+i) | EEPROM.read(0x2c+i) << 8; + if (tmp == 0xffff) tmp = 0; + CONF_overcurrent[i] = tmp; + + tmp = EEPROM.read(0x38+i) | EEPROM.read(0x3c+i) << 8; + if (tmp == 0xffff) tmp = 0; + CONF_overvoltage[i] = tmp; + + tmp = EEPROM.read(0x48+i) | EEPROM.read(0x4c+i) << 8; + if (tmp == 0xffff) tmp = 0; + CONF_undervoltage[i] = tmp; + + } + } + + +/***************************************************************** + * Setup + *****************************************************************/ + +void setup() { + pinMode(LED_YELLOW, OUTPUT); + pinMode(LED_GREEN, OUTPUT); + + pinMode(N0, OUTPUT); + pinMode(N1, OUTPUT); + pinMode(N2, OUTPUT); + pinMode(N3, OUTPUT); + + EEPROM.begin(EEPROM_SIZE); + loadsettings(); + set_onoff(); + + //init UART + //Serial.begin(57600); + Wire.begin(SDA,SCL); + display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS, false, false); + display_start_screen(); + + for (uint8_t i = 0; i < 4; i++) { + ads[i].begin(); + } + + + //start the telnet server + WiFi.onEvent(WiFiEvent); + delay(1000); + ETH.begin(1,17,23,18,ETH_PHY_LAN8720,ETH_CLOCK_GPIO0_IN); + server.begin(); + server.setNoDelay(true); + + while (eth_connected == false); + + //visual status for telnet work + digitalWrite(LED_YELLOW,LOW); + digitalWrite(LED_GREEN,HIGH); + } + + + +/***************************************************************** + * Main loop + *****************************************************************/ +void loop() { + uint8_t i; + if (eth_connected == true) { + //check if there are any new clients + if (server.hasClient()) { + for(i = 0; i < MAX_SRV_CLIENTS; i++) { + //find free/disconnected spot + if (!serverClients[i] || !serverClients[i].connected()) { + if(serverClients[i]) serverClients[i].stop(); + serverClients[i] = server.available(); + break; + } + } + if (i >= MAX_SRV_CLIENTS) { + //no free/disconnected spot so reject + server.available().stop(); + } + } + //check clients for data + for(i = 0; i < MAX_SRV_CLIENTS; i++) { + if (serverClients[i] && serverClients[i].connected()) { + if(serverClients[i].available()) { + //get data from the telnet client and push it to the UART + while(serverClients[i].available()) { + int character = serverClients[i].read(); + if( character >= 0 ) + getdata(character); + } + } + } + else { + if (serverClients[i]) { + serverClients[i].stop(); + } + } + } + } + unsigned long time = millis(); + if(time - lastADCRead >= 500) { + lastADCRead = time; + get_adc_val(); + } + } + +/***************************************************************** + * Receive & Interpret commands + *****************************************************************/ + +void getdata(uint8_t buf) { + + if (rxcnt != 0 || (buf == 'W' || buf == 'R')) { + rxbuf[rxcnt++] = buf; + } + if (buf == '\n' || buf == '\r') { // End of Command + if (rxcnt == 11 && is_my_address(11)) { + uint8_t regnumber = hex_to_int(rxbuf[5]); + uint8_t channel = hex_to_int(rxbuf[4]); + if (rxbuf[0] == 'R') { + if (regnumber == 0) { //Register 0: Channel on/off + send_answer_hex(&rxbuf[0], CONF_channelon[channel]); + } + if (regnumber == 1) { //Register 1: Output voltage + send_answer_hex(&rxbuf[0], adc[channel][1]); + } + if (regnumber == 2) { //Register 2: Input voltage + send_answer_hex(&rxbuf[0], adc[channel][2]); + } + if (regnumber == 3) { //Register 3: Current + send_answer_hex(&rxbuf[0], adc[channel][0]); + } + if (regnumber == 5) { //Register 5: Information + send_answer_hex(&rxbuf[0], FIRMWARE_VERSION << 4 | CONF_activegroups); + } + if (regnumber == 6) { //Register 6: Current Offset + send_answer_hex(&rxbuf[0], CONF_currentoffset[channel]); + } + if (regnumber == 7) { //Register 7: Current Gain + send_answer_hex(&rxbuf[0], (uint16_t)(CONF_currentgain[channel]*1000)); + } + if (regnumber == 8) { //Register 8: Voltage Gain + send_answer_hex(&rxbuf[0], (uint16_t)(CONF_voltagedivider[channel]*1000)); + } + if (regnumber == 9) { //Register 9: Current Limit + send_answer_hex(&rxbuf[0], CONF_overcurrent[channel]); + } + if (regnumber == 0xa) { //Register 10: Overvoltage Limit + send_answer_hex(&rxbuf[0], CONF_overvoltage[channel]); + } + if (regnumber == 0xb) { //Register 11: Undervoltage Limit + send_answer_hex(&rxbuf[0], CONF_undervoltage[channel]); + } + } + if (rxbuf[0] == 'W') { + if (regnumber == 0) { //Register 0: Channel on/off + CONF_channelon[channel] = rxbuf[9]=='1'?1:0; + set_onoff(); + send_answer_hex(&rxbuf[0], CONF_channelon[channel]); + } + if (regnumber == 4) { //Register 4: save settings + if(rxbuf[9]=='1') { + savesettings(); + send_answer_hex(&rxbuf[0], 0x5afe); + } + else if(rxbuf[9]=='f') { + for (int i = 0 ; i < EEPROM.length() ; i++) { + EEPROM.write(i, 0); + } + EEPROM.commit(); + send_answer_hex(&rxbuf[0], 0xeeee); + } + else { + loadsettings(); + send_answer_hex(&rxbuf[0], 0x10ad); + } + } + if (regnumber == 5) { //Register 5: Information + uint8_t tmp = hex_to_int(rxbuf[9]); + if(tmp >= 0 && tmp <= 4) CONF_activegroups = tmp; + send_answer_hex(&rxbuf[0], FIRMWARE_VERSION << 4 | CONF_activegroups); + } + if (regnumber == 6) { //Register 6: Current Offset + CONF_currentoffset[channel] = (uint16_t) hex_to_int(rxbuf[6]) * 4096 + hex_to_int(rxbuf[7]) * 256 + hex_to_int(rxbuf[8]) * 16 + hex_to_int(rxbuf[9]); + send_answer_hex(&rxbuf[0], CONF_currentoffset[channel]); + } + if (regnumber == 7) { //Register 7: Current Gain + uint16_t tmp = (uint16_t) hex_to_int(rxbuf[6]) * 4096 + hex_to_int(rxbuf[7]) * 256 + hex_to_int(rxbuf[8]) * 16 + hex_to_int(rxbuf[9]); + CONF_currentgain[channel] = (float) tmp / 1000.; + send_answer_hex(&rxbuf[0], tmp); + } + if (regnumber == 8) { //Register 8: Voltage Divider + uint16_t tmp = (uint16_t) hex_to_int(rxbuf[6]) * 4096 + hex_to_int(rxbuf[7]) * 256 + hex_to_int(rxbuf[8]) * 16 + hex_to_int(rxbuf[9]); + CONF_voltagedivider[channel] = (float) tmp / 1000.; + send_answer_hex(&rxbuf[0], (uint16_t)(CONF_voltagedivider[channel] * 1000)); + } + if (regnumber == 9) { //Register 9: Current Limit + CONF_overcurrent[channel] = (uint16_t) hex_to_int(rxbuf[6]) * 4096 + hex_to_int(rxbuf[7]) * 256 + hex_to_int(rxbuf[8]) * 16 + hex_to_int(rxbuf[9]); + send_answer_hex(&rxbuf[0], CONF_overcurrent[channel]); + } + if (regnumber == 0xa) { //Register 10: Overvoltage Limit + CONF_overvoltage[channel] = (uint16_t) hex_to_int(rxbuf[6]) * 4096 + hex_to_int(rxbuf[7]) * 256 + hex_to_int(rxbuf[8]) * 16 + hex_to_int(rxbuf[9]); + send_answer_hex(&rxbuf[0], CONF_overvoltage[channel]); + } + if (regnumber == 0xb) { //Register 11: Undervoltage Limit + CONF_undervoltage[channel] = (uint16_t) hex_to_int(rxbuf[6]) * 4096 + hex_to_int(rxbuf[7]) * 256 + hex_to_int(rxbuf[8]) * 16 + hex_to_int(rxbuf[9]); + send_answer_hex(&rxbuf[0], CONF_undervoltage[channel]); + } + } + } + } + + + if (rxcnt >= 11 || buf == '\n' || buf == '\r') { + rxcnt = 0; + } + } + + + + +// | Registers | description | +// |-----------|--------------------------------------------------------------| +// | 0 | Channel ON/OFF | +// | 1 | Voltage V_out (RO) | +// | 2 | Voltage V_in (RO) | +// | 3 | Current C_in (RO) | +// | 4 | Save settings (WO) | +// | 5 | [15:4] Firmware, [3..0] number of channels (RO) | +// | 6 | Current Offset | in ADC LSB (0.125 mV) +// | 7 | Current Gain | in mV/A +// | 8 | Voltage Divider | in mV/V (ratio times 1000) +// | 9 | Overcurrent Limit | in mA +// | A | Overvoltage Limit | in mV +// | B | Undervoltage Limit | in mV + + +