Skip to content

Instantly share code, notes, and snippets.

@NonaSuomy
Created December 31, 2017 19:10
Show Gist options
  • Save NonaSuomy/eaaedb4e99228fbdcae541b71e3fb717 to your computer and use it in GitHub Desktop.
Save NonaSuomy/eaaedb4e99228fbdcae541b71e3fb717 to your computer and use it in GitHub Desktop.
/*
Project: WOOF
Date: 20171228
Hardware
FTDI for Pro Mini
https://www.banggood.com/FT232RL-FTDI-USB-To-TTL-Serial-Converter-Adapter-Module-For-Arduino-p-917226.html?rmmds=search&cur_warehouse=CN
Arduino Pro Mini or Micro
https://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html?rmmds=search&cur_warehouse=CN
https://www.banggood.com/Pro-Micro-5V-16M-Mini-Leonardo-Microcontroller-Development-Board-For-Arduino-p-1077675.html?rmmds=search&cur_warehouse=CN
W5500 Ethernet Network Module
http://wiznetmuseum.com/portfolio-items/w5500-ethernet-network-module-tcpip-interface-51stm32-program/
https://www.banggood.com/W5500-Ethernet-Network-Module-TCPIP-Interface-51STM32-Program-p-982668.html?cur_warehouse=CN
Libraries
ICMPPing
https://github.com/NonaSuomy/Arduino-Ping-W5500
Ethernet2
Use the library manager to get ethernet2 library.
https://github.com/adafruit/Ethernet2
Pinouts
Arduino W5500 Wire Colours
10 SCS Grey
11 MOSI Orange
12 MISO Brown
13 SCLK White
RST RST Purple
5V 5V White
N/C 3.3V N/C
GND GND Black
N/C INT N/C
N/C NC N/C
Tips
Look in the Serial Monitor for your DHCP IP or Static set it.
Connect to IP of Arduino in your web browser example: http://192.168.1.50
Use ' instead of " in the html.
*/
#include <string.h>
#include <EEPROM.h>
#include "EEPROMAnything.h"
#include <SPI.h>
#include <Ethernet2.h>
#include <ICMPPing.h>
IPAddress pingAddr(255, 255, 255, 255); // ip address to ping
// PING_REQUEST_TIMEOUT_MS -- Timeout in ms. between 1 and 65000 or so
// Save values: 1000 to 5000, say.
//#define PING_REQUEST_TIMEOUT_MS 2500
//#ifndef ICMPPING_ASYNCH_ENABLE
//#error "Asynchronous functions only available if ICMPPING_ASYNCH_ENABLE is defined -- see ICMPPing.h"
//#endif
SOCKET pingSocket = 0;
char buffer [256];
ICMPPing ping(pingSocket, (uint16_t)random(0, 255));
#define MINPIN 2 // Pin 0 and 1 are RX/TX.
#define MAXPIN 9 // Stick to digital for now.
#define SHORT 250 // Short keypress, in 'ms'.
#define LONG 4500 // Long keypress, in 'ms'.
#define INPUTLEN 50 // Length of input string we parse.
#define NAMELEN 10 // Length of a host/config name.
#define IPLEN 256 // Length of IP.
#define CONFIGS 7 // Amount of configs to store.
#define PROMPT "\n> "
// Function declarations
void processString();
char * inputstring = (char *) malloc(INPUTLEN+1);
char * isbegin = inputstring;
byte islen = 0;
bool inputdone = false;
struct configdata
{
bool used;
byte resetpin;
byte powerpin;
char name[NAMELEN];
byte pip1;
byte pip2;
byte pip3;
byte pip4;
} config[CONFIGS];
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Physical MAC Address
byte ip[] = { 10, 20, 30, 33 }; // IP Address
byte gateway[] = { 10, 20, 30, 40 }; // Router Gateway
byte subnet[] = { 255, 255, 255, 0 }; // Network Subnet MaskEthernetServer server(80); // Server Port
EthernetServer server(80); // Server Port
String readString;
// Arduino PINS default to 'input' and 'LOW', but set them anyway
// so we can call reset later to revert to defaults if needed.
void setup()
{
for( int i = MINPIN; i <= MAXPIN; i++)
{
pinMode(i, INPUT);
digitalWrite(i, LOW);
}
// Start Ethernet
Ethernet.begin(mac, ip, gateway, subnet); // Static
//Ethernet.begin(mac); // DHCP
server.begin();
// initialize serial communication at 9600 bits per second:
Serial.begin(115200);
Serial.print(F( "WOOF!\n\r" ));
/*
int i = sizeof(config);
Serial.print( "Configuration is " );
Serial.print( i, DEC );
Serial.print( " bytes\n\r\n\r" );
*/
Serial.print(F("Server is at: "));
Serial.println(Ethernet.localIP());
// increase the default time-out, if needed, assuming a bad
// connection or whatever.
ICMPPing::setTimeout(PING_REQUEST_TIMEOUT_MS);
inputstring[0] = '\0'; // Initialize to empty
inputstring[INPUTLEN+1] = '\0'; // Should never be overwritten
Serial.print( PROMPT );
EEPROM_readAnything(0, config);
}
// the loop routine runs over and over again forever:
void loop()
{
// Create a client connection
EthernetClient client = server.available();
if (client) {
while (client.connected()) {
if (client.available()) {
pong(10,13,37,173);
char c = client.read();
//read char by char HTTP request
if (readString.length() < 100) {
//store characters to string
readString += c;
//Serial.print(c);
}
// If HTTP request has ended.
if (c == '\n') {
Serial.println(readString); // Print to serial monitor for debuging.
client.println(F("HTTP/1.1 200 OK")); // Send new page.
client.println(F("Content-Type: text/html"));
client.println();
client.println(F("<HTML>"));
client.println(F("<HEAD>"));
client.println(F("<TITLE>WOOF!</TITLE>"));
client.println(F("</HEAD>"));
client.println(F("<BODY>"));
client.println(F("<H1>Watchdog Overseer Open Farm</H1>"));
// Custom Buttons
client.print(F("Sys0 "));
//client.print("<input type=submit value=ON style=width:100px;height:45px onClick=location.href='/?on2;'>");
//client.print("<input type=submit value=OFF style=width:100px;height:45px onClick=location.href='/?off3;'><br><br>");
client.println(F("<a href=/?p0 >POW</a>"));
client.println(F("<a href=/?r0 >RST</a>"));
client.println(F("<a href=/?f0 >FRC</a><br>"));
client.print(F("Sys1 "));
client.println(F("<a href=/?p1 >POW</a>"));
client.println(F("<a href=/?r1 >RST</a>"));
client.println(F("<a href=/?f1 >FRC</a><br>"));
client.print(F("Sys2 "));
client.println(F("<a href=/?p2 >POW</a>"));
client.println(F("<a href=/?r2 >RST</a>"));
client.println(F("<a href=/?f2 >FRC</a><br>"));
client.print(F("Sys3 "));
client.println(F("<a href=/?p3 >POW</a>"));
client.println(F("<a href=/?r3 >RST</a>"));
client.println(F("<a href=/?f3 >FRC</a><br>"));
client.print(F("Sys All "));
//client.print("&nbsp;<input type=submit value='ALL OFF' style=width:100px;height:45px onClick=location.href='/?off3579;'>");
client.println(F("<a href=/?pall >POW All</a><br>"));
client.println(F("</BODY>"));
client.println(F("</HTML>"));
delay(1);
// Stopping client
client.stop();
// Change pin states from web url.
if(readString.indexOf("p0") >0) // Checks for p1
{
do_power( 0 );
//digitalWrite(2, HIGH); // Set pin 2 high
//Serial.println(F("P2P"));
}
else if(readString.indexOf("r0") >0) // Checks for 3
{
do_reset( 0 );
//digitalWrite(2, LOW); // Set pin 2 low
//Serial.println("P2R");
}
else if(readString.indexOf("f0") >0) // Checks for 3
{
do_force( 0 );
//digitalWrite(2, LOW); // Set pin 2 low
//Serial.println("P2R");
}
else if(readString.indexOf("p1") >0) // Checks for 4
{
do_power( 1 );
//digitalWrite(4, HIGH); // Set pin 4 high
//Serial.println("Led 4 On");
}
else if(readString.indexOf("r1") >0) // Checks for 5
{
do_reset( 1 );
//digitalWrite(4, LOW); // Set pin 4 low
//Serial.println("Led 4 Off");
}
else if(readString.indexOf("f1") >0) // Checks for 3
{
do_force( 1 );
//digitalWrite(2, LOW); // Set pin 2 low
//Serial.println("P2R");
}
else if(readString.indexOf("p2") >0) // Checks for 6
{
do_power( 2 );
//digitalWrite(6, HIGH); // Set pin 6 high
//Serial.println("Led 6 On");
}
else if(readString.indexOf("r2") >0) // Checks for 7
{
do_reset( 2 );
//digitalWrite(6, LOW); // Set pin 6 low
//Serial.println("Led 6 Off");
}
else if(readString.indexOf("f2") >0) // Checks for 3
{
do_force( 2 );
//digitalWrite(2, LOW); // Set pin 2 low
//Serial.println("P2R");
}
else if(readString.indexOf("p3") >0) // Checks for 8
{
do_power( 3 );
//digitalWrite(8, HIGH); // Set pin 8 high
//Serial.println("Led 8 On");
}
else if(readString.indexOf("r3") >0) // Checks for 9
{
do_reset( 3 );
//digitalWrite(8, LOW); // Set pin 8 low
//Serial.println("Led 8 Off");
}
else if(readString.indexOf("f3") >0) // Checks for 3
{
do_force( 3 );
//digitalWrite(2, LOW); // Set pin 2 low
//Serial.println("P2R");
}
else if(readString.indexOf("pall") >0) // Checks for 9
{
do_power( 0 );
do_power( 1 );
do_power( 2 );
do_power( 3 );
//digitalWrite(8, LOW); // Set pin 8 low
//Serial.println("Led 8 Off");
}
//clearing string for next read
readString="";
}
}
}
}
// If we have a input to process, do so
if (inputdone) {
processString();
// clear the string:
inputstring[0] = '\0';
islen=0;
inputdone = false;
Serial.print( PROMPT );
}
if( Serial.available() > 0)
{
char input = Serial.read();
Serial.print(input);
// Newline / Carriage return close the input
if( ( input == '\n' ) || ( input == '\r' ) )
{
// Close input with \0
inputstring[islen++] = '\0';
inputdone=true;
Serial.print(F( "\n\r\n\r" ));
}
else if( input == 127 )
{
// Backspace
if ( islen >= 1 )
{
Serial.print(F( "\b \b" ));
inputstring[islen--] = '\0';
}
}
else if( ( input >= ' ' ) && ( input <= 'z' ) )
{
// Add valid character, increment islen
inputstring[islen++] = input;
}
else
{
Serial.print(F( "Illegal character: '" ));
Serial.print( input, HEX );
Serial.print(F( "'\n" ));
}
// Have we reached max length, also close input and flush remainder
if( islen >= INPUTLEN )
{
inputstring[islen] = '\0';
inputdone=true;
// Flush remaining characters in input to /dev/zero
while( Serial.available() > 0 )
{
// This doesn't seem to flush all input
Serial.read();
}
}
}
}
// Toggle pin state.
void toggle_pin( byte pin, int ms )
{
pinMode( pin, OUTPUT );
digitalWrite(pin, LOW);
delay( ms );
pinMode(pin, INPUT);
digitalWrite(pin, LOW);
}
// Send reset signal to pin.
void do_reset( byte cnum )
{
if( config[cnum].used )
{
Serial.print(F( "Sending reset signal to pin: " ));
Serial.println( config[cnum].resetpin );
toggle_pin( config[cnum].resetpin, SHORT );
}
else
{
Serial.print(F( "Config invalid" ));
}
}
// Trigger Computer Power Button.
void do_power( byte cnum )
{
if( config[cnum].used )
{
Serial.print(F( "Sending power signal to pin: " ));
Serial.println( config[cnum].powerpin );
toggle_pin( config[cnum].powerpin, SHORT );
}
else
{
Serial.print(F( "Config invalid" ));
}
}
void do_force( byte cnum )
{
if( config[cnum].used )
{
Serial.print(F( "Sending long power signal to pin: " ));
Serial.println( config[cnum].powerpin );
toggle_pin( config[cnum].powerpin, LONG );
}
else
{
Serial.print(F( "Config invalid" ));
}
}
void do_state( byte cnum )
{
if( config[cnum].used )
{
bool power, state;
power = digitalRead( config[cnum].powerpin );
state = digitalRead( config[cnum].resetpin );
Serial.print(F( "System " ));
Serial.print( config[cnum].name );
Serial.print(F( " has " ));
if ( ! power )
{
Serial.print(F( "NO " ));
}
Serial.print(F( "ATX power." ));
if ( state )
{
Serial.println(F( " It seems to be powered on." ));
}
else
{
Serial.println(F( " It seems to be off." ));
}
}
else
{
Serial.print(F( "Config invalid" ));
}
}
void do_load()
{
EEPROM_readAnything(0, config);
}
void do_save()
{
EEPROM_writeAnything(0, config);
}
void do_erase( byte confignum )
{
config[confignum].used = false;
config[confignum].resetpin = 255;
config[confignum].powerpin = 255;
strncpy( config[confignum].name, "unused", NAMELEN );
config[confignum].pip1 = 255;
config[confignum].pip2 = 255;
config[confignum].pip3 = 255;
config[confignum].pip4 = 255;
}
void do_dump()
{
Serial.print(F( "\rConfig\n\r" ));
for( byte i = 0; i < CONFIGS; i++ )
{
Serial.print(F( "Config: " ));
Serial.print( i );
Serial.print(F( " Data: " ));
Serial.print( config[i].used );
Serial.print(F( " / " ));
Serial.print( config[i].resetpin );
Serial.print(F( " / " ));
Serial.print( config[i].powerpin );
Serial.print(F( " / " ));
Serial.print( config[i].name );
Serial.print(F( " / " ));
Serial.print( config[i].pip1 );
Serial.print(F( "." ));
Serial.print( config[i].pip2 );
Serial.print(F( "." ));
Serial.print( config[i].pip3 );
Serial.print(F( "." ));
Serial.println( config[i].pip4 );
}
}
void do_wipe()
{
for( byte i = 0; i < CONFIGS; i++ )
{
do_erase( i );
}
do_save();
}
void do_help()
{
Serial.print(F( "Help: \n\r\
config Edit configuration\n\r\
config [0-7] resetpin pwrpin name 192 168 1 100\n\r\
reset # Toggle reset switch on config #\n\r\
power # Toggle power switch on config #\n\r\
force # Long-Press power switch on pc number #\n\r\
erase # Erase config number #\n\r\
state Check power state\n\r\
dump Dump configuration to serial\n\r\
save Save configuration to EEPROM\n\r\
load Load configuration from EEPROM\n\r\
wipe Wipe onfiguration and update EEPROM\n\r\
\n\r\n\r" ));
}
bool do_config( byte cnum, byte rspin, byte ppin, char * name, byte pipl1, byte pipl2, byte pipl3, byte pipl4)
{
byte namelen = strnlen( name, NAMELEN +2 );
if( ( cnum >= 0 ) && ( cnum < CONFIGS ) && ( rspin != ppin ) &&
( rspin >= MINPIN ) && ( rspin <= MAXPIN ) &&
( ppin >= MINPIN ) && ( ppin <= MAXPIN ) &&
( namelen < NAMELEN ) && ( pipl1 < IPLEN ) &&
( pipl2 < IPLEN ) && ( pipl3 < IPLEN ) &&
( pipl4 < IPLEN ) )
{
Serial.print(F( "Do_CONFIG\n\r" ));
config[cnum].used = true;
config[cnum].resetpin = rspin;
config[cnum].powerpin = ppin;
strncpy( config[cnum].name, name, NAMELEN );
config[cnum].pip1 = pipl1;
config[cnum].pip2 = pipl2;
config[cnum].pip3 = pipl3;
config[cnum].pip4 = pipl4;
return true;
}
else
{
Serial.print(F( "Illegal config. Try: config 0 3 2 Sys0 192 168 1 100\n\r" ));
return false;
}
};
void pong(byte ip0, byte ip1, byte ip2, byte ip3)
{
pingAddr[0] = ip0;
pingAddr[1] = ip1;
pingAddr[2] = ip2;
pingAddr[3] = ip3;
Serial.print(ip0);
Serial.print(".");
Serial.print(ip1);
Serial.print(".");
Serial.print(ip2);
Serial.print(".");
Serial.println(ip3);
ICMPEchoReply echoReply = ping(pingAddr, 4);
if (echoReply.status == SUCCESS)
{
sprintf(buffer,
"Reply[%d] from: %d.%d.%d.%d: bytes=%d time=%ldms TTL=%d",
echoReply.data.seq,
echoReply.addr[0],
echoReply.addr[1],
echoReply.addr[2],
echoReply.addr[3],
REQ_DATASIZE,
millis() - echoReply.data.time,
echoReply.ttl);
}
else
{
sprintf(buffer, "Echo request failed; %d", echoReply.status);
}
Serial.println(buffer);
delay(500);
}
void processString()
{
char *cmd, *save;
cmd = strtok_r(inputstring," ",&save);
//Serial.print(cmd);
// Simple commands without arguments
if( ( strncmp( cmd, "help", 4 ) == 0 ) )
{
do_help();
}
else if( ( strncmp( cmd, "save", 4 ) == 0 ) )
{
do_save();
}
else if( ( strncmp( cmd, "load", 4 ) == 0 ) )
{
do_load();
}
else if( ( strncmp( cmd, "dump", 4 ) == 0 ) )
{
do_dump();
}
else if( ( strncmp( cmd, "wipe", 4 ) == 0 ) )
{
do_wipe();
}
else
{
// Commands with at least 1 argument
char * confignum;
byte cnum;
confignum = strtok_r( NULL, " ", &save );
cnum = (byte) atoi(confignum);
if( ! ( cnum >= 0 ) && ( cnum < CONFIGS ) )
{
Serial.println(F( "Invalid config number\n\r" ));
}
else
{
if( ( strncmp( cmd, "reset", 5 ) == 0 ) )
{
//Serial.println( cnum );
do_reset( cnum );
}
else if( ( strncmp( cmd, "power", 5 ) == 0 ) )
{
do_power( cnum );
}
else if( ( strncmp( cmd, "force", 5 ) == 0 ) )
{
do_force( cnum );
}
else if( ( strncmp( cmd, "erase", 5 ) == 0 ) )
{
do_erase( cnum );
}
else if( ( strncmp( cmd, "state", 5 ) == 0 ) )
{
do_state( cnum );
}
// config 0 3 2 Sys0 10 13 37 173
// config 1 5 4 Sys1 10 13 37 173
// config 2 7 6 Sys2 10 13 37 173
// config 3 9 8 Sys3 10 13 37 173
// config 0 3 2 Sys0 192 168 1 100
// config 1 5 4 Sys1 192 168 1 101
// config 2 7 6 Sys2 192 168 1 102
// config 3 9 8 Sys3 192 168 1 103
else if( ( strncmp( cmd, "config", 6 ) == 0 ) )
{
char *resetpin, *pwrpin, *name, *pips0, *pips1, *pips2, *pips3;
resetpin = strtok_r( NULL, " ", &save );
pwrpin = strtok_r( NULL, " ", &save );
name = strtok_r( NULL, " ", &save );
pips0 = strtok_r( NULL, " ", &save );
pips1 = strtok_r( NULL, " ", &save );
pips2 = strtok_r( NULL, " ", &save );
pips3 = strtok_r( NULL, " ", &save );
if ( resetpin && pwrpin && name && pips0 && pips1 && pips2 && pips3 )
{
byte rspin, ppin, pip0, pip1, pip2, pip3;
rspin = atoi( resetpin );
ppin = atoi( pwrpin );
pip0 = atoi( pips0 );
pip1 = atoi( pips1 );
pip2 = atoi( pips2 );
pip3 = atoi( pips3 );
do_config( cnum, rspin, ppin, name, pip0, pip1, pip2, pip3);
}
else
{
Serial.print(F( "ERROR: Please specify configuration number, resetpin, pwrpin, name, 192 168 1 100\n\r\n\r" ));
}
}
else
{
Serial.print(F( "Unknown command: " ));
Serial.print( cmd );
Serial.print(F( "\n\r\n\r" ));
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment