Naos v1.x
Node Assassin :: Naos v1.x |
#include <Ethernet.h> // Arduino's enthernet library.
#include <ctype.h> // Library for testing and character manipulation.
#include <stdint.h> // Library for standard integer types (guarantees the size of an int).
// 00:X is a request for info where 'X' is the requested data. Currently '0' is only data type and returns the current state of all nodes.
// [01-99]:[0-1] Sends a command to set the state of node [01-99] to on [:1] or off [:0].
// MAC Address; Array of six bytes.
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xEF };
// Arduino IP, netmask and gateway.
byte ip[] = { 192, 168, 111, 66 };
// Netmask defaults to 255.255.255.0.
byte nm[] = { 255, 255, 255, 0 };
// Default gateway defaults to IP with the last octal set to 1.
byte dg[] = { 192, 168, 1, 1 };
// Laptop's IP address that I test connecting to.
byte remote[] = { 192, 168, 1, 154 };
// This is the port that I will listen on.
#define port 238
// Setup the server.
Server server = Server(port);
// My function prototypes.
void printError(char reading[]);
// Setup my digital out pins.
#define maxnode 5
#define firstnode 2
// Setup
void setup()
{
// Setup the IP info.
Ethernet.begin(mac, ip, dg, nm);
// Print what comes in over telnet.
Serial.begin(9600);
Serial.println("Node Assassin: 'Ariel' now listening for orders.");
// Iterator
for (int i=firstnode; i<(firstnode+maxnode); i++)
{
// Set my pin 'i' to be output.
pinMode(i, OUTPUT);
// and set it initially to be low.
digitalWrite(i, LOW);
}
// Start the server listening for connections.
server.begin();
}
// And GO!
void loop()
{
// Variables
uint8_t node=0; // The device I am working on.
uint8_t state=0; // The (new?) state of the pin.
// Start the network library.
Client client=server.available();
if (client)
{
char reading[7]; // 4 chars (XX:Y) + '\n' or '\r\n' or <NUL>' + double-increment below
int i=0;
while (((reading[i]=client.read())!=-1)||(i<5))
{
i++;
}
// Double increment to make sure my test works even when I don't get an '\n' or '\r\n'.
reading[i++]=0;
reading[i]=0;
// Parse the string.
// Format: XX:Y where XX is the node to work on and Y is the new state
// Make sure the string is formatted properly and print an error if not.
if (reading[2] != ':')
{
// Error
printError(reading);
return;
}
if (!isdigit(reading[0]) || !isdigit(reading[1]) || !isdigit(reading[3]))
{
// Error
printError(reading);
return;
}
// Next two check the termination
if ((reading[4] != 0) && (reading[4] != '\n') && (reading[4] != '\r'))
{
// Extraneous terminated string.
printError(reading);
return;
}
if ((reading[5] != 0) && (reading[5] != '\n') && (reading[5] != '\r'))
{
// Extraneous terminated string.
printError(reading);
return;
}
// Do the math to turn the node number into a binary value.
node=reading[0]-'0'; // First digit convertion (ie: '1' (0x31)-'0' (0x30) = 0x01 = "0000 0001 (dec. 1)").
node*=10; // Shift to the first base-10 position.
node+=reading[1]-'0'; // Now 'node' contains the binary version of the ASCII two-digit value read off of telnet.
// Do the math to turn the state number into a binary value.
state=reading[3]-'0'; // Now 'state' contains the binary version.
// Check the node.
if (node > 5)
{
// Node number can't be higher than '05' on this model.
Serial.println("This fence only supports up to '05' nodes.");
server.write("This fence only supports up to '05' nodes.\n");
}
if (state > 1)
{
// Node number can't be higher than '05' on this model.
Serial.println("Invalid state received. Send 'XX:0' to kill a node, XX:1 to release a node");
server.write("Invalid state received. Send 'XX:0' to kill a node, XX:1 to release a node\n");
}
// Check is this is an info request.
// By putting 0 first, I can never accidentally set 'node' to '0' with an accidental single-equal.
if (0 == node)
{
// Send states
Serial.println("Node states: ");
server.write("Node states: \n");
// Make my maxnode an ASCII value so that I can print it by reversing the convertion to binary done earlier.
char saynode[3]; // This is '3' because of 'first char' + 'second char' + terminating '0'.
saynode[0]=(maxnode/10)+'0'; // Move from the 'tens' posiition into the '1' position and add '0' to get the ASCII value.
saynode[1]=(maxnode%10)+'0'; // The modulous returns my real one position.
saynode[2]=0; // Null terminated.
Serial.print("- Max Node: "); Serial.println(saynode);
server.write("- Max Node: "); server.write(saynode); server.write("\n");
for (int i=0; i<maxnode; i++)
{
// 'i' is the current, printable node number.
saynode[0]=((i+1)/10)+'0'; // The '+1' makes the node 1-based instead of 0-based.
saynode[1]=((i+1)%10)+'0'; // The modulous returns my real one position.
char saystate = digitalRead(i+firstnode); // i + pin offset.
Serial.print("- Node "); Serial.print(saynode); Serial.print(": "); Serial.println((LOW == saystate) ? "Running" : "Fenced!" );
server.write("- Node "); server.write(saynode); server.write(": "); server.write((LOW == saystate) ? "Running\n" : "Fenced!\n");
}
Serial.println("End Message.");
server.write("End Message.\n");
return;
}
// Subtract 1 from node to make it zero-based.
node--;
// Set the pin based on whether 'state' is '0' or not.
digitalWrite(node+firstnode, (0 == state) ? HIGH : LOW);
// This is what I am trying to concatenate and to print as a whole line.
Serial.println(reading);
server.write(reading);
}
}
void printError(char reading[])
{
// Print the message to the serial bus and the client.
// I know this is dirty but it represents the one line string.
Serial.print("Bad command: [" ); Serial.print(reading); Serial.println("]" );
server.write("Bad command: [" ); server.write(reading); server.write("]\n" );
}
Input, advice, complaints and meanderings all welcome! | ||||
Digimer | digimer@alteeve.ca | https://alteeve.ca/w | legal stuff: | |
All info is provided "As-Is". Do not use anything here unless you are willing and able to take resposibility for your own actions. © 1997-2013 | ||||
Naming credits go to Christopher Olah! | ||||
In memory of Kettle, Tonia, Josh, Leah and Harvey. In special memory of Hannah, Jack and Riley. |