--- /dev/null
+ /*
+
+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 <Adafruit_ADS1X15.h> //for external ADC
+#include <ETH.h> //for Telnet Server Connection
+#include <Wire.h> //for I2C Connection
+#include <Adafruit_SSD1306.h> //for OLED display driver
+#include <SPI.h> //for display control
+#include <EEPROM.h> //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
+
+
+