+ /*
+
+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 <SPI.h> //for display control
+#include <EEPROM.h> //to save settings
+#include <ModbusRTUMaster.h>
+
+#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 CB0 32
+#define CB1 5
+#define CB2 33
+#define CB3 14
+
+
+ModbusRTUMaster modbus(Serial);
+
+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[13];
+unsigned long lastModBus = 0;
+/*****************************************************************
+ * Ethernet
+ *****************************************************************/
+void WiFiEvent(WiFiEvent_t event) {
+ 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;
+ }
+}
+
+
+/*****************************************************************
+ * Command Handling
+ *****************************************************************/
+
+// convert integer or nibbles into hex value
+uint8_t nib_to_hex(uint32_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;
+ }
+
+
+uint32_t hex_to_int32(uint8_t * buf) {
+ uint32_t value = 0;
+ for(uint8_t i = 0;i < 8; i++) {
+ value <<= 4;
+ value += hex_to_int(*buf);
+ buf++;
+ }
+ return value;
+ }
+
+//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, uint32_t v) {
+ txbuf[0] = 'A';
+ txbuf[1] = rxbuf[1];
+ txbuf[2] = rxbuf[2];
+ txbuf[3] = nib_to_hex(v, 7);
+ txbuf[4] = nib_to_hex(v, 6);
+ txbuf[5] = nib_to_hex(v, 5);
+ txbuf[6] = nib_to_hex(v, 4);
+ txbuf[7] = nib_to_hex(v, 3);
+ txbuf[8] = nib_to_hex(v, 2);
+ txbuf[9] = nib_to_hex(v, 1);
+ txbuf[10] =nib_to_hex(v, 0);
+ txbuf[11] = '\n';
+ txbuf[12] = 0;
+ send_answer_buf(txbuf,12);
+ }
+
+/*****************************************************************
+ * IO Port
+ *****************************************************************/
+void set_port(uint32_t port) {
+ digitalWrite(CB0,(port >> 0) & 1);
+ digitalWrite(CB1,(port >> 4) & 1);
+ digitalWrite(CB2,(port >> 8) & 1);
+ digitalWrite(CB3,(port >> 12) & 1);
+ }
+
+void set_ddr(uint32_t ddr) {
+ if(ddr & 0x0001) pinMode(CB0, OUTPUT); else pinMode(CB0, INPUT);
+ if(ddr & 0x0010) pinMode(CB1, OUTPUT); else pinMode(CB1, INPUT);
+ if(ddr & 0x0100) pinMode(CB2, OUTPUT); else pinMode(CB2, INPUT);
+ if(ddr & 0x1000) pinMode(CB3, OUTPUT); else pinMode(CB3, INPUT);
+ }
+
+uint32_t get_pin() {
+ uint16_t pin = 0;
+ if(digitalRead(CB0)) pin |= 0x0001;
+ if(digitalRead(CB1)) pin |= 0x0010;
+ if(digitalRead(CB2)) pin |= 0x0100;
+ if(digitalRead(CB3)) pin |= 0x1000;
+ return pin;
+ }
+
+
+/*****************************************************************
+ * EEPROM
+ *****************************************************************/
+
+/*****************************************************************
+ * Setup
+ *****************************************************************/
+
+void setup() {
+ pinMode(LED_YELLOW, OUTPUT);
+ pinMode(LED_GREEN, OUTPUT);
+
+ //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);
+ // Serial.begin(9600, SERIAL_8N2);
+
+ Serial.begin(9600,SERIAL_8N1);
+ modbus.begin(9600,SERIAL_8N1);
+ modbus.setTimeout(1000);
+ }
+
+
+
+/*****************************************************************
+ * 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 - lastModBus >= 1000) {
+ // lastModBus = time;
+ // modbustest();
+ // }
+ }
+
+// void modbustest(){
+// uint16_t inputdata[10] = {0xeeee};
+// for(uint8_t i=2; i<3; i++) {
+// uint32_t error = modbus.readHoldingRegisters(2,i,inputdata,2);
+// rxbuf[2] = 'e';
+// rxbuf[1] = 'e';
+// send_answer_hex(rxbuf,error);
+// rxbuf[2] = nib_to_hex(i,0);
+// rxbuf[1] = nib_to_hex(i,1);
+// send_answer_hex(rxbuf,((uint32_t)inputdata[0]));
+// send_answer_hex(rxbuf,((uint32_t)inputdata[1]));
+// send_answer_hex(rxbuf,((uint32_t)inputdata[2]));
+// send_answer_hex(rxbuf,((uint32_t)inputdata[3]));
+//
+// send_answer_hex(rxbuf,(((uint32_t)inputdata[0])<<16) + inputdata[1]);
+// send_answer_hex(rxbuf,(((uint32_t)inputdata[2])<<16) + inputdata[3]);
+//
+// send_answer_hex(rxbuf,0x12345678);
+// }
+// }
+
+uint8_t modbus_busid;
+
+
+/*****************************************************************
+ * 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 == 12) {
+ uint8_t regnumber = hex_to_int(rxbuf[2]) + hex_to_int(rxbuf[1])*16;
+
+ if (rxbuf[0] == 'R') {
+ if (regnumber == 1) { //Register 1: PIN
+ send_answer_hex(&rxbuf[0], get_pin());
+ }
+
+ }
+ if (rxbuf[0] == 'W') {
+ uint32_t value = hex_to_int32(&rxbuf[3]);
+ if (regnumber == 0) { //Register 0: PORT
+ set_port(value);
+ send_answer_hex(&rxbuf[0], value);
+ }
+ if (regnumber == 2) { //Register 2: DDR
+ set_ddr(value);
+ send_answer_hex(&rxbuf[0], value);
+ }
+ if (regnumber == 0x10) { //Register 10: MODBUS_SETUP
+ modbus_busid = hex_to_int(rxbuf[4]) + hex_to_int(rxbuf[3])*16;
+ }
+ if (regnumber == 0x11) { //Register 11: MODBUS_READ_REG
+ uint16_t modbus_address = hex_to_int(rxbuf[6]) + hex_to_int(rxbuf[5])*16 + hex_to_int(rxbuf[4])*16*16 + hex_to_int(rxbuf[3])*16*16*16;
+ uint8_t modbus_length = hex_to_int(rxbuf[10]) + hex_to_int(rxbuf[9])*16;
+ uint16_t inputdata[10];
+ uint32_t error = modbus.readHoldingRegisters(modbus_busid,modbus_address,inputdata,modbus_length);
+ if(error) {
+ send_answer_hex(rxbuf,error + 0xeeeeee00);
+ }
+ else {
+ send_answer_hex(rxbuf,(((uint32_t)inputdata[0])<<16) + inputdata[1]);
+ }
+ }
+ if (regnumber == 0x12) { //Register 10: MODBUS_WRITE_REG
+ uint16_t modbus_address = hex_to_int(rxbuf[6]) + hex_to_int(rxbuf[5])*16 + hex_to_int(rxbuf[4])*16*16 + hex_to_int(rxbuf[3])*16*16*16;
+ uint16_t modbus_data = hex_to_int(rxbuf[10]) + hex_to_int(rxbuf[9])*16 + hex_to_int(rxbuf[8])*16*16 + hex_to_int(rxbuf[7])*16*16*16;
+ uint32_t error = modbus.writeSingleHoldingRegister(modbus_busid,modbus_address,modbus_data);
+ if(error) {
+ send_answer_hex(rxbuf,error + 0xeeeeee00);
+ }
+ else {
+ send_answer_hex(rxbuf,0);
+ }
+ }
+ }
+ }
+ }
+
+ if (rxcnt >= 12 || buf == '\n' || buf == '\r') {
+ rxcnt = 0;
+ }
+ }
+
+
+/*
+ **Data format:** *XRRvvvvvvvv*
+ X - command (write: W, read: R, answer: A)
+ R - register (Hex value)
+ vvvvvvvv - 32 Bit value
+
+ close with a "\n"
+ e.g. "W0200000000\n"
+
+
+| Registers | description |
+|-----------|--------------------------------------------------------------|
+| 0 | PORT_C (W) | V = xxxx3210 (one nibble per pin, possible values 0/1)
+| 1 | PIN_C (R) |
+| 2 | DDR_C (W) |
+| 10h | MODBUS_SETUP II000000 (W) | I: busId
+| 11h | MODBUS_READ_REG AAAA00LL (W) | read LL (1 or 2) words from address A
+| 12h | MODBUS_WRITE_REG AAAADDDD (W) | write 16 bit data D to address A
+*/