Naos v1.x: Difference between revisions
Line 40: | Line 40: | ||
#include <ctype.h> // Library for testing and character manipulation. | #include <ctype.h> // Library for testing and character manipulation. | ||
#include <stdint.h> // Library for standard integer types (guarantees the size of an int). | #include <stdint.h> // Library for standard integer types (guarantees the size of an int). | ||
#include <stdlib.h> // Library for things like 'sizeof()' and 'itoa()'. | |||
/* | /* | ||
Line 45: | Line 46: | ||
- Digimer | - Digimer | ||
Version: 1.0. | Version: 1.0.4 | ||
- Release: 2010- | - Release: 2010-02-28 | ||
License: | License: | ||
Line 70: | Line 71: | ||
- 0 fences the requested node. | - 0 fences the requested node. | ||
- 1 releases the fence and lets the node boot. | - 1 releases the fence and lets the node boot. | ||
- 2 Fence for one second. Useful for rebooting a node or for when a port | |||
is connected to a node's power button to boot or gracefully power down | |||
a node (via ACPI). | |||
- 3 Fence for five seconds. Only useful when connected to a power button. | |||
This allows the Node Assassin to force a frozen server to power off. | |||
- Example: | - Example: | ||
- To fence Node 01, send: | - To fence Node 01, send: | ||
Line 84: | Line 90: | ||
- Changing this file will have no effect until the program is recompiled and | - Changing this file will have no effect until the program is recompiled and | ||
uploaded to the Node Assassin. | uploaded to the Node Assassin. | ||
To Do: | |||
- Make naming the device and setting it's network settings configurable. | |||
Changes: | |||
- v1.0.2 | |||
- First release. | |||
- v1.0.3 | |||
- Added the '00:1' query message which returns the Node Assassin's details | |||
and identification. | |||
- Added the '##:2' and '##:3' options. | |||
*/ | */ | ||
// MAC Address; Array of six bytes. | // MAC Address; Array of six bytes. | ||
byte mac[] = { | // MAC address provided by Mark Loit. | ||
byte mac[] = { 0x00, 0x09, 0x30, 0xFF, 0xF0, 0x8A }; | |||
// Arduino IP, netmask and gateway. | // Arduino IP, netmask and gateway. | ||
byte ip[] = { 192, 168, 1, 66 }; | byte ip[] = { 192, 168, 1, 66 }; | ||
// byte ip[] = { 192, 168, 111, 66 }; | |||
// byte ip[] = { 10, 255, 0, 66 }; | |||
// Netmask defaults to 255.255.255.0. | // Netmask defaults to 255.255.255.0. | ||
// byte nm[] = { 255, 255, 255, 0 }; | |||
byte nm[] = { 255, 255, 255, 0 }; | byte nm[] = { 255, 255, 255, 0 }; | ||
// Default gateway defaults to IP with the last octal set to 1. | // Default gateway defaults to IP with the last octal set to 1. | ||
byte dg[] = { 192, 168, 1, 1 }; | byte dg[] = { 192, 168, 1, 1 }; | ||
// byte dg[] = { 192, 168, 111, 1 }; | |||
// byte dg[] = { 10, 255, 255, 254 }; | |||
// The user-set name of the node, up to sixteen characters long. | |||
char nodeName[16]="Ariel"; | |||
// The serial number. | |||
char serialNumber[7]="NA0001"; | |||
char osVersion[7]="v1.0.3"; | |||
char buildDate[11]="2010-02-26"; | |||
// This is the port that I will listen on. | // This is the port that I will listen on. | ||
Line 103: | Line 137: | ||
// Setup my digital out pins. | // Setup my digital out pins. | ||
// CONSTRAINT: Output pins must be ssigned sequentially | // CONSTRAINT: Output pins must be ssigned sequentially | ||
#define NODECOUNT | #define NODECOUNT 8 | ||
#define FIRSTNODEPIN 2 | #define FIRSTNODEPIN 2 | ||
Line 118: | Line 152: | ||
// Print the serial port welcom message. | // Print the serial port welcom message. | ||
Serial.begin(9600); | Serial.begin(9600); | ||
Serial.println("Node Assassin: 'Ariel' now listening for orders."); | // Serial.println("Node Assassin: 'Ariel' now listening for orders."); | ||
Serial.print("Node Assassin: '"); Serial.print(nodeName); Serial.println("' now listening for orders."); | |||
// Iterator to setup the digital pins to output and to set them | // Iterator to setup the digital pins to output and to set them | ||
Line 136: | Line 171: | ||
{ | { | ||
// Variables | // Variables | ||
uint8_t node=0; // The node | uint8_t node=0; // The node that will work on. | ||
uint8_t state=0; // The | uint8_t state=0; // The state of the node. | ||
char nodeASCII[3]; // ASCII representation of node number. This is | char nodeASCII[3]; // ASCII representation of node number. This is | ||
// '3' because of 'first char' + 'second char' + terminating <NUL> | // '3' because of 'first char' + 'second char' + terminating <NUL> | ||
char command[5]; // | char command[5]; // 5 chars "XX:Y" + <NUL> | ||
int index = 0; // Just an index to increment and reset in loops. | int index = 0; // Just an index to increment and reset in loops. | ||
char macString[6]; // MAC address. | |||
// Start the network library. | // Start the network library. | ||
Line 228: | Line 264: | ||
if (node > NODECOUNT) | if (node > NODECOUNT) | ||
{ | { | ||
// Node number can't be higher than NODECOUNT | // Node number can't be higher than NODECOUNT. | ||
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier. | // Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier. | ||
Line 236: | Line 272: | ||
// nodeASCII was <NUL> terminated earlier at 3, so no need to do it again here | // nodeASCII was <NUL> terminated earlier at 3, so no need to do it again here | ||
printMessage("This fence | printMessage("This fence supports up to "); printMessage(nodeASCII); printMessage("nodes.\n"); | ||
return; | return; | ||
} | } | ||
// Check that the requested state is sane. | // Check that the requested state is sane. | ||
if (state > | if (state > 3) | ||
{ | { | ||
// Node | // Node state can't be higher than '1' on this model. | ||
printMessage("Invalid state received. Send ' | printMessage("Invalid state received. Send '##:0' to kill a node, ##:1 to release a node, ##:2 to send a one second fence and ##:3 to send a 10 second fence.\n"); | ||
return; | return; | ||
} | } | ||
Line 251: | Line 287: | ||
if (0 == node) | if (0 == node) | ||
{ | { | ||
// | // If the message request is '0', return states. | ||
// If the message request is '1', return NA info. | |||
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier. | if (0 == state) | ||
{ | |||
// Send states | |||
printMessage("Node states: \n"); | |||
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier. | |||
// the below 2 lines will be converted by the compiler, so there is no run-time penalty for the math here | |||
nodeASCII[0]=(NODECOUNT/10)+'0'; // Move from the 'tens' posiition into the '1' position and add '0' to get the ASCII value. | |||
nodeASCII[1]=(NODECOUNT%10)+'0'; // The modulous returns my real one position. | |||
// nodeASCII was <NUL> terminated earlier at 3, so no need to do it again here | |||
printMessage("- Max Node: "); printMessage(nodeASCII); printMessage("\n"); | |||
/* | |||
Future optimization: | |||
The division and modulus in the loop can be expensive | |||
processing wise, as the compiler cannot do the | |||
calculation at compile time. As we are simply | |||
itteratively looping and incrementing, we can increment | |||
the ASCII value directly, removing the need for any | |||
division or modulus operations. | |||
*/ | |||
for (int i=0; i<NODECOUNT; i++) | |||
{ | |||
// 'i' is the current, zero-based node number. | |||
nodeASCII[0]=((i+1)/10)+'0'; // The '+1' makes the node 1-based instead of 0-based. | |||
nodeASCII[1]=((i+1)%10)+'0'; // The modulous returns my real one position. | |||
state = digitalRead(i+FIRSTNODEPIN); // i + pin offset. | |||
printMessage("- Node "); printMessage(nodeASCII); printMessage((LOW == state) ? ": Running\n" : ": Fenced!\n"); | |||
} | |||
printMessage("End Message.\n"); | |||
} | |||
else if (1 == state) | |||
{ | { | ||
// 'i' is the | /* Setup some strings. */ | ||
// MAC address. | |||
nodeASCII[1]=( | printMessage("Node info: \n"); | ||
char macASCII[18]; // Enough room for 6 bytes | |||
// of hex [12 digits], colon | |||
// seperators (:) and the | |||
// NULL terminator | |||
char ipASCII[16]; // IP address with '.'s. | |||
char nmASCII[16]; // Now the netmask | |||
char dgASCII[16]; // and the default gateway. | |||
int j=0; | |||
for(int i=0; i < (sizeof(mac) / sizeof(mac[0])); i++) | |||
{ | |||
// If I have a value, that is, is '1' | |||
// or higher, start by inserting a | |||
// period (.) to seperate the octets. | |||
// This method avoids a preceeding '.'. | |||
if (i) | |||
{ | |||
macASCII[j++] = ':'; | |||
} | |||
// We're dealing with two characters, | |||
// so if this value is less than 16 | |||
// (0000 1111), add a leading '0'. | |||
if (mac[i]<16) | |||
{ | |||
macASCII[j] = '0'; | |||
itoa(mac[i], &macASCII[(j)+1], 16); | |||
} | |||
else | |||
{ | |||
itoa(mac[i], &macASCII[j], 16); | |||
} | |||
j+=2; | |||
} | |||
// IP, netmask and default gateway. | |||
j=0; | |||
for (int i=0; i < (sizeof(ip) / sizeof(ip[0])); i++) | |||
{ | |||
// If I have a value, that is, is '1' | |||
// or higher, start by inserting a | |||
// period (.) to seperate the octets. | |||
// This method avoids a preceeding '.'. | |||
if (i) | |||
{ | |||
ipASCII[j++] = '.'; | |||
} | |||
// Convert the integer to an ASCII. | |||
itoa(ip[i], &ipASCII[j++], 10); | |||
// Increment 'j' one or two places, | |||
// depending on the value of 'j'. | |||
if(ip[i]>9) j++; | |||
if(ip[i]>99) j++; | |||
} | |||
j=0; | |||
for (int i=0; i < (sizeof(nm) / sizeof(nm[0])); i++) | |||
{ | |||
// If I have a value, that is, is '1' | |||
// or higher, start by inserting a | |||
// period (.) to seperate the octets. | |||
// This method avoids a preceeding '.'. | |||
if (i) | |||
{ | |||
nmASCII[j++] = '.'; | |||
} | |||
// Convert the integer to an ASCII. | |||
itoa(nm[i], &nmASCII[j++], 10); | |||
// Increment 'j' one or two places, | |||
// depending on the value of 'j'. | |||
if(nm[i]>9) j++; | |||
if(nm[i]>99) j++; | |||
} | |||
j=0; | |||
for (int i=0; i < (sizeof(ip) / sizeof(ip[0])); i++) | |||
{ | |||
// If I have a value, that is, is '1' | |||
// or higher, start by inserting a | |||
// period (.) to seperate the octets. | |||
// This method avoids a preceeding '.'. | |||
if (i) | |||
{ | |||
dgASCII[j++] = '.'; | |||
} | |||
// Convert the integer to an ASCII. | |||
itoa(dg[i], &dgASCII[j++], 10); | |||
// Increment 'j' one or two places, | |||
// depending on the value of 'j'. | |||
if(dg[i]>9) j++; | |||
if(dg[i]>99) j++; | |||
} | |||
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier. | |||
// the below 2 lines will be converted by the compiler, so there is no run-time penalty for the math here | |||
nodeASCII[0]=(NODECOUNT/10)+'0'; // Move from the 'tens' posiition into the '1' position and add '0' to get the ASCII value. | |||
nodeASCII[1]=(NODECOUNT%10)+'0'; // The modulous returns my real one position. | |||
// Print the info. | |||
printMessage("- Node "); printMessage(nodeASCII); printMessage(( | printMessage("- Node Name: ..... "); printMessage(nodeName); printMessage("\n"); | ||
printMessage("- Port Count: .... "); printMessage(nodeASCII); printMessage("\n"); | |||
printMessage("- NAOS Version: .. "); printMessage(osVersion); printMessage("\n"); | |||
printMessage("- Serial Number: . "); printMessage(serialNumber); printMessage("\n"); | |||
printMessage("- Build Date: .... "); printMessage(buildDate); printMessage("\n"); | |||
printMessage("- MAC address: ... "); printMessage(macASCII); printMessage("\n"); | |||
printMessage("- IP address: .... "); printMessage(ipASCII); printMessage("\n"); | |||
printMessage("- Subnet Mask: ... "); printMessage(nmASCII); printMessage("\n"); | |||
printMessage("- Default Gateway: "); printMessage(dgASCII); printMessage("\n"); | |||
printMessage("End Message.\n"); | |||
} | |||
else | |||
{ | |||
// Unrecognized message request. | |||
printMessage("Unknown message request ID. '00:0' returns node states, '00:1' returns Node Assassin information.\n"); | |||
} | } | ||
return; | return; | ||
Line 289: | Line 446: | ||
node--; | node--; | ||
// Set the pin based on whether 'state' is '0' or not. | // Set the pin based on whether 'state' is '0' or not. | ||
digitalWrite(node+FIRSTNODEPIN, ( | if (0 == state) | ||
{ | |||
// Fence the node | |||
digitalWrite(node+FIRSTNODEPIN, HIGH); | |||
printMessage("Node "); printMessage(command); printMessage(": Now Fenced!\n"); | |||
} | |||
else if (1 == state) | |||
{ | |||
// Release the node. | |||
digitalWrite(node+FIRSTNODEPIN, LOW); | |||
printMessage("Node "); printMessage(command); printMessage(": Fence released!\n"); | |||
} | |||
else if (2 == state) | |||
{ | |||
// Fence for 1 second. | |||
printMessage("Node "); printMessage(command); printMessage(": Fencing for 1 second - "); | |||
digitalWrite(node+FIRSTNODEPIN, HIGH); | |||
delay(1000); | |||
digitalWrite(node+FIRSTNODEPIN, LOW); | |||
printMessage("Fence released.\n"); | |||
} | |||
else if (3 == state) | |||
{ | |||
// Fence for 5 seconds. | |||
printMessage("Node "); printMessage(command); printMessage(": Fencing for 5 seconds - "); | |||
digitalWrite(node+FIRSTNODEPIN, HIGH); | |||
delay(5000); | |||
digitalWrite(node+FIRSTNODEPIN, LOW); | |||
printMessage("Fence released.\n"); | |||
} | |||
} | } | ||
} | } |
Revision as of 00:34, 1 March 2010
Node Assassin :: Naos v1.x |
Release
- Last update: Feb. 28, 2010
- Tested Against: Arduino Alpha v0017 x86
- Naos Version: 1.0.3
Notes
WARNING
USE THIS CODE AT YOUR OWN RISK!
It's the default warning for everything related to this project, but it's worth repeating here. This code come with no guarantee in any way, shape or form. This has only been tested on my board, the Arduino Duemilanove with the ATmega320 chip connected to the Wiznet W5100 ethernet shield. I can't guarantee it will work on any other hardware, but I would love to hear from you if you do try it elsewhere!
Changes To Make BEFORE Uploading
Before you upload this, be sure to set an IP address and MAC address that suits your network.
- Change the network address to fit your network. The defaults are:
- IP Addr: 192.168.1.66
- Netmask: 255.255.255.0
- Gateway: 192.168.1.1
- In the sketch below, alter the byte mac[] value to a value unique on you network. To be honest, the default is probably ok.
Use
Copy this code into the 'Arduino alpha' loader, test it and then upload it to your board.
Thanks
The majority of this first version was made possible thanks the generous patience of Mark Loit at hacklab.to who spent the day giving me a crash course in C and helping me diagnose my first circuit. He also gets the credit for the project's tag line.
Code
#include <Ethernet.h> // Arduino's ethernet library.
#include <ctype.h> // Library for testing and character manipulation.
#include <stdint.h> // Library for standard integer types (guarantees the size of an int).
#include <stdlib.h> // Library for things like 'sizeof()' and 'itoa()'.
/*
Author:
- Digimer
Version: 1.0.4
- Release: 2010-02-28
License:
- The GNU GPL v2.0
Thanks:
- Hacklab.TO: The idea for this device was born there.
- Christopher Olah; Came up with the name "Node Assassin".
- Mark Loit: Taught me enough C to write version 1.0 of NaOS!
Bugs:
- None known at this time.
Protocol:
- Telnet (or similar) to the IP and Port set below.
- To query the state of the nodes, send:
- 00:0
- The integer after the '00:' is reserved for future queries.
- To set the state of a node, send:
- XX:Y
- XX is the zero-padded node ID number; 01, 02, 03, 04 or 05
- Y is the state to set
- 0 fences the requested node.
- 1 releases the fence and lets the node boot.
- 2 Fence for one second. Useful for rebooting a node or for when a port
is connected to a node's power button to boot or gracefully power down
a node (via ACPI).
- 3 Fence for five seconds. Only useful when connected to a power button.
This allows the Node Assassin to force a frozen server to power off.
- Example:
- To fence Node 01, send:
- 01:0
- To release the fence and thus let the node boot, send:
- 01:1
- Sending any other non-standard command will generate an error message and no
action will be taken.
Note:
- This device implements NO security. You MUST install in on a private, secure
intranet or similar back channel. Installing it on the same LAN as the
storage devices is advised.
- Changing this file will have no effect until the program is recompiled and
uploaded to the Node Assassin.
To Do:
- Make naming the device and setting it's network settings configurable.
Changes:
- v1.0.2
- First release.
- v1.0.3
- Added the '00:1' query message which returns the Node Assassin's details
and identification.
- Added the '##:2' and '##:3' options.
*/
// MAC Address; Array of six bytes.
// MAC address provided by Mark Loit.
byte mac[] = { 0x00, 0x09, 0x30, 0xFF, 0xF0, 0x8A };
// Arduino IP, netmask and gateway.
byte ip[] = { 192, 168, 1, 66 };
// byte ip[] = { 192, 168, 111, 66 };
// byte ip[] = { 10, 255, 0, 66 };
// Netmask defaults to 255.255.255.0.
// byte nm[] = { 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 };
// byte dg[] = { 192, 168, 111, 1 };
// byte dg[] = { 10, 255, 255, 254 };
// The user-set name of the node, up to sixteen characters long.
char nodeName[16]="Ariel";
// The serial number.
char serialNumber[7]="NA0001";
char osVersion[7]="v1.0.3";
char buildDate[11]="2010-02-26";
// This is the port that I will listen on.
#define PORT 238
// Setup the server.
Server server = Server(PORT);
// Setup my digital out pins.
// CONSTRAINT: Output pins must be ssigned sequentially
#define NODECOUNT 8
#define FIRSTNODEPIN 2
// My function prototypes.
void printError(const char *message);
void printMessage(const char *message);
// Setup the Arduino on boot.
void setup()
{
// Setup the IP info.
Ethernet.begin(mac, ip, dg, nm);
// Print the serial port welcom message.
Serial.begin(9600);
// Serial.println("Node Assassin: 'Ariel' now listening for orders.");
Serial.print("Node Assassin: '"); Serial.print(nodeName); Serial.println("' now listening for orders.");
// Iterator to setup the digital pins to output and to set them
// initially to LOW.
for (int pin = FIRSTNODEPIN; pin < (FIRSTNODEPIN+NODECOUNT); pin++)
{
pinMode(pin, OUTPUT);
digitalWrite(pin, LOW);
}
// Start the server listening for connections.
server.begin();
}
// And GO!
void loop()
{
// Variables
uint8_t node=0; // The node that will work on.
uint8_t state=0; // The state of the node.
char nodeASCII[3]; // ASCII representation of node number. This is
// '3' because of 'first char' + 'second char' + terminating <NUL>
char command[5]; // 5 chars "XX:Y" + <NUL>
int index = 0; // Just an index to increment and reset in loops.
char macString[6]; // MAC address.
// Start the network library.
Client client=server.available();
if (client)
{
// process the input in a line-based manner, allowing for 1 command per line
while ((-1 != (command[index] = client.read()) ) && (5 > index))
{
// exit at the end of line
if( ('\n' == command[index]) || ('\r' == command[index]) )
{
break; // EOL found, break out of the while loop.
}
index++; // advance the index.
}
// on a valid line the above while loop will exit with index == 4
// If there is no message, nothing to do but exit.
// Coding note: By putting 0 first, I can never accidentally
// set the variable to '0' with an accidental single-equal.
if (0 == index)
{
return;
}
// sanity check on length
if (4 > index)
{
printMessage("Message too short. Format is 'XX:Y' where 'XX' is the zero-padded node number and Y is the state to set.\n");
return;
}
// Spool off whatever is left in the buffer/line in case it was a string longer than 4.
if (5 == index)
{
char ch;
printMessage("Message too long. Format is 'XX:Y' where 'XX' is the zero-padded node number and Y is the state to set.\n");
while (-1 != (ch = client.read()) )
{
// exit at the end of line
if( ('\n' == ch) || ('\r' == ch) )
{
break; // break out of the while loop
}
}
return;
}
// <NUL> terminate the string
command[index] = 0;
// Parse the string; Error if anything isn't right.
// Make sure we have a colon in the right location
if (':' != command[2])
{
// Error
printError(command);
return;
}
// Make sure the other characters are digits
if (!isdigit(command[0]) || !isdigit(command[1]) || !isdigit(command[3]))
{
// Error
printError(command);
return;
}
// No need to check for the terminator or newline at the end,
// that was taken care of in the read loop.
// Do the math to turn the ASCII node number into a binary
// value.
node=command[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+=command[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=command[3]-'0'; // Now 'state' contains the binary version.
// copy the ASCII node name for the response messages [so we don't have to convert it back later]
nodeASCII[0] = command[0];
nodeASCII[1] = command[1];
nodeASCII[2] = 0; // <NUL> terminate it
// Check the node.
if (node > NODECOUNT)
{
// Node number can't be higher than NODECOUNT.
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier.
// the below 2 lines will be converted by the compiler, so there is no run-time penalty for the math here
nodeASCII[0]=(NODECOUNT/10)+'0'; // Move from the 'tens' posiition into the '1' position and add '0' to get the ASCII value.
nodeASCII[1]=(NODECOUNT%10)+'0'; // The modulous returns my real one position.
// nodeASCII was <NUL> terminated earlier at 3, so no need to do it again here
printMessage("This fence supports up to "); printMessage(nodeASCII); printMessage("nodes.\n");
return;
}
// Check that the requested state is sane.
if (state > 3)
{
// Node state can't be higher than '1' on this model.
printMessage("Invalid state received. Send '##:0' to kill a node, ##:1 to release a node, ##:2 to send a one second fence and ##:3 to send a 10 second fence.\n");
return;
}
// Check is this is an info request.
if (0 == node)
{
// If the message request is '0', return states.
// If the message request is '1', return NA info.
if (0 == state)
{
// Send states
printMessage("Node states: \n");
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier.
// the below 2 lines will be converted by the compiler, so there is no run-time penalty for the math here
nodeASCII[0]=(NODECOUNT/10)+'0'; // Move from the 'tens' posiition into the '1' position and add '0' to get the ASCII value.
nodeASCII[1]=(NODECOUNT%10)+'0'; // The modulous returns my real one position.
// nodeASCII was <NUL> terminated earlier at 3, so no need to do it again here
printMessage("- Max Node: "); printMessage(nodeASCII); printMessage("\n");
/*
Future optimization:
The division and modulus in the loop can be expensive
processing wise, as the compiler cannot do the
calculation at compile time. As we are simply
itteratively looping and incrementing, we can increment
the ASCII value directly, removing the need for any
division or modulus operations.
*/
for (int i=0; i<NODECOUNT; i++)
{
// 'i' is the current, zero-based node number.
nodeASCII[0]=((i+1)/10)+'0'; // The '+1' makes the node 1-based instead of 0-based.
nodeASCII[1]=((i+1)%10)+'0'; // The modulous returns my real one position.
state = digitalRead(i+FIRSTNODEPIN); // i + pin offset.
printMessage("- Node "); printMessage(nodeASCII); printMessage((LOW == state) ? ": Running\n" : ": Fenced!\n");
}
printMessage("End Message.\n");
}
else if (1 == state)
{
/* Setup some strings. */
// MAC address.
printMessage("Node info: \n");
char macASCII[18]; // Enough room for 6 bytes
// of hex [12 digits], colon
// seperators (:) and the
// NULL terminator
char ipASCII[16]; // IP address with '.'s.
char nmASCII[16]; // Now the netmask
char dgASCII[16]; // and the default gateway.
int j=0;
for(int i=0; i < (sizeof(mac) / sizeof(mac[0])); i++)
{
// If I have a value, that is, is '1'
// or higher, start by inserting a
// period (.) to seperate the octets.
// This method avoids a preceeding '.'.
if (i)
{
macASCII[j++] = ':';
}
// We're dealing with two characters,
// so if this value is less than 16
// (0000 1111), add a leading '0'.
if (mac[i]<16)
{
macASCII[j] = '0';
itoa(mac[i], &macASCII[(j)+1], 16);
}
else
{
itoa(mac[i], &macASCII[j], 16);
}
j+=2;
}
// IP, netmask and default gateway.
j=0;
for (int i=0; i < (sizeof(ip) / sizeof(ip[0])); i++)
{
// If I have a value, that is, is '1'
// or higher, start by inserting a
// period (.) to seperate the octets.
// This method avoids a preceeding '.'.
if (i)
{
ipASCII[j++] = '.';
}
// Convert the integer to an ASCII.
itoa(ip[i], &ipASCII[j++], 10);
// Increment 'j' one or two places,
// depending on the value of 'j'.
if(ip[i]>9) j++;
if(ip[i]>99) j++;
}
j=0;
for (int i=0; i < (sizeof(nm) / sizeof(nm[0])); i++)
{
// If I have a value, that is, is '1'
// or higher, start by inserting a
// period (.) to seperate the octets.
// This method avoids a preceeding '.'.
if (i)
{
nmASCII[j++] = '.';
}
// Convert the integer to an ASCII.
itoa(nm[i], &nmASCII[j++], 10);
// Increment 'j' one or two places,
// depending on the value of 'j'.
if(nm[i]>9) j++;
if(nm[i]>99) j++;
}
j=0;
for (int i=0; i < (sizeof(ip) / sizeof(ip[0])); i++)
{
// If I have a value, that is, is '1'
// or higher, start by inserting a
// period (.) to seperate the octets.
// This method avoids a preceeding '.'.
if (i)
{
dgASCII[j++] = '.';
}
// Convert the integer to an ASCII.
itoa(dg[i], &dgASCII[j++], 10);
// Increment 'j' one or two places,
// depending on the value of 'j'.
if(dg[i]>9) j++;
if(dg[i]>99) j++;
}
// Make my NODECOUNT an ASCII value so that I can print it by reversing the convertion to binary done earlier.
// the below 2 lines will be converted by the compiler, so there is no run-time penalty for the math here
nodeASCII[0]=(NODECOUNT/10)+'0'; // Move from the 'tens' posiition into the '1' position and add '0' to get the ASCII value.
nodeASCII[1]=(NODECOUNT%10)+'0'; // The modulous returns my real one position.
// Print the info.
printMessage("- Node Name: ..... "); printMessage(nodeName); printMessage("\n");
printMessage("- Port Count: .... "); printMessage(nodeASCII); printMessage("\n");
printMessage("- NAOS Version: .. "); printMessage(osVersion); printMessage("\n");
printMessage("- Serial Number: . "); printMessage(serialNumber); printMessage("\n");
printMessage("- Build Date: .... "); printMessage(buildDate); printMessage("\n");
printMessage("- MAC address: ... "); printMessage(macASCII); printMessage("\n");
printMessage("- IP address: .... "); printMessage(ipASCII); printMessage("\n");
printMessage("- Subnet Mask: ... "); printMessage(nmASCII); printMessage("\n");
printMessage("- Default Gateway: "); printMessage(dgASCII); printMessage("\n");
printMessage("End Message.\n");
}
else
{
// Unrecognized message request.
printMessage("Unknown message request ID. '00:0' returns node states, '00:1' returns Node Assassin information.\n");
}
return;
}
// Subtract 1 from node to make it zero-based.
node--;
// Set the pin based on whether 'state' is '0' or not.
if (0 == state)
{
// Fence the node
digitalWrite(node+FIRSTNODEPIN, HIGH);
printMessage("Node "); printMessage(command); printMessage(": Now Fenced!\n");
}
else if (1 == state)
{
// Release the node.
digitalWrite(node+FIRSTNODEPIN, LOW);
printMessage("Node "); printMessage(command); printMessage(": Fence released!\n");
}
else if (2 == state)
{
// Fence for 1 second.
printMessage("Node "); printMessage(command); printMessage(": Fencing for 1 second - ");
digitalWrite(node+FIRSTNODEPIN, HIGH);
delay(1000);
digitalWrite(node+FIRSTNODEPIN, LOW);
printMessage("Fence released.\n");
}
else if (3 == state)
{
// Fence for 5 seconds.
printMessage("Node "); printMessage(command); printMessage(": Fencing for 5 seconds - ");
digitalWrite(node+FIRSTNODEPIN, HIGH);
delay(5000);
digitalWrite(node+FIRSTNODEPIN, LOW);
printMessage("Fence released.\n");
}
}
}
// The error handling function.
void printError(const char *message)
{
// Print the message to the serial bus and the client.
// I know this is dirty but it represents the one line string.
printMessage("Bad command: [" ); printMessage(message); printMessage("]\n" );
}
void printMessage(const char *message)
{
// Print the message to the serial bus and the client.
Serial.print(message);
server.write(message);
}
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. |