2019-01-05 13:25:01 +11:00
|
|
|
/*
|
|
|
|
WiFi SIXFOUR - A virtual WiFi modem based on the ESP 8266 chipset
|
|
|
|
Copyright (C) 2016 Paul Rickards <rickards@gmail.com>
|
|
|
|
Added EEPROM read/write, status/help pages, busy answering of incoming calls
|
|
|
|
uses the readily available Sparkfun ESP8266 WiFi Shield which has 5v level
|
|
|
|
shifters and 3.3v voltage regulation present-- easily connect to a C64
|
|
|
|
https://www.sparkfun.com/products/13287
|
|
|
|
|
|
|
|
based on
|
|
|
|
ESP8266 based virtual modem
|
|
|
|
Copyright (C) 2016 Jussi Salin <salinjus@gmail.com>
|
|
|
|
|
|
|
|
https://github.com/jsalin/esp8266_modem
|
|
|
|
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <ESP8266WiFi.h>
|
|
|
|
#include <ESP8266WebServer.h>
|
|
|
|
#include <EEPROM.h>
|
|
|
|
#include <ESP8266mDNS.h>
|
|
|
|
|
|
|
|
// Project headers
|
|
|
|
#include <WiFi64.h>
|
|
|
|
|
|
|
|
// Global variables
|
|
|
|
String cmd = ""; // Gather a new AT command to this string from serial
|
|
|
|
bool cmdMode = true; // Are we in AT command mode or connected mode
|
|
|
|
bool callConnected = false;// Are we currently in a call
|
|
|
|
bool telnet = false; // Is telnet control code handling enabled
|
|
|
|
bool verboseResults = false;
|
|
|
|
//#define DEBUG 1 // Print additional debug information to serial channel
|
|
|
|
#undef DEBUG
|
|
|
|
#define LISTEN_PORT 6400 // Listen to this if not connected. Set to zero to disable.
|
|
|
|
int tcpServerPort = LISTEN_PORT;
|
|
|
|
#define RING_INTERVAL 3000 // How often to print RING when having a new incoming connection (ms)
|
|
|
|
unsigned long lastRingMs = 0; // Time of last "RING" message (millis())
|
|
|
|
//long myBps; // What is the current BPS setting
|
|
|
|
#define MAX_CMD_LENGTH 256 // Maximum length for AT command
|
|
|
|
char plusCount = 0; // Go to AT mode at "+++" sequence, that has to be counted
|
|
|
|
unsigned long plusTime = 0;// When did we last receive a "+++" sequence
|
|
|
|
#define LED_TIME 15 // How many ms to keep LED on at activity
|
|
|
|
unsigned long ledTime = 0;
|
|
|
|
#define TX_BUF_SIZE 256 // Buffer where to read from serial before writing to TCP
|
|
|
|
// (that direction is very blocking by the ESP TCP stack,
|
|
|
|
// so we can't do one byte a time.)
|
|
|
|
uint8_t txBuf[TX_BUF_SIZE];
|
|
|
|
const int speedDialAddresses[] = { DIAL0_ADDRESS, DIAL1_ADDRESS, DIAL2_ADDRESS, DIAL3_ADDRESS, DIAL4_ADDRESS, DIAL5_ADDRESS, DIAL6_ADDRESS, DIAL7_ADDRESS, DIAL8_ADDRESS, DIAL9_ADDRESS };
|
|
|
|
String speedDials[10];
|
|
|
|
const int bauds[] = { 300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200 };
|
|
|
|
byte serialspeed;
|
|
|
|
bool echo = true;
|
|
|
|
bool autoAnswer = false;
|
|
|
|
String ssid, password, busyMsg;
|
|
|
|
byte ringCount = 0;
|
|
|
|
String resultCodes[] = { "OK", "CONNECT", "RING", "NO CARRIER", "ERROR", "", "NO DIALTONE", "BUSY", "NO ANSWER" };
|
|
|
|
enum resultCodes_t { R_OK, R_CONNECT, R_RING, R_NOCARRIER, R_ERROR, R_NONE, R_NODIALTONE, R_BUSY, R_NOANSWER };
|
|
|
|
unsigned long connectTime = 0;
|
|
|
|
bool petTranslate = false; // Fix PET MCTerm 1.26C Pet->ASCII encoding to actual ASCII
|
|
|
|
bool hex = false;
|
|
|
|
enum flowControl_t { F_NONE, F_HARDWARE, F_SOFTWARE };
|
|
|
|
byte flowControl = F_NONE; // Use flow control
|
|
|
|
bool txPaused = false; // Has flow control asked us to pause?
|
|
|
|
enum pinPolarity_t { P_INVERTED, P_NORMAL }; // Is LOW (0) or HIGH (1) active?
|
|
|
|
byte pinPolarity = P_INVERTED;
|
|
|
|
|
|
|
|
// Telnet codes
|
|
|
|
#define DO 0xfd
|
|
|
|
#define WONT 0xfc
|
|
|
|
#define WILL 0xfb
|
|
|
|
#define DONT 0xfe
|
|
|
|
|
|
|
|
WiFiClient tcpClient;
|
|
|
|
WiFiServer tcpServer(tcpServerPort);
|
|
|
|
ESP8266WebServer webServer(80);
|
|
|
|
MDNSResponder mdns;
|
|
|
|
|
|
|
|
extern void waitForSpace();
|
|
|
|
extern void displayHelp();
|
|
|
|
extern void welcome();
|
|
|
|
|
|
|
|
String connectTimeString() {
|
|
|
|
unsigned long now = millis();
|
|
|
|
int secs = (now - connectTime) / 1000;
|
|
|
|
int mins = secs / 60;
|
|
|
|
int hours = mins / 60;
|
|
|
|
String out = "";
|
|
|
|
if (hours < 10) out.concat("0");
|
|
|
|
out.concat(String(hours));
|
|
|
|
out.concat(":");
|
|
|
|
if (mins % 60 < 10) out.concat("0");
|
|
|
|
out.concat(String(mins % 60));
|
|
|
|
out.concat(":");
|
|
|
|
if (secs % 60 < 10) out.concat("0");
|
|
|
|
out.concat(String(secs % 60));
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
|
|
|
void writeSettings() {
|
|
|
|
setEEPROM(ssid, SSID_ADDRESS, SSID_LEN);
|
|
|
|
setEEPROM(password, PASS_ADDRESS, PASS_LEN);
|
|
|
|
setEEPROM(busyMsg, BUSY_MSG_ADDRESS, BUSY_MSG_LEN);
|
|
|
|
|
|
|
|
EEPROM.write(BAUD_ADDRESS, serialspeed);
|
|
|
|
EEPROM.write(ECHO_ADDRESS, byte(echo));
|
|
|
|
EEPROM.write(AUTO_ANSWER_ADDRESS, byte(autoAnswer));
|
|
|
|
EEPROM.write(SERVER_PORT_ADDRESS, highByte(tcpServerPort));
|
|
|
|
EEPROM.write(SERVER_PORT_ADDRESS + 1, lowByte(tcpServerPort));
|
|
|
|
EEPROM.write(TELNET_ADDRESS, byte(telnet));
|
|
|
|
EEPROM.write(VERBOSE_ADDRESS, byte(verboseResults));
|
|
|
|
EEPROM.write(PET_TRANSLATE_ADDRESS, byte(petTranslate));
|
|
|
|
EEPROM.write(FLOW_CONTROL_ADDRESS, byte(flowControl));
|
|
|
|
EEPROM.write(PIN_POLARITY_ADDRESS, byte(pinPolarity));
|
|
|
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
setEEPROM(speedDials[i], speedDialAddresses[i], 50);
|
|
|
|
}
|
|
|
|
EEPROM.commit();
|
|
|
|
}
|
|
|
|
|
|
|
|
void readSettings() {
|
|
|
|
echo = EEPROM.read(ECHO_ADDRESS);
|
|
|
|
autoAnswer = EEPROM.read(AUTO_ANSWER_ADDRESS);
|
|
|
|
// serialspeed = EEPROM.read(BAUD_ADDRESS);
|
|
|
|
|
|
|
|
ssid = getEEPROM(SSID_ADDRESS, SSID_LEN);
|
|
|
|
password = getEEPROM(PASS_ADDRESS, PASS_LEN);
|
|
|
|
busyMsg = getEEPROM(BUSY_MSG_ADDRESS, BUSY_MSG_LEN);
|
|
|
|
tcpServerPort = word(EEPROM.read(SERVER_PORT_ADDRESS), EEPROM.read(SERVER_PORT_ADDRESS + 1));
|
|
|
|
telnet = EEPROM.read(TELNET_ADDRESS);
|
|
|
|
verboseResults = EEPROM.read(VERBOSE_ADDRESS);
|
|
|
|
petTranslate = EEPROM.read(PET_TRANSLATE_ADDRESS);
|
|
|
|
flowControl = EEPROM.read(FLOW_CONTROL_ADDRESS);
|
|
|
|
pinPolarity = EEPROM.read(PIN_POLARITY_ADDRESS);
|
|
|
|
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
speedDials[i] = getEEPROM(speedDialAddresses[i], 50);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void defaultEEPROM() {
|
|
|
|
EEPROM.write(VERSION_ADDRESS, VERSIONA);
|
|
|
|
EEPROM.write(VERSION_ADDRESS + 1, VERSIONB);
|
|
|
|
|
|
|
|
setEEPROM("", SSID_ADDRESS, SSID_LEN);
|
|
|
|
setEEPROM("", PASS_ADDRESS, PASS_LEN);
|
|
|
|
setEEPROM("d", IP_TYPE_ADDRESS, 1);
|
|
|
|
EEPROM.write(SERVER_PORT_ADDRESS, highByte(LISTEN_PORT));
|
|
|
|
EEPROM.write(SERVER_PORT_ADDRESS + 1, lowByte(LISTEN_PORT));
|
|
|
|
|
|
|
|
EEPROM.write(BAUD_ADDRESS, 0x00);
|
|
|
|
EEPROM.write(ECHO_ADDRESS, 0x01);
|
|
|
|
EEPROM.write(AUTO_ANSWER_ADDRESS, 0x01);
|
|
|
|
EEPROM.write(TELNET_ADDRESS, 0x00);
|
|
|
|
EEPROM.write(VERBOSE_ADDRESS, 0x01);
|
|
|
|
EEPROM.write(PET_TRANSLATE_ADDRESS, 0x00);
|
|
|
|
EEPROM.write(FLOW_CONTROL_ADDRESS, 0x00);
|
|
|
|
EEPROM.write(PIN_POLARITY_ADDRESS, 0x01);
|
|
|
|
|
|
|
|
setEEPROM(SPEEDDIAL0, speedDialAddresses[0], 50);
|
|
|
|
setEEPROM(SPEEDDIAL1, speedDialAddresses[1], 50);
|
|
|
|
setEEPROM(SPEEDDIAL2, speedDialAddresses[2], 50);
|
|
|
|
setEEPROM(SPEEDDIAL3, speedDialAddresses[3], 50);
|
|
|
|
setEEPROM(SPEEDDIAL4, speedDialAddresses[4], 50);
|
|
|
|
setEEPROM(SPEEDDIAL5, speedDialAddresses[5], 50);
|
|
|
|
setEEPROM(SPEEDDIAL6, speedDialAddresses[6], 50);
|
|
|
|
setEEPROM(SPEEDDIAL7, speedDialAddresses[7], 50);
|
|
|
|
setEEPROM(SPEEDDIAL8, speedDialAddresses[8], 50);
|
|
|
|
setEEPROM(SPEEDDIAL9, speedDialAddresses[9], 50);
|
|
|
|
|
|
|
|
for (int i = 5; i < 10; i++) {
|
|
|
|
setEEPROM("", speedDialAddresses[i], 50);
|
|
|
|
}
|
|
|
|
|
|
|
|
setEEPROM("SORRY, SYSTEM IS CURRENTLY BUSY. PLEASE TRY AGAIN LATER.", BUSY_MSG_ADDRESS, BUSY_MSG_LEN);
|
|
|
|
EEPROM.commit();
|
|
|
|
}
|
|
|
|
|
|
|
|
String getEEPROM(int startAddress, int len) {
|
|
|
|
String myString;
|
|
|
|
|
|
|
|
for (int i = startAddress; i < startAddress + len; i++) {
|
|
|
|
if (EEPROM.read(i) == 0x00) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
myString += char(EEPROM.read(i));
|
|
|
|
//Serial.print(char(EEPROM.read(i)));
|
|
|
|
}
|
|
|
|
//Serial.println();
|
|
|
|
return myString;
|
|
|
|
}
|
|
|
|
|
|
|
|
void setEEPROM(String inString, int startAddress, int maxLen) {
|
|
|
|
for (unsigned int i = startAddress; i < inString.length() + startAddress; i++) {
|
|
|
|
EEPROM.write(i, inString[i - startAddress]);
|
|
|
|
//Serial.print(i, DEC); Serial.print(": "); Serial.println(inString[i - startAddress]);
|
|
|
|
//if (EEPROM.read(i) != inString[i - startAddress]) { Serial.print(" (!)"); }
|
|
|
|
//Serial.println();
|
|
|
|
}
|
|
|
|
// null pad the remainder of the memory space
|
|
|
|
for (int i = inString.length() + startAddress; i < maxLen + startAddress; i++) {
|
|
|
|
EEPROM.write(i, 0x00);
|
|
|
|
//Serial.print(i, DEC); Serial.println(": 0x00");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendResult(int resultCode) {
|
|
|
|
Serial.print("\r\n");
|
|
|
|
if (verboseResults == 0) {
|
|
|
|
Serial.println(resultCode);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (resultCode == R_CONNECT) {
|
|
|
|
Serial.print(String(resultCodes[R_CONNECT]) + " " + String(bauds[serialspeed]));
|
|
|
|
} else if (resultCode == R_NOCARRIER) {
|
|
|
|
Serial.print(String(resultCodes[R_NOCARRIER]) + " (" + connectTimeString() + ")");
|
|
|
|
} else {
|
|
|
|
Serial.print(String(resultCodes[resultCode]));
|
|
|
|
}
|
|
|
|
Serial.print("\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void sendString(String msg) {
|
|
|
|
Serial.print("\r\n");
|
|
|
|
Serial.print(msg);
|
|
|
|
Serial.print("\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hold for 5 seconds to switch to 300 baud
|
|
|
|
// Slow flash: keep holding
|
|
|
|
// Fast flash: let go
|
|
|
|
int checkButton() {
|
|
|
|
long time = millis();
|
|
|
|
while (digitalRead(SWITCH_PIN) == LOW && millis() - time < 5000) {
|
|
|
|
delay(250);
|
|
|
|
digitalWrite(LED1, !digitalRead(LED1));
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
if (millis() - time > 5000) {
|
|
|
|
Serial.flush();
|
|
|
|
Serial.end();
|
|
|
|
serialspeed = 2;
|
|
|
|
delay(100);
|
|
|
|
Serial.begin(bauds[serialspeed]);
|
|
|
|
sendResult(R_OK);
|
|
|
|
while (digitalRead(SWITCH_PIN) == LOW) {
|
|
|
|
delay(50);
|
|
|
|
digitalWrite(LED1, !digitalRead(LED1));
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
} else {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void connectWiFi() {
|
|
|
|
if (ssid == "" || password == "") {
|
|
|
|
Serial.println("CONFIGURE SSID AND PASSWORD. TYPE AT? FOR HELP.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
WiFi.begin(ssid.c_str(), password.c_str());
|
|
|
|
Serial.print("\nCONNECTING TO SSID "); Serial.print(ssid);
|
|
|
|
uint8_t i = 0;
|
|
|
|
while (WiFi.status() != WL_CONNECTED && i++ < 20) {
|
|
|
|
digitalWrite(LED2, LOW);
|
|
|
|
delay(250);
|
|
|
|
digitalWrite(LED2, HIGH);
|
|
|
|
delay(250);
|
|
|
|
Serial.print(".");
|
|
|
|
}
|
|
|
|
Serial.println();
|
|
|
|
if (i == 30) {
|
|
|
|
Serial.print("COULD NOT CONNECT TO "); Serial.println(ssid);
|
|
|
|
WiFi.disconnect();
|
|
|
|
updateLed();
|
|
|
|
} else {
|
|
|
|
Serial.print("CONNECTED TO "); Serial.println(WiFi.SSID());
|
|
|
|
Serial.print("IP ADDRESS: "); Serial.println(WiFi.localIP());
|
|
|
|
updateLed();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void updateLed() {
|
|
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
|
|
digitalWrite(LED2, LOW); // on
|
|
|
|
} else {
|
|
|
|
digitalWrite(LED2, HIGH); //off
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void disconnectWiFi() {
|
|
|
|
WiFi.disconnect();
|
|
|
|
updateLed();
|
|
|
|
}
|
|
|
|
|
|
|
|
void setBaudRate(int inSpeed) {
|
|
|
|
if (inSpeed == 0) {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
int foundBaud = -1;
|
|
|
|
for (unsigned int i = 0; i < sizeof(bauds); i++) {
|
|
|
|
if (inSpeed == bauds[i]) {
|
|
|
|
foundBaud = i;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// requested baud rate not found, return error
|
|
|
|
if (foundBaud == -1) {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (foundBaud == serialspeed) {
|
|
|
|
sendResult(R_OK);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
Serial.print("SWITCHING SERIAL PORT TO ");
|
|
|
|
Serial.print(inSpeed);
|
|
|
|
Serial.println(" IN 5 SECONDS");
|
|
|
|
delay(5000);
|
|
|
|
Serial.end();
|
|
|
|
delay(200);
|
|
|
|
Serial.begin(bauds[foundBaud]);
|
|
|
|
serialspeed = foundBaud;
|
|
|
|
delay(200);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
void setCarrier(byte carrier) {
|
|
|
|
if (pinPolarity == P_NORMAL) carrier = !carrier;
|
|
|
|
digitalWrite(DCD_PIN, carrier);
|
|
|
|
}
|
|
|
|
|
|
|
|
void displayNetworkStatus() {
|
|
|
|
Serial.print("WIFI STATUS: ");
|
|
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
|
|
Serial.println("CONNECTED");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_IDLE_STATUS) {
|
|
|
|
Serial.println("OFFLINE");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_CONNECT_FAILED) {
|
|
|
|
Serial.println("CONNECT FAILED");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
|
|
|
Serial.println("SSID UNAVAILABLE");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_CONNECTION_LOST) {
|
|
|
|
Serial.println("CONNECTION LOST");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_DISCONNECTED) {
|
|
|
|
Serial.println("DISCONNECTED");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_SCAN_COMPLETED) {
|
|
|
|
Serial.println("SCAN COMPLETED");
|
|
|
|
}
|
|
|
|
yield();
|
|
|
|
|
|
|
|
Serial.print("SSID.......: "); Serial.println(WiFi.SSID());
|
|
|
|
|
|
|
|
// Serial.print("ENCRYPTION: ");
|
|
|
|
// switch(WiFi.encryptionType()) {
|
|
|
|
// case 2:
|
|
|
|
// Serial.println("TKIP (WPA)");
|
|
|
|
// break;
|
|
|
|
// case 5:
|
|
|
|
// Serial.println("WEP");
|
|
|
|
// break;
|
|
|
|
// case 4:
|
|
|
|
// Serial.println("CCMP (WPA)");
|
|
|
|
// break;
|
|
|
|
// case 7:
|
|
|
|
// Serial.println("NONE");
|
|
|
|
// break;
|
|
|
|
// case 8:
|
|
|
|
// Serial.println("AUTO");
|
|
|
|
// break;
|
|
|
|
// default:
|
|
|
|
// Serial.println("UNKNOWN");
|
|
|
|
// break;
|
|
|
|
// }
|
|
|
|
|
|
|
|
byte mac[6];
|
|
|
|
WiFi.macAddress(mac);
|
|
|
|
Serial.print("MAC ADDRESS: ");
|
|
|
|
Serial.print(mac[0], HEX);
|
|
|
|
Serial.print(":");
|
|
|
|
Serial.print(mac[1], HEX);
|
|
|
|
Serial.print(":");
|
|
|
|
Serial.print(mac[2], HEX);
|
|
|
|
Serial.print(":");
|
|
|
|
Serial.print(mac[3], HEX);
|
|
|
|
Serial.print(":");
|
|
|
|
Serial.print(mac[4], HEX);
|
|
|
|
Serial.print(":");
|
|
|
|
Serial.println(mac[5], HEX);
|
|
|
|
yield();
|
|
|
|
|
|
|
|
Serial.print("IP ADDRESS.: "); Serial.println(WiFi.localIP()); yield();
|
|
|
|
Serial.print("GATEWAY....: "); Serial.println(WiFi.gatewayIP()); yield();
|
|
|
|
Serial.print("SUBNET MASK: "); Serial.println(WiFi.subnetMask()); yield();
|
|
|
|
Serial.print("SERVER PORT: "); Serial.println(tcpServerPort); yield();
|
|
|
|
Serial.print("WEB CONFIG.: HTTP://"); Serial.println(WiFi.localIP()); yield();
|
|
|
|
Serial.print("CALL STATUS: "); yield();
|
|
|
|
if (callConnected) {
|
|
|
|
Serial.print("CONNECTED TO "); Serial.println(ipToString(tcpClient.remoteIP())); yield();
|
|
|
|
Serial.print("CALL LENGTH: "); Serial.println(connectTimeString()); yield();
|
|
|
|
} else {
|
|
|
|
Serial.println("NOT CONNECTED");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void displayCurrentSettings() {
|
|
|
|
Serial.println("ACTIVE PROFILE:"); yield();
|
|
|
|
Serial.print("BAUD: "); Serial.println(bauds[serialspeed]); yield();
|
|
|
|
Serial.print("SSID: "); Serial.println(ssid); yield();
|
|
|
|
Serial.print("PASS: "); Serial.println(password); yield();
|
|
|
|
//Serial.print("SERVER TCP PORT: "); Serial.println(tcpServerPort); yield();
|
|
|
|
Serial.print("BUSY MSG: "); Serial.println(busyMsg); yield();
|
|
|
|
Serial.print("E"); Serial.print(echo); Serial.print(" "); yield();
|
|
|
|
Serial.print("V"); Serial.print(verboseResults); Serial.print(" "); yield();
|
|
|
|
Serial.print("&K"); Serial.print(flowControl); Serial.print(" "); yield();
|
|
|
|
Serial.print("&P"); Serial.print(pinPolarity); Serial.print(" "); yield();
|
|
|
|
Serial.print("NET"); Serial.print(telnet); Serial.print(" "); yield();
|
|
|
|
Serial.print("PET"); Serial.print(petTranslate); Serial.print(" "); yield();
|
|
|
|
Serial.print("S0:"); Serial.print(autoAnswer); Serial.print(" "); yield();
|
|
|
|
Serial.println(); yield();
|
|
|
|
|
|
|
|
Serial.println("SPEED DIAL:");
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
Serial.print(i); Serial.print(": "); Serial.println(speedDials[i]);
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
Serial.println();
|
|
|
|
}
|
|
|
|
|
|
|
|
void displayStoredSettings() {
|
|
|
|
Serial.println("STORED PROFILE:"); yield();
|
|
|
|
Serial.print("BAUD: "); Serial.println(bauds[EEPROM.read(BAUD_ADDRESS)]); yield();
|
|
|
|
Serial.print("SSID: "); Serial.println(getEEPROM(SSID_ADDRESS, SSID_LEN)); yield();
|
|
|
|
Serial.print("PASS: "); Serial.println(getEEPROM(PASS_ADDRESS, PASS_LEN)); yield();
|
|
|
|
//Serial.print("SERVER TCP PORT: "); Serial.println(word(EEPROM.read(SERVER_PORT_ADDRESS), EEPROM.read(SERVER_PORT_ADDRESS+1))); yield();
|
|
|
|
Serial.print("BUSY MSG: "); Serial.println(getEEPROM(BUSY_MSG_ADDRESS, BUSY_MSG_LEN)); yield();
|
|
|
|
Serial.print("E"); Serial.print(EEPROM.read(ECHO_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.print("V"); Serial.print(EEPROM.read(VERBOSE_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.print("&K"); Serial.print(EEPROM.read(FLOW_CONTROL_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.print("&P"); Serial.print(EEPROM.read(PIN_POLARITY_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.print("NET"); Serial.print(EEPROM.read(TELNET_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.print("PET"); Serial.print(EEPROM.read(PET_TRANSLATE_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.print("S0:"); Serial.print(EEPROM.read(AUTO_ANSWER_ADDRESS)); Serial.print(" "); yield();
|
|
|
|
Serial.println(); yield();
|
|
|
|
|
|
|
|
Serial.println("STORED SPEED DIAL:");
|
|
|
|
for (int i = 0; i < 10; i++) {
|
|
|
|
Serial.print(i); Serial.print(": "); Serial.println(getEEPROM(speedDialAddresses[i], 50));
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
Serial.println();
|
|
|
|
}
|
|
|
|
|
|
|
|
void storeSpeedDial(byte num, String location) {
|
|
|
|
//if (num < 0 || num > 9) { return; }
|
|
|
|
speedDials[num] = location;
|
|
|
|
//Serial.print("STORED "); Serial.print(num); Serial.print(": "); Serial.println(location);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Arduino main init function
|
|
|
|
*/
|
|
|
|
void setup() {
|
|
|
|
pinMode(LED1, OUTPUT);
|
2019-01-08 20:39:26 +11:00
|
|
|
digitalWrite(LED1, LOW); // off
|
2019-01-05 13:25:01 +11:00
|
|
|
pinMode(LED2, OUTPUT);
|
2019-01-08 20:39:26 +11:00
|
|
|
digitalWrite(LED2, LOW); // off
|
2019-01-05 13:25:01 +11:00
|
|
|
pinMode(LED3, OUTPUT);
|
2019-01-08 20:39:26 +11:00
|
|
|
digitalWrite(LED3, LOW); // off
|
2019-01-05 13:25:01 +11:00
|
|
|
pinMode(LED4, OUTPUT);
|
2019-01-08 20:39:26 +11:00
|
|
|
digitalWrite(LED4, LOW); // off
|
|
|
|
|
|
|
|
pinMode(SWITCH_PIN, INPUT);
|
|
|
|
digitalWrite(SWITCH_PIN, HIGH);
|
|
|
|
pinMode(DCD_PIN, OUTPUT);
|
|
|
|
pinMode(RTS_PIN, OUTPUT);
|
|
|
|
digitalWrite(RTS_PIN, HIGH);
|
|
|
|
pinMode(CTS_PIN, INPUT);
|
|
|
|
setCarrier(false);
|
|
|
|
|
2019-01-05 13:25:01 +11:00
|
|
|
delay(100);
|
2019-01-08 20:39:26 +11:00
|
|
|
|
2019-01-05 13:25:01 +11:00
|
|
|
for (int cnt = 0; cnt < 3; cnt++) {
|
|
|
|
digitalWrite(LED1, HIGH); // off
|
|
|
|
delay(100);
|
|
|
|
digitalWrite(LED1, LOW); // off
|
|
|
|
digitalWrite(LED2, HIGH); // on
|
|
|
|
delay(100);
|
|
|
|
digitalWrite(LED2, LOW); // on
|
|
|
|
digitalWrite(LED3, HIGH); // off
|
|
|
|
delay(100);
|
|
|
|
digitalWrite(LED3, LOW); // off
|
|
|
|
digitalWrite(LED4, HIGH); // on
|
|
|
|
delay(100);
|
|
|
|
digitalWrite(LED4, LOW); // on
|
|
|
|
}
|
|
|
|
digitalWrite(LED1, HIGH); // on
|
2019-01-08 20:39:26 +11:00
|
|
|
digitalWrite(LED2, LOW); // off
|
|
|
|
digitalWrite(LED3, LOW); // off
|
|
|
|
digitalWrite(LED3, LOW); // off
|
2019-01-05 13:25:01 +11:00
|
|
|
|
2019-01-08 20:39:26 +11:00
|
|
|
EEPROM.begin(LAST_ADDRESS + 1);
|
2019-01-05 13:25:01 +11:00
|
|
|
delay(10);
|
|
|
|
|
|
|
|
if (EEPROM.read(VERSION_ADDRESS) != VERSIONA || EEPROM.read(VERSION_ADDRESS + 1) != VERSIONB) {
|
|
|
|
defaultEEPROM();
|
|
|
|
}
|
|
|
|
|
|
|
|
readSettings();
|
|
|
|
// Fetch baud rate from EEPROM
|
|
|
|
serialspeed = EEPROM.read(BAUD_ADDRESS);
|
|
|
|
// Check if it's out of bounds-- we have to be able to talk
|
|
|
|
if (serialspeed < 0 || serialspeed > sizeof(bauds)) {
|
|
|
|
serialspeed = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Serial.begin(bauds[serialspeed]);
|
|
|
|
|
|
|
|
char c = 0x00;
|
|
|
|
//unsigned long startMillis = millis();
|
|
|
|
//while (c != 8 && c != 127 && c!= 20) { // Check for the backspace key to begin
|
|
|
|
//while (c != 32) { // Check for space to begin
|
|
|
|
while (c != 0x0a && c != 0x0d) {
|
|
|
|
if (Serial.available() > 0) {
|
|
|
|
c = Serial.read();
|
|
|
|
if (petTranslate == true){
|
|
|
|
if (c > 127) c-= 128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (checkButton() == 1) {
|
|
|
|
break; // button pressed, we're setting to 300 baud and moving on
|
|
|
|
}
|
|
|
|
//if (millis() - startMillis > 2000) {
|
|
|
|
//digitalWrite(LED2, !digitalRead(LED2));
|
|
|
|
//startMillis = millis();
|
|
|
|
//}
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
welcome();
|
|
|
|
|
|
|
|
if (tcpServerPort > 0) tcpServer.begin();
|
|
|
|
|
|
|
|
WiFi.mode(WIFI_STA);
|
|
|
|
connectWiFi();
|
|
|
|
sendResult(R_OK);
|
|
|
|
//tcpServer(tcpServerPort); // can't start tcpServer inside a function-- must live outside
|
|
|
|
|
|
|
|
digitalWrite(LED2, LOW); // on
|
|
|
|
|
|
|
|
webServer.on("/", handleRoot);
|
|
|
|
webServer.on("/ath", handleWebHangUp);
|
|
|
|
webServer.begin();
|
|
|
|
mdns.begin("C64WiFi", WiFi.localIP());
|
|
|
|
}
|
|
|
|
|
|
|
|
String ipToString(IPAddress ip) {
|
|
|
|
char s[16];
|
|
|
|
sprintf(s, "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
void hangUp() {
|
|
|
|
tcpClient.stop();
|
|
|
|
callConnected = false;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
sendResult(R_NOCARRIER);
|
|
|
|
connectTime = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleWebHangUp() {
|
|
|
|
String t = "NO CARRIER (" + connectTimeString() + ")";
|
|
|
|
hangUp();
|
|
|
|
webServer.send(200, "text/plain", t);
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleRoot() {
|
|
|
|
String page = "WIFI STATUS: ";
|
|
|
|
if (WiFi.status() == WL_CONNECTED) {
|
|
|
|
page.concat("CONNECTED");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_IDLE_STATUS) {
|
|
|
|
page.concat("OFFLINE");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_CONNECT_FAILED) {
|
|
|
|
page.concat("CONNECT FAILED");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_NO_SSID_AVAIL) {
|
|
|
|
page.concat("SSID UNAVAILABLE");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_CONNECTION_LOST) {
|
|
|
|
page.concat("CONNECTION LOST");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_DISCONNECTED) {
|
|
|
|
page.concat("DISCONNECTED");
|
|
|
|
}
|
|
|
|
if (WiFi.status() == WL_SCAN_COMPLETED) {
|
|
|
|
page.concat("SCAN COMPLETED");
|
|
|
|
}
|
|
|
|
yield();
|
|
|
|
page.concat("\nSSID.......: " + WiFi.SSID());
|
|
|
|
|
|
|
|
byte mac[6];
|
|
|
|
WiFi.macAddress(mac);
|
|
|
|
page.concat("\nMAC ADDRESS: ");
|
|
|
|
page.concat(String(mac[0], HEX));
|
|
|
|
page.concat(":");
|
|
|
|
page.concat(String(mac[1], HEX));
|
|
|
|
page.concat(":");
|
|
|
|
page.concat(String(mac[2], HEX));
|
|
|
|
page.concat(":");
|
|
|
|
page.concat(String(mac[3], HEX));
|
|
|
|
page.concat(":");
|
|
|
|
page.concat(String(mac[4], HEX));
|
|
|
|
page.concat(":");
|
|
|
|
page.concat(String(mac[5], HEX));
|
|
|
|
yield();
|
|
|
|
|
|
|
|
page.concat("\nIP ADDRESS.: "); page.concat(ipToString(WiFi.localIP()));
|
|
|
|
page.concat("\nGATEWAY....: "); page.concat(ipToString(WiFi.gatewayIP()));
|
|
|
|
yield();
|
|
|
|
|
|
|
|
page.concat("\nSUBNET MASK: "); page.concat(ipToString(WiFi.subnetMask()));
|
|
|
|
yield();
|
|
|
|
page.concat("\nSERVER PORT: "); page.concat(tcpServerPort);
|
|
|
|
page.concat("\nCALL STATUS: ");
|
|
|
|
if (callConnected) {
|
|
|
|
page.concat("CONNECTED TO ");
|
|
|
|
page.concat(ipToString(tcpClient.remoteIP()));
|
|
|
|
page.concat("\nCALL LENGTH: "); page.concat(connectTimeString()); yield();
|
|
|
|
} else {
|
|
|
|
page.concat("NOT CONNECTED");
|
|
|
|
}
|
|
|
|
page.concat("\n");
|
|
|
|
webServer.send(200, "text/plain", page);
|
|
|
|
delay(100);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Turn on the LED and store the time, so the LED will be shortly after turned off
|
|
|
|
*/
|
|
|
|
void led_on()
|
|
|
|
{
|
|
|
|
digitalWrite(LED2, !digitalRead(LED2));
|
|
|
|
ledTime = millis();
|
|
|
|
}
|
|
|
|
|
|
|
|
void answerCall() {
|
|
|
|
tcpClient = tcpServer.available();
|
|
|
|
tcpClient.setNoDelay(true); // try to disable naggle
|
|
|
|
//tcpServer.stop();
|
|
|
|
sendResult(R_CONNECT);
|
|
|
|
connectTime = millis();
|
|
|
|
cmdMode = false;
|
|
|
|
callConnected = true;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
Serial.flush();
|
|
|
|
}
|
|
|
|
|
|
|
|
void handleIncomingConnection() {
|
|
|
|
if (callConnected == 1 || (autoAnswer == false && ringCount > 3)) {
|
|
|
|
// We're in a call already or didn't answer the call after three rings
|
|
|
|
// We didn't answer the call. Notify our party we're busy and disconnect
|
|
|
|
ringCount = lastRingMs = 0;
|
|
|
|
WiFiClient anotherClient = tcpServer.available();
|
|
|
|
anotherClient.print(busyMsg);
|
|
|
|
anotherClient.print("\r\n");
|
|
|
|
anotherClient.print("CURRENT CALL LENGTH: ");
|
|
|
|
anotherClient.print(connectTimeString());
|
|
|
|
anotherClient.print("\r\n");
|
|
|
|
anotherClient.print("\r\n");
|
|
|
|
anotherClient.flush();
|
|
|
|
anotherClient.stop();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (autoAnswer == false) {
|
|
|
|
if (millis() - lastRingMs > 6000 || lastRingMs == 0) {
|
|
|
|
lastRingMs = millis();
|
|
|
|
sendResult(R_RING);
|
|
|
|
ringCount++;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (autoAnswer == true) {
|
|
|
|
WiFiClient tempClient = tcpServer.available(); // this is the key to keeping the connection open
|
|
|
|
tcpClient = tempClient; // hand over the new connection to the global client
|
|
|
|
tempClient.stop(); // stop the temporary one
|
|
|
|
sendString(String("RING ") + ipToString(tcpClient.remoteIP()));
|
|
|
|
delay(1000);
|
|
|
|
sendResult(R_CONNECT);
|
|
|
|
connectTime = millis();
|
|
|
|
cmdMode = false;
|
|
|
|
tcpClient.flush();
|
|
|
|
callConnected = true;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void dialOut(String upCmd) {
|
|
|
|
// Can't place a call while in a call
|
|
|
|
if (callConnected) {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
String host, port;
|
|
|
|
int portIndex;
|
|
|
|
// Dialing a stored number
|
|
|
|
if (upCmd.indexOf("ATDS") == 0) {
|
|
|
|
byte speedNum = upCmd.substring(4, 5).toInt();
|
|
|
|
portIndex = speedDials[speedNum].indexOf(':');
|
|
|
|
if (portIndex != -1) {
|
|
|
|
host = speedDials[speedNum].substring(0, portIndex);
|
|
|
|
port = speedDials[speedNum].substring(portIndex + 1);
|
|
|
|
} else {
|
|
|
|
port = "23";
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// Dialing an ad-hoc number
|
|
|
|
int portIndex = cmd.indexOf(":");
|
|
|
|
if (portIndex != -1)
|
|
|
|
{
|
|
|
|
host = cmd.substring(4, portIndex);
|
|
|
|
port = cmd.substring(portIndex + 1, cmd.length());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
host = cmd.substring(4, cmd.length());
|
|
|
|
port = "23"; // Telnet default
|
|
|
|
}
|
|
|
|
}
|
|
|
|
host.trim(); // remove leading or trailing spaces
|
|
|
|
port.trim();
|
|
|
|
Serial.print("DIALING "); Serial.print(host); Serial.print(":"); Serial.println(port);
|
|
|
|
char *hostChr = new char[host.length() + 1];
|
|
|
|
host.toCharArray(hostChr, host.length() + 1);
|
|
|
|
int portInt = port.toInt();
|
|
|
|
tcpClient.setNoDelay(true); // Try to disable naggle
|
|
|
|
if (tcpClient.connect(hostChr, portInt))
|
|
|
|
{
|
|
|
|
tcpClient.setNoDelay(true); // Try to disable naggle
|
|
|
|
sendResult(R_CONNECT);
|
|
|
|
connectTime = millis();
|
|
|
|
cmdMode = false;
|
|
|
|
Serial.flush();
|
|
|
|
callConnected = true;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
//if (tcpServerPort > 0) tcpServer.stop();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sendResult(R_NOANSWER);
|
|
|
|
callConnected = false;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
}
|
|
|
|
delete hostChr;
|
|
|
|
}
|
|
|
|
|
|
|
|
void waitForSpace() {
|
|
|
|
Serial.print("PRESS SPACE");
|
|
|
|
char c = 0;
|
|
|
|
while (c != 0x20) {
|
|
|
|
if (Serial.available() > 0) {
|
|
|
|
c = Serial.read();
|
|
|
|
if (petTranslate == true){
|
|
|
|
if (c > 127) c-= 128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Serial.print("\r");
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Perform a command given in command mode
|
|
|
|
*/
|
|
|
|
void command()
|
|
|
|
{
|
|
|
|
cmd.trim();
|
|
|
|
if (cmd == "") return;
|
|
|
|
Serial.println();
|
|
|
|
String upCmd = cmd;
|
|
|
|
upCmd.toUpperCase();
|
|
|
|
|
|
|
|
/**** Just AT ****/
|
|
|
|
if (upCmd == "AT") sendResult(R_OK);
|
|
|
|
|
|
|
|
/**** Dial to host ****/
|
|
|
|
else if ((upCmd.indexOf("ATDT") == 0) || (upCmd.indexOf("ATDP") == 0) || (upCmd.indexOf("ATDI") == 0) || (upCmd.indexOf("ATDS") == 0))
|
|
|
|
{
|
|
|
|
dialOut(upCmd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Change telnet mode ****/
|
|
|
|
else if (upCmd == "ATNET0")
|
|
|
|
{
|
|
|
|
telnet = false;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd == "ATNET1")
|
|
|
|
{
|
|
|
|
telnet = true;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
else if (upCmd == "ATNET?") {
|
|
|
|
Serial.println(String(telnet));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Answer to incoming connection ****/
|
|
|
|
else if ((upCmd == "ATA") && tcpServer.hasClient()) {
|
|
|
|
answerCall();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display Help ****/
|
|
|
|
else if (upCmd == "AT?" || upCmd == "ATHELP") {
|
|
|
|
displayHelp();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Reset, reload settings from EEPROM ****/
|
|
|
|
else if (upCmd == "ATZ") {
|
|
|
|
readSettings();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Disconnect WiFi ****/
|
|
|
|
else if (upCmd == "ATC0") {
|
|
|
|
disconnectWiFi();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Connect WiFi ****/
|
|
|
|
else if (upCmd == "ATC1") {
|
|
|
|
connectWiFi();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Control local echo in command mode ****/
|
|
|
|
else if (upCmd.indexOf("ATE") == 0) {
|
|
|
|
if (upCmd.substring(3, 4) == "?") {
|
|
|
|
sendString(String(echo));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(3, 4) == "0") {
|
|
|
|
echo = 0;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(3, 4) == "1") {
|
|
|
|
echo = 1;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Control verbosity ****/
|
|
|
|
else if (upCmd.indexOf("ATV") == 0) {
|
|
|
|
if (upCmd.substring(3, 4) == "?") {
|
|
|
|
sendString(String(verboseResults));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(3, 4) == "0") {
|
|
|
|
verboseResults = 0;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(3, 4) == "1") {
|
|
|
|
verboseResults = 1;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Control pin polarity of CTS, RTS, DCD ****/
|
|
|
|
else if (upCmd.indexOf("AT&P") == 0) {
|
|
|
|
if (upCmd.substring(4, 5) == "?") {
|
|
|
|
sendString(String(pinPolarity));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(4, 5) == "0") {
|
|
|
|
pinPolarity = P_INVERTED;
|
|
|
|
sendResult(R_OK);
|
|
|
|
setCarrier(callConnected);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(4, 5) == "1") {
|
|
|
|
pinPolarity = P_NORMAL;
|
|
|
|
sendResult(R_OK);
|
|
|
|
setCarrier(callConnected);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Control Flow Control ****/
|
|
|
|
else if (upCmd.indexOf("AT&K") == 0) {
|
|
|
|
if (upCmd.substring(4, 5) == "?") {
|
|
|
|
sendString(String(flowControl));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(4, 5) == "0") {
|
|
|
|
flowControl = 0;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(4, 5) == "1") {
|
|
|
|
flowControl = 1;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else if (upCmd.substring(4, 5) == "2") {
|
|
|
|
flowControl = 2;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set current baud rate ****/
|
|
|
|
else if (upCmd.indexOf("AT$SB=") == 0) {
|
|
|
|
setBaudRate(upCmd.substring(6).toInt());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display current baud rate ****/
|
|
|
|
else if (upCmd.indexOf("AT$SB?") == 0) {
|
|
|
|
sendString(String(bauds[serialspeed]));;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set busy message ****/
|
|
|
|
else if (upCmd.indexOf("AT$BM=") == 0) {
|
|
|
|
busyMsg = cmd.substring(6);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display busy message ****/
|
|
|
|
else if (upCmd.indexOf("AT$BM?") == 0) {
|
|
|
|
sendString(busyMsg);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display Network settings ****/
|
|
|
|
else if (upCmd == "ATI") {
|
|
|
|
displayNetworkStatus();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display profile settings ****/
|
|
|
|
else if (upCmd == "AT&V") {
|
|
|
|
displayCurrentSettings();
|
|
|
|
waitForSpace();
|
|
|
|
displayStoredSettings();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Save (write) current settings to EEPROM ****/
|
|
|
|
else if (upCmd == "AT&W") {
|
|
|
|
writeSettings();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set or display a speed dial number ****/
|
|
|
|
else if (upCmd.indexOf("AT&Z") == 0) {
|
|
|
|
byte speedNum = upCmd.substring(4, 5).toInt();
|
|
|
|
if (speedNum >= 0 && speedNum <= 9) {
|
|
|
|
if (upCmd.substring(5, 6) == "=") {
|
|
|
|
String speedDial = cmd;
|
|
|
|
storeSpeedDial(speedNum, speedDial.substring(6));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
if (upCmd.substring(5, 6) == "?") {
|
|
|
|
sendString(speedDials[speedNum]);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set WiFi SSID ****/
|
|
|
|
else if (upCmd.indexOf("AT$SSID=") == 0) {
|
|
|
|
ssid = cmd.substring(8);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display WiFi SSID ****/
|
|
|
|
else if (upCmd == "AT$SSID?") {
|
|
|
|
sendString(ssid);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set WiFi Password ****/
|
|
|
|
else if (upCmd.indexOf("AT$PASS=") == 0) {
|
|
|
|
password = cmd.substring(8);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display WiFi Password ****/
|
|
|
|
else if (upCmd == "AT$PASS?") {
|
|
|
|
sendString(password);
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Reset EEPROM and current settings to factory defaults ****/
|
|
|
|
else if (upCmd == "AT&F") {
|
|
|
|
defaultEEPROM();
|
|
|
|
readSettings();
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set auto answer off ****/
|
|
|
|
else if (upCmd == "ATS0=0") {
|
|
|
|
autoAnswer = false;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set auto answer on ****/
|
|
|
|
else if (upCmd == "ATS0=1") {
|
|
|
|
autoAnswer = true;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display auto answer setting ****/
|
|
|
|
else if (upCmd == "ATS0?") {
|
|
|
|
sendString(String(autoAnswer));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set PET MCTerm Translate On ****/
|
|
|
|
else if (upCmd == "ATPET=1") {
|
|
|
|
petTranslate = true;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set PET MCTerm Translate Off ****/
|
|
|
|
else if (upCmd == "ATPET=0") {
|
|
|
|
petTranslate = false;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display PET MCTerm Translate Setting ****/
|
|
|
|
else if (upCmd == "ATPET?") {
|
|
|
|
sendString(String(petTranslate));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set HEX Translate On ****/
|
|
|
|
else if (upCmd == "ATHEX=1") {
|
|
|
|
hex = true;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set HEX Translate Off ****/
|
|
|
|
else if (upCmd == "ATHEX=0") {
|
|
|
|
hex = false;
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Hang up a call ****/
|
|
|
|
else if (upCmd.indexOf("ATH") == 0) {
|
|
|
|
hangUp();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Hang up a call ****/
|
|
|
|
else if (upCmd.indexOf("AT$RB") == 0) {
|
|
|
|
sendResult(R_OK);
|
|
|
|
Serial.flush();
|
|
|
|
delay(500);
|
|
|
|
ESP.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Exit modem command mode, go online ****/
|
|
|
|
else if (upCmd == "ATO") {
|
|
|
|
if (callConnected == 1) {
|
|
|
|
sendResult(R_CONNECT);
|
|
|
|
cmdMode = false;
|
|
|
|
} else {
|
|
|
|
sendResult(R_ERROR);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Set incoming TCP server port ****/
|
|
|
|
else if (upCmd.indexOf("AT$SP=") == 0) {
|
|
|
|
tcpServerPort = upCmd.substring(6).toInt();
|
|
|
|
sendString("CHANGES REQUIRES NV SAVE (AT&W) AND RESTART");
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Display icoming TCP server port ****/
|
|
|
|
else if (upCmd == "AT$SP?") {
|
|
|
|
sendString(String(tcpServerPort));
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** See my IP address ****/
|
|
|
|
else if (upCmd == "ATIP?")
|
|
|
|
{
|
|
|
|
Serial.println(WiFi.localIP());
|
|
|
|
sendResult(R_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** HTTP GET request ****/
|
|
|
|
else if (upCmd.indexOf("ATGET") == 0)
|
|
|
|
{
|
|
|
|
// From the URL, aquire required variables
|
|
|
|
// (12 = "ATGEThttp://")
|
|
|
|
int portIndex = cmd.indexOf(":", 12); // Index where port number might begin
|
|
|
|
int pathIndex = cmd.indexOf("/", 12); // Index first host name and possible port ends and path begins
|
|
|
|
int port;
|
|
|
|
String path, host;
|
|
|
|
if (pathIndex < 0)
|
|
|
|
{
|
|
|
|
pathIndex = cmd.length();
|
|
|
|
}
|
|
|
|
if (portIndex < 0)
|
|
|
|
{
|
|
|
|
port = 80;
|
|
|
|
portIndex = pathIndex;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
port = cmd.substring(portIndex + 1, pathIndex).toInt();
|
|
|
|
}
|
|
|
|
host = cmd.substring(12, portIndex);
|
|
|
|
path = cmd.substring(pathIndex, cmd.length());
|
|
|
|
if (path == "") path = "/";
|
|
|
|
char *hostChr = new char[host.length() + 1];
|
|
|
|
host.toCharArray(hostChr, host.length() + 1);
|
|
|
|
|
|
|
|
// Establish connection
|
|
|
|
if (!tcpClient.connect(hostChr, port))
|
|
|
|
{
|
|
|
|
sendResult(R_NOCARRIER);
|
|
|
|
connectTime = 0;
|
|
|
|
callConnected = false;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sendResult(R_CONNECT);
|
|
|
|
connectTime = millis();
|
|
|
|
cmdMode = false;
|
|
|
|
callConnected = true;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
|
|
|
|
// Send a HTTP request before continuing the connection as usual
|
|
|
|
String request = "GET ";
|
|
|
|
request += path;
|
|
|
|
request += " HTTP/1.1\r\nHost: ";
|
|
|
|
request += host;
|
|
|
|
request += "\r\nConnection: close\r\n\r\n";
|
|
|
|
tcpClient.print(request);
|
|
|
|
}
|
|
|
|
delete hostChr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** Unknown command ****/
|
|
|
|
else sendResult(R_ERROR);
|
|
|
|
|
|
|
|
cmd = "";
|
|
|
|
}
|
|
|
|
|
|
|
|
// RTS/CTS protocol is a method of handshaking which uses one wire in each direction to allow each
|
|
|
|
// device to indicate to the other whether or not it is ready to receive data at any given moment.
|
|
|
|
// One device sends on RTS and listens on CTS; the other does the reverse. A device should drive
|
|
|
|
// its handshake-output wire low when it is ready to receive data, and high when it is not. A device
|
|
|
|
// that wishes to send data should not start sending any bytes while the handshake-input wire is low;
|
|
|
|
// if it sees the handshake wire go high, it should finish transmitting the current byte and then wait
|
|
|
|
// for the handshake wire to go low before transmitting any more.
|
|
|
|
// http://electronics.stackexchange.com/questions/38022/what-is-rts-and-cts-flow-control
|
|
|
|
void handleFlowControl() {
|
|
|
|
if (flowControl == F_NONE) return;
|
|
|
|
if (flowControl == F_HARDWARE) {
|
|
|
|
if (digitalRead(CTS_PIN) == pinPolarity) txPaused = true;
|
|
|
|
else txPaused = false;
|
|
|
|
}
|
|
|
|
if (flowControl == F_SOFTWARE) {
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
Arduino main loop function
|
|
|
|
*/
|
|
|
|
void loop()
|
|
|
|
{
|
|
|
|
// Check flow control
|
|
|
|
handleFlowControl();
|
|
|
|
|
|
|
|
// Service the Web server
|
|
|
|
webServer.handleClient();
|
|
|
|
|
|
|
|
// Check to see if user is requesting rate change to 300 baud
|
|
|
|
checkButton();
|
|
|
|
|
|
|
|
// New unanswered incoming connection on server listen socket
|
|
|
|
if (tcpServer.hasClient()) {
|
|
|
|
handleIncomingConnection();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**** AT command mode ****/
|
|
|
|
if (cmdMode == true)
|
|
|
|
{
|
|
|
|
|
|
|
|
// In command mode - don't exchange with TCP but gather characters to a string
|
|
|
|
if (Serial.available())
|
|
|
|
{
|
|
|
|
char chr = Serial.read();
|
|
|
|
|
|
|
|
if (petTranslate == true) {
|
|
|
|
// Fix PET MCTerm 1.26C Pet->ASCII encoding to actual ASCII
|
|
|
|
if (chr > 127) chr-= 128;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
// Convert uppercase PETSCII to lowercase ASCII (C64) in command mode only
|
|
|
|
if ((chr >= 193) && (chr <= 218)) chr-= 96;
|
|
|
|
|
|
|
|
// Return, enter, new line, carriage return.. anything goes to end the command
|
|
|
|
if ((chr == '\n') || (chr == '\r'))
|
|
|
|
{
|
|
|
|
command();
|
|
|
|
}
|
|
|
|
// Backspace or delete deletes previous character
|
|
|
|
else if ((chr == 8) || (chr == 127) || (chr == 20))
|
|
|
|
{
|
|
|
|
cmd.remove(cmd.length() - 1);
|
|
|
|
if (echo == true) {
|
|
|
|
Serial.write(chr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (cmd.length() < MAX_CMD_LENGTH) cmd.concat(chr);
|
|
|
|
if (echo == true) {
|
|
|
|
Serial.write(chr);
|
|
|
|
}
|
|
|
|
if (hex) {
|
|
|
|
Serial.print(chr, HEX);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/**** Connected mode ****/
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Transmit from terminal to TCP
|
|
|
|
if (Serial.available())
|
|
|
|
{
|
|
|
|
led_on();
|
|
|
|
|
|
|
|
// In telnet in worst case we have to escape every byte
|
|
|
|
// so leave half of the buffer always free
|
|
|
|
int max_buf_size;
|
|
|
|
if (telnet == true)
|
|
|
|
max_buf_size = TX_BUF_SIZE / 2;
|
|
|
|
else
|
|
|
|
max_buf_size = TX_BUF_SIZE;
|
|
|
|
|
|
|
|
// Read from serial, the amount available up to
|
|
|
|
// maximum size of the buffer
|
|
|
|
size_t len = std::min(Serial.available(), max_buf_size);
|
|
|
|
Serial.readBytes(&txBuf[0], len);
|
|
|
|
|
|
|
|
// Enter command mode with "+++" sequence
|
|
|
|
for (int i = 0; i < (int)len; i++)
|
|
|
|
{
|
|
|
|
if (txBuf[i] == '+') plusCount++; else plusCount = 0;
|
|
|
|
if (plusCount >= 3)
|
|
|
|
{
|
|
|
|
plusTime = millis();
|
|
|
|
}
|
|
|
|
if (txBuf[i] != '+')
|
|
|
|
{
|
|
|
|
plusCount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Double (escape) every 0xff for telnet, shifting the following bytes
|
|
|
|
// towards the end of the buffer from that point
|
|
|
|
if (telnet == true)
|
|
|
|
{
|
|
|
|
for (int i = len - 1; i >= 0; i--)
|
|
|
|
{
|
|
|
|
if (txBuf[i] == 0xff)
|
|
|
|
{
|
|
|
|
for (int j = TX_BUF_SIZE - 1; j > i; j--)
|
|
|
|
{
|
|
|
|
txBuf[j] = txBuf[j - 1];
|
|
|
|
}
|
|
|
|
len++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Fix PET MCTerm 1.26C Pet->ASCII encoding to actual ASCII
|
|
|
|
if (petTranslate == true) {
|
|
|
|
for (int i = len - 1; i >= 0; i--) {
|
|
|
|
if (txBuf[i] > 127) txBuf[i]-= 128;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Write the buffer to TCP finally
|
|
|
|
tcpClient.write(&txBuf[0], len);
|
|
|
|
yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Transmit from TCP to terminal
|
|
|
|
while (tcpClient.available() && txPaused == false)
|
|
|
|
{
|
|
|
|
led_on();
|
|
|
|
uint8_t rxByte = tcpClient.read();
|
|
|
|
|
|
|
|
// Is a telnet control code starting?
|
|
|
|
if ((telnet == true) && (rxByte == 0xff))
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print("<t>");
|
|
|
|
#endif
|
|
|
|
rxByte = tcpClient.read();
|
|
|
|
if (rxByte == 0xff)
|
|
|
|
{
|
|
|
|
// 2 times 0xff is just an escaped real 0xff
|
|
|
|
Serial.write(0xff); Serial.flush();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// rxByte has now the first byte of the actual non-escaped control code
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(rxByte);
|
|
|
|
Serial.print(",");
|
|
|
|
#endif
|
|
|
|
uint8_t cmdByte1 = rxByte;
|
|
|
|
rxByte = tcpClient.read();
|
|
|
|
uint8_t cmdByte2 = rxByte;
|
|
|
|
// rxByte has now the second byte of the actual non-escaped control code
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print(rxByte); Serial.flush();
|
|
|
|
#endif
|
|
|
|
// We are asked to do some option, respond we won't
|
|
|
|
if (cmdByte1 == DO)
|
|
|
|
{
|
|
|
|
tcpClient.write((uint8_t)255); tcpClient.write((uint8_t)WONT); tcpClient.write(cmdByte2);
|
|
|
|
}
|
|
|
|
// Server wants to do any option, allow it
|
|
|
|
else if (cmdByte1 == WILL)
|
|
|
|
{
|
|
|
|
tcpClient.write((uint8_t)255); tcpClient.write((uint8_t)DO); tcpClient.write(cmdByte2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
|
|
Serial.print("</t>");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Non-control codes pass through freely
|
|
|
|
Serial.write(rxByte); yield(); Serial.flush(); yield();
|
|
|
|
}
|
|
|
|
handleFlowControl();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// If we have received "+++" as last bytes from serial port and there
|
|
|
|
// has been over a second without any more bytes
|
|
|
|
if (plusCount >= 3)
|
|
|
|
{
|
|
|
|
if (millis() - plusTime > 1000)
|
|
|
|
{
|
|
|
|
//tcpClient.stop();
|
|
|
|
cmdMode = true;
|
|
|
|
sendResult(R_OK);
|
|
|
|
plusCount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Go to command mode if TCP disconnected and not in command mode
|
|
|
|
if ((!tcpClient.connected()) && (cmdMode == false) && callConnected == true)
|
|
|
|
{
|
|
|
|
cmdMode = true;
|
|
|
|
sendResult(R_NOCARRIER);
|
|
|
|
connectTime = 0;
|
|
|
|
callConnected = false;
|
|
|
|
setCarrier(callConnected);
|
|
|
|
//if (tcpServerPort > 0) tcpServer.begin();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Turn off tx/rx led if it has been lit long enough to be visible
|
|
|
|
if (millis() - ledTime > LED_TIME) digitalWrite(LED2, !digitalRead(LED2)); // toggle LED state
|
|
|
|
}
|