Files
ESPEasy/src/_P020_Ser2Net.ino
T
Gijs Noorlander 1de135001b [Cleanup] Include _Plugin_Helper.h in all plugin INO files
This does include almost all needed for a plugin.
So it will make intellisense highlighting useful as otherwise almost each line in a plugin file will be marked red.
2020-03-03 16:42:07 +01:00

329 lines
12 KiB
Arduino

#ifdef USES_P020
//#######################################################################################################
//#################################### Plugin 020: Ser2Net ##############################################
//#######################################################################################################
#include "_Plugin_Helper.h"
#define PLUGIN_020
#define PLUGIN_ID_020 20
#define PLUGIN_NAME_020 "Communication - Serial Server"
#define PLUGIN_VALUENAME1_020 "Ser2Net"
#define P020_BUFFER_SIZE 128
boolean Plugin_020_init = false;
byte Plugin_020_SerialProcessing = 0;
WiFiServer *ser2netServer;
WiFiClient ser2netClient;
boolean Plugin_020(byte function, struct EventStruct *event, String& string)
{
boolean success = false;
static byte connectionState = 0;
switch (function)
{
case PLUGIN_DEVICE_ADD:
{
Device[++deviceCount].Number = PLUGIN_ID_020;
Device[deviceCount].Type = DEVICE_TYPE_SINGLE;
Device[deviceCount].Custom = true;
Device[deviceCount].TimerOption = false;
break;
}
case PLUGIN_GET_DEVICENAME:
{
string = F(PLUGIN_NAME_020);
break;
}
case PLUGIN_GET_DEVICEVALUENAMES:
{
strcpy_P(ExtraTaskSettings.TaskDeviceValueNames[0], PSTR(PLUGIN_VALUENAME1_020));
break;
}
case PLUGIN_GET_DEVICEGPIONAMES:
{
event->String1 = formatGpioName_bidirectional(F("Reset"));
break;
}
case PLUGIN_WEBFORM_LOAD:
{
addFormNumericBox(F("TCP Port"), F("p020_port"), ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
addFormNumericBox(F("Baud Rate"), F("p020_baud"), ExtraTaskSettings.TaskDevicePluginConfigLong[1]);
addFormNumericBox(F("Data bits"), F("p020_data"), ExtraTaskSettings.TaskDevicePluginConfigLong[2]);
byte choice = ExtraTaskSettings.TaskDevicePluginConfigLong[3];
String options[3];
options[0] = F("No parity");
options[1] = F("Even");
options[2] = F("Odd");
int optionValues[3];
optionValues[0] = 0;
optionValues[1] = 2;
optionValues[2] = 3;
addFormSelector(F("Parity"), F("p020_parity"), 3, options, optionValues, choice);
addFormNumericBox(F("Stop bits"), F("p020_stop"), ExtraTaskSettings.TaskDevicePluginConfigLong[4]);
addFormPinSelect(F("TX Enable Pin"), F("taskdevicepin2"), Settings.TaskDevicePin2[event->TaskIndex]);
addFormPinSelect(F("Reset target after boot"), F("taskdevicepin1"), Settings.TaskDevicePin1[event->TaskIndex]);
addFormNumericBox(F("RX Receive Timeout (mSec)"), F("p020_rxwait"), Settings.TaskDevicePluginConfig[event->TaskIndex][0]);
byte choice2 = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
String options2[3];
options2[0] = F("None");
options2[1] = F("Generic");
options2[2] = F("RFLink");
addFormSelector(F("Event processing"), F("p020_events"), 3, options2, NULL, choice2);
success = true;
break;
}
case PLUGIN_WEBFORM_SAVE:
{
ExtraTaskSettings.TaskDevicePluginConfigLong[0] = getFormItemInt(F("p020_port"));
ExtraTaskSettings.TaskDevicePluginConfigLong[1] = getFormItemInt(F("p020_baud"));
ExtraTaskSettings.TaskDevicePluginConfigLong[2] = getFormItemInt(F("p020_data"));
ExtraTaskSettings.TaskDevicePluginConfigLong[3] = getFormItemInt(F("p020_parity"));
ExtraTaskSettings.TaskDevicePluginConfigLong[4] = getFormItemInt(F("p020_stop"));
Settings.TaskDevicePluginConfig[event->TaskIndex][0] = getFormItemInt(F("p020_rxwait"));
Settings.TaskDevicePluginConfig[event->TaskIndex][1] = getFormItemInt(F("p020_events"));
success = true;
break;
}
case PLUGIN_INIT:
{
LoadTaskSettings(event->TaskIndex);
if ((ExtraTaskSettings.TaskDevicePluginConfigLong[0] != 0) && (ExtraTaskSettings.TaskDevicePluginConfigLong[1] != 0))
{
#if defined(ESP8266)
byte serialconfig = 0x10;
#endif
#if defined(ESP32)
uint32_t serialconfig = 0x8000010;
#endif
serialconfig += ExtraTaskSettings.TaskDevicePluginConfigLong[3];
serialconfig += (ExtraTaskSettings.TaskDevicePluginConfigLong[2] - 5) << 2;
if (ExtraTaskSettings.TaskDevicePluginConfigLong[4] == 2)
serialconfig += 0x20;
#if defined(ESP8266)
Serial.begin(ExtraTaskSettings.TaskDevicePluginConfigLong[1], (SerialConfig)serialconfig);
#endif
#if defined(ESP32)
Serial.begin(ExtraTaskSettings.TaskDevicePluginConfigLong[1], serialconfig);
#endif
ser2netServer = new WiFiServer(ExtraTaskSettings.TaskDevicePluginConfigLong[0]);
ser2netServer->begin();
if (Settings.TaskDevicePin1[event->TaskIndex] != -1)
{
pinMode(Settings.TaskDevicePin1[event->TaskIndex], OUTPUT);
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], LOW);
delay(500);
digitalWrite(Settings.TaskDevicePin1[event->TaskIndex], HIGH);
pinMode(Settings.TaskDevicePin1[event->TaskIndex], INPUT_PULLUP);
}
// set the TX Enable Pin to LOW
if (Settings.TaskDevicePin2[event->TaskIndex] != -1)
{
pinMode(Settings.TaskDevicePin2[event->TaskIndex], OUTPUT);
digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW);
}
Plugin_020_init = true;
}
Plugin_020_SerialProcessing = Settings.TaskDevicePluginConfig[event->TaskIndex][1];
success = true;
break;
}
case PLUGIN_TEN_PER_SECOND:
{
if (Plugin_020_init)
{
size_t bytes_read;
if (ser2netServer->hasClient())
{
if (ser2netClient) ser2netClient.stop();
ser2netClient = ser2netServer->available();
addLog(LOG_LEVEL_ERROR, F("Ser2N: Client connected!"));
}
if (ser2netClient.connected())
{
connectionState = 1;
uint8_t net_buf[P020_BUFFER_SIZE];
int count = ser2netClient.available();
if (count > 0)
{
if (count > P020_BUFFER_SIZE)
count = P020_BUFFER_SIZE;
bytes_read = ser2netClient.read(net_buf, count);
if (Settings.TaskDevicePin2[event->TaskIndex] != -1)
{
digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], HIGH); // Activate the TX Enable
}
Serial.write(net_buf, bytes_read);
Serial.flush(); // Waits for the transmission of outgoing serial data to complete
if (Settings.TaskDevicePin2[event->TaskIndex] != -1)
{
digitalWrite(Settings.TaskDevicePin2[event->TaskIndex], LOW); // Deactivate the TX Enable
}
if (count == P020_BUFFER_SIZE) // if we have a full buffer, drop the last position to stuff with string end marker
{
count--;
addLog(LOG_LEVEL_ERROR, F("Ser2N: network buffer full!"));
}
net_buf[count] = 0; // before logging as a char array, zero terminate the last position to be safe.
char log[P020_BUFFER_SIZE + 40];
sprintf_P(log, PSTR("Ser2N: N>: %s"), (char*)net_buf);
addLog(LOG_LEVEL_DEBUG, log);
}
}
else
{
if (connectionState == 1) // there was a client connected before...
{
connectionState = 0;
// workaround see: https://github.com/esp8266/Arduino/issues/4497#issuecomment-373023864
ser2netClient = WiFiClient();
ser2netClient.setTimeout(CONTROLLER_CLIENTTIMEOUT_DFLT);
addLog(LOG_LEVEL_ERROR, F("Ser2N: Client disconnected!"));
}
while (Serial.available())
Serial.read();
}
success = true;
}
break;
}
case PLUGIN_SERIAL_IN:
{
if (Plugin_020_init)
{
uint8_t serial_buf[P020_BUFFER_SIZE];
int RXWait = Settings.TaskDevicePluginConfig[event->TaskIndex][0];
if (RXWait == 0)
RXWait = 1;
int timeOut = RXWait;
size_t bytes_read = 0;
while (timeOut > 0)
{
while (Serial.available()) {
if (bytes_read < P020_BUFFER_SIZE) {
serial_buf[bytes_read] = Serial.read();
bytes_read++;
}
else
Serial.read(); // when the buffer is full, just read remaining input, but do not store...
timeOut = RXWait; // if serial received, reset timeout counter
}
delay(1);
timeOut--;
}
if (bytes_read != P020_BUFFER_SIZE)
{
if (bytes_read > 0) {
if (Plugin_020_init && ser2netClient.connected())
{
ser2netClient.write((const uint8_t*)serial_buf, bytes_read);
ser2netClient.flush();
}
}
}
else // if we have a full buffer, drop the last position to stuff with string end marker
{
while (Serial.available()) // read possible remaining data to avoid sending rubbish...
Serial.read();
bytes_read--;
// and log buffer full situation
addLog(LOG_LEVEL_ERROR, F("Ser2N: serial buffer full!"));
}
serial_buf[bytes_read] = 0; // before logging as a char array, zero terminate the last position to be safe.
char log[P020_BUFFER_SIZE + 40];
sprintf_P(log, PSTR("Ser2N: S>: %s"), (char*)serial_buf);
addLog(LOG_LEVEL_DEBUG, log);
// We can also use the rules engine for local control!
if (Settings.UseRules)
{
String message = (char*)serial_buf;
int NewLinePos = message.indexOf("\r\n");
if (NewLinePos > 0)
message = message.substring(0, NewLinePos);
String eventString = "";
switch (Plugin_020_SerialProcessing)
{
case 0:
{
break;
}
case 1: // Generic
{
eventString = F("!Serial#");
eventString += message;
break;
}
case 2: // RFLink
{
message = message.substring(6); // RFLink, strip 20;xx; from incoming message
if (message.startsWith("ESPEASY")) // Special treatment for gpio values, strip unneeded parts...
{
message = message.substring(8); // Strip "ESPEASY;"
eventString = F("RFLink#");
}
else
eventString = F("!RFLink#"); // default event as it comes in, literal match needed in rules, using '!'
eventString += message;
break;
}
} // switch
if (eventString.length() > 0)
eventQueue.add(eventString);
} // if rules
success = true;
break;
}
}
case PLUGIN_WRITE:
{
String command = parseString(string, 1);
if (command == F("serialsend"))
{
success = true;
String tmpString = string.substring(11);
Serial.println(tmpString); // FIXME TD-er: Should this also use the serial write buffer?
}
break;
}
}
return success;
}
#endif // USES_P020