Compare commits
10 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| eefc7c325d | |||
| 7233d97674 | |||
| 56bf1942ec | |||
| 400265094e | |||
| 5dd11eef10 | |||
| 5435c21ebc | |||
| d88327d372 | |||
| 83d7e5d465 | |||
| 7a3f194cd5 | |||
| 0d243683fe |
+7
-1
@@ -1,7 +1,7 @@
|
||||
// =============================================================================
|
||||
// Auth: Alex Celani
|
||||
// File: colonel.go
|
||||
// Revn: 06-27-2022 1.2
|
||||
// Revn: 07-05-2022 2.0
|
||||
// Func: Send message to another machine and then receive a single
|
||||
// response. Extremely tight bounds, not robust at all
|
||||
//
|
||||
@@ -13,6 +13,7 @@
|
||||
//*06-20-2022: changed name to reflect first draft of colonel.go
|
||||
// 06-23-2022: made input an infinite loop
|
||||
// 06-27-2022: added flag package, assumed ip
|
||||
//*07-05-2022: added support for kill messages
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
@@ -90,6 +91,11 @@ func main() {
|
||||
if *verbose {
|
||||
fmt.Println( "\nrtt: ", t.Sub( start ) ) // print time
|
||||
}
|
||||
|
||||
// response is "kill" if user sends a kill message
|
||||
if string( buf[:n] ) == "kill" {
|
||||
os.Exit( 1 )
|
||||
}
|
||||
}
|
||||
|
||||
os.Exit( 0 ) // exeunt
|
||||
|
||||
+22
-29
@@ -1,10 +1,11 @@
|
||||
// =============================================================================
|
||||
// Auth: Alex Celani
|
||||
// File: led.go
|
||||
// Revn: 07-04-2022 2.0
|
||||
// Revn: 07-11-2022 4.0
|
||||
// Func: receive data as an endpoint, send response back to middleman
|
||||
// ONLY A SIMULATION FOR THE REAL THING
|
||||
//
|
||||
// TODO:
|
||||
// TODO: implement rainbow
|
||||
// =============================================================================
|
||||
// CHANGE LOG
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -28,6 +29,8 @@
|
||||
// added support for white, cyan, yellow, and magenta
|
||||
// finished comments for tell() and ask() and even simple
|
||||
// parsing stuff in handleClient()
|
||||
//*07-05-2022: added support for kill messages
|
||||
//*07-11-2022: added /list/ as field that calls ask()
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
@@ -86,24 +89,6 @@ func ask( comm []string ) string {
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
// quick function to make a rainbow
|
||||
func rainbow() {
|
||||
for {
|
||||
for r := 255; r >= 0; r-- {
|
||||
|
||||
}
|
||||
for g := 255; g >= 0; g-- {
|
||||
|
||||
}
|
||||
for b := 255; b >= 0; b-- {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
// quick function to change LED colors
|
||||
func tell( comm []string ) string {
|
||||
|
||||
@@ -144,9 +129,6 @@ func tell( comm []string ) string {
|
||||
pinR.Low()
|
||||
pinG.Low()
|
||||
pinB.Low()
|
||||
case "rainbow": // user wants a loop
|
||||
// go rainbow()
|
||||
response = "not yet implemented"
|
||||
default: // user asks for else, bail out
|
||||
response = "color unknown"
|
||||
status = "off"
|
||||
@@ -163,8 +145,9 @@ func tell( comm []string ) string {
|
||||
default: // user asks for else, bail out
|
||||
response = "status unknown"
|
||||
}
|
||||
case "kill": // user wants to stop running
|
||||
os.Exit( 2 ) // FIXME
|
||||
// user wants to stop running
|
||||
case "kill", "quit", "end", "die", "stop":
|
||||
response = "kill"
|
||||
default: // user enters incorrect command
|
||||
response = "command unknown"
|
||||
}
|
||||
@@ -197,12 +180,10 @@ func handleClient( conn net.Conn ) {
|
||||
// split command into words for ease of parsing
|
||||
command := strings.Split( string( buf[:n] ), " " )
|
||||
|
||||
if command[1] != "led" { // confirm message belongs here
|
||||
if command[1] != "piled" { // confirm message belongs here
|
||||
os.Exit( 2 ) // if not, exit
|
||||
}
|
||||
|
||||
// TODO differentiate ask commands from tell commands
|
||||
|
||||
// initiate response variable
|
||||
var resp string
|
||||
|
||||
@@ -210,6 +191,9 @@ func handleClient( conn net.Conn ) {
|
||||
case "ask": // if getting
|
||||
// get, store response in variable to be sent back
|
||||
resp = ask( command[2:] )
|
||||
case "list": // is user getting list?
|
||||
// get, store response in variable to be sent back
|
||||
resp = ask( command )
|
||||
case "tell": // if setting
|
||||
// set, store response in variable to be sent back
|
||||
resp = tell( command[2:] )
|
||||
@@ -230,6 +214,10 @@ func handleClient( conn net.Conn ) {
|
||||
if *verbose { // XXX identical verbose print
|
||||
fmt.Println( "sent: ", resp ) // print response
|
||||
}
|
||||
|
||||
if resp == "kill" { // if user sent back kill
|
||||
os.Exit( 1 ) // end process
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -258,7 +246,7 @@ func main() {
|
||||
lg = flag.Int( "lg", 9, "GPIO pin for green LED" )
|
||||
lb = flag.Int( "lb", 25, "GPIO pin for blue LED" )
|
||||
verbose = flag.Bool( "v", false, "verbose printing" )
|
||||
ip = flag.String( "ip", ":1202", "ip and port of self" )
|
||||
ip = flag.String( "ip", ":1212", "ip and port of self" )
|
||||
flag.Parse()
|
||||
|
||||
// initialize pins to GPIO 11, 9, and 25
|
||||
@@ -280,6 +268,11 @@ func main() {
|
||||
pinG.Output()
|
||||
pinB.Output()
|
||||
|
||||
// Initialize output to "off"
|
||||
pinR.High()
|
||||
pinG.High()
|
||||
pinB.High()
|
||||
|
||||
// "resolve" ip & host according to TCP rules
|
||||
tcpAddr, err := net.ResolveTCPAddr( "tcp", *ip )
|
||||
check( err ) // check error
|
||||
|
||||
+398
@@ -0,0 +1,398 @@
|
||||
// ===================================================================
|
||||
// Auth: Alex
|
||||
// File: led.ino
|
||||
// Revn: 07-20-2022 1.0
|
||||
// Func: End node, to run on ESP8266. Operate as server, process
|
||||
// incoming messages, react to them, send responses
|
||||
//
|
||||
// TODO: incorporate interrupt example for builtin led
|
||||
// ===================================================================
|
||||
// CHANGE LOG
|
||||
// -------------------------------------------------------------------
|
||||
// 07-07-2022: found online
|
||||
// 07-12-2022: changed client.write() to client.println(), to fix
|
||||
// bug about sending Strings
|
||||
// investigated strcmp, pinmode, etc
|
||||
// cleaned up, commented setup()
|
||||
// 07-13-2022: commented
|
||||
// investigated faster ways to take input; no dice
|
||||
// toggle builtin led on receipt
|
||||
// 07-14-2022: commented loop()
|
||||
// wrote prse()
|
||||
// began added [list esp] message, lst()
|
||||
// wrote bones for refresh(), to update led
|
||||
// 07-19-2022: added led to circuit, wrote refresh()
|
||||
// moved check for /list/ above check for second word
|
||||
// to fix /list/ not sending bug
|
||||
// added default error value for response variable
|
||||
// added call to refresh at the end of setup() to init
|
||||
// led state
|
||||
//*07-20-2022: /tell/ commands set status to on
|
||||
// commented
|
||||
// changed name of file from democode to led.ino
|
||||
// changed NAME var from "esp" to "led"
|
||||
//
|
||||
// ===================================================================
|
||||
|
||||
// ESP8266 version of Wifi.h
|
||||
// API Documentation located at:
|
||||
//
|
||||
// Pinout located at:
|
||||
// https://microcontrollerslab.com/led-blinking-using-esp8266-nodemcu/#ESP8266_Pinout_in_Arduino_IDE
|
||||
#include <ESP8266WiFi.h>
|
||||
// documentation at
|
||||
// https://arduino.cc/reference/en/libraries/esp8266timerinterrupt/
|
||||
#include <ESP8266TimerInterrupt.h>
|
||||
|
||||
// real shit, not certain why this is important
|
||||
#define SendKey 0 // button to send data Flash BTN on NodeMCU
|
||||
|
||||
int port = 1210; // port of server
|
||||
WiFiServer server(port);
|
||||
|
||||
IPAddress self( 192, 168, 1, 69 ); // ip address of self
|
||||
IPAddress gate( 192, 168, 1, 1 ); // ip address of gateway
|
||||
IPAddress subn( 255, 255, 0, 0 ); // subnet mask
|
||||
IPAddress pDNS( 8, 8, 8, 8 ); // primary DNS server ip
|
||||
IPAddress sDNS( 8, 8, 4, 4 ); // secondary DNS server ip
|
||||
|
||||
// credentials for WiFi Network
|
||||
const char *ssid = "waystation";
|
||||
const char *password = "homophobiaR0X";
|
||||
|
||||
// pin definitions
|
||||
int pinR = 16; // GPIO16 --> D0 on the board
|
||||
int pinG = 5; // GPIO5 --> D1 on the board
|
||||
int pinB = 4; // GPIO4 --> D2 on the board
|
||||
|
||||
//int pinBI = 2; // GPIO2 --> D4 on the board, built-in LED
|
||||
|
||||
// state variables
|
||||
bool statusRGB = true; // init, true -> off
|
||||
String color = "red"; // init color red
|
||||
|
||||
bool statusBI = true; // init, true -> off
|
||||
|
||||
String NAME = "led"; // variable to semi-hardcode program name
|
||||
|
||||
// ===================================================================
|
||||
// Power on setup
|
||||
// ===================================================================
|
||||
void setup() {
|
||||
pinMode( pinBI, OUTPUT ); // set built-in LED to output
|
||||
digitalWrite( pinBI, statusBI ); // initialize it off
|
||||
// this really dumb fucking board is active low, I am fucking weeping
|
||||
|
||||
// init rgb led pins as output
|
||||
pinMode( pinR, OUTPUT );
|
||||
pinMode( pinG, OUTPUT );
|
||||
pinMode( pinB, OUTPUT );
|
||||
|
||||
// init rgb led as off ( active low, the headache )
|
||||
digitalWrite( pinR, HIGH );
|
||||
digitalWrite( pinG, HIGH );
|
||||
digitalWrite( pinB, HIGH );
|
||||
|
||||
Serial.begin( 115200 ); // board works at 115,200 [baud]
|
||||
pinMode( SendKey, INPUT_PULLUP ); // Btn to send data (NMC NMM)
|
||||
|
||||
WiFi.mode( WIFI_STA ); // set mode to station
|
||||
// set static ip address ( only way it would let me do it )
|
||||
WiFi.config( self, gate, subn, pDNS, sDNS );
|
||||
WiFi.begin( ssid, password ); // connect to wifi
|
||||
|
||||
// Serial.prints all considered verbose, because you can only see
|
||||
// them if you're trying to
|
||||
// wait for connection
|
||||
Serial.println( "Connecting to Wifi" );
|
||||
// iterate until connected
|
||||
while( WiFi.status() != WL_CONNECTED ) {
|
||||
delay( 1000 );
|
||||
Serial.print( "." );
|
||||
}
|
||||
|
||||
// print connection status
|
||||
Serial.println();
|
||||
Serial.print( "Connected to " );
|
||||
Serial.println( ssid );
|
||||
|
||||
server.begin(); // bring server online
|
||||
// print server address
|
||||
Serial.print( "On at: " );
|
||||
Serial.print( WiFi.localIP() );
|
||||
Serial.print( ":" );
|
||||
Serial.println( port );
|
||||
|
||||
refresh(); // update led on setup
|
||||
}
|
||||
|
||||
|
||||
void refresh() {
|
||||
// print led status
|
||||
Serial.print( "color: " );
|
||||
Serial.println( color );
|
||||
Serial.print( "status: " );
|
||||
Serial.println( statusRGB );
|
||||
|
||||
// declare all pins off
|
||||
digitalWrite( pinR, HIGH );
|
||||
digitalWrite( pinG, HIGH );
|
||||
digitalWrite( pinB, HIGH );
|
||||
|
||||
// if led should be on
|
||||
// if off, led pins are already off
|
||||
if( !statusRGB ) {
|
||||
if( color == "red" ) { // if red
|
||||
digitalWrite( pinR, LOW ); // turn on only red
|
||||
} else if( color == "green" ) { // if green
|
||||
digitalWrite( pinG, LOW ); // turn on only green
|
||||
} else if( color == "blue" ) { // if blue
|
||||
digitalWrite( pinB, LOW ); // turn on only blue
|
||||
} else if( color == "cyan" ) { // if 'cyan'
|
||||
digitalWrite( pinG, LOW ); // cyan = B + G
|
||||
digitalWrite( pinB, LOW );
|
||||
} else if( color == "yellow" ) { // if yellow
|
||||
digitalWrite( pinR, LOW ); // yellow = R + G
|
||||
digitalWrite( pinG, LOW );
|
||||
} else if( color == "magenta" ) { // if magenta
|
||||
digitalWrite( pinR, LOW ); // magenta = R + B
|
||||
digitalWrite( pinB, LOW );
|
||||
} else if( color == "white" ) { // if white
|
||||
digitalWrite( pinR, LOW ); // all on for white
|
||||
digitalWrite( pinG, LOW );
|
||||
digitalWrite( pinB, LOW );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
String lst() {
|
||||
//craft list string and return
|
||||
String resp = "";
|
||||
|
||||
resp = resp + "color ^v\n";
|
||||
resp = resp + " blue\n";
|
||||
resp = resp + " cyan\n";
|
||||
resp = resp + " green\n";
|
||||
resp = resp + " magenta\n";
|
||||
resp = resp + " red\n";
|
||||
resp = resp + " white\n";
|
||||
resp = resp + " yellow\n";
|
||||
resp = resp + " status ^v\n";
|
||||
resp = resp + " on\n";
|
||||
resp = resp + " off\n";
|
||||
resp = resp + " off ^\n";
|
||||
resp = resp + " on ^\n";
|
||||
resp = resp + " list v";
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
String prse( String command ) {
|
||||
int amnt = 0; // keep track of amount of spaces
|
||||
int len = command.length(); // capture length
|
||||
|
||||
// quick variables to keep track of command
|
||||
bool ask = false;
|
||||
bool tell = false;
|
||||
bool list = false;
|
||||
|
||||
// init failure string
|
||||
String response = "error: command unrecognized";
|
||||
|
||||
// iterate over each letter of incoming message
|
||||
for( int i = 0; i < command.length(); i++ ) {
|
||||
// when letter is space...
|
||||
if( command[i] == ' ' ) {
|
||||
amnt++; // increment count for number of spaces
|
||||
// on the first space
|
||||
if( amnt == 1 ) {
|
||||
// print first command
|
||||
Serial.print( "ask/tell: " );
|
||||
Serial.println( command.substring( 0, i ) );
|
||||
// snatch bools for various commands
|
||||
ask = command.substring( 0, i ) == "ask";
|
||||
tell = command.substring( 0, i ) == "tell";
|
||||
list = command.substring( 0, i ) == "list";
|
||||
|
||||
// print bools
|
||||
Serial.println( ask );
|
||||
Serial.println( tell );
|
||||
Serial.println( list );
|
||||
|
||||
// seemed hacky but it fuckin works
|
||||
// if command was list, get list and return it
|
||||
if( list ) {
|
||||
Serial.println( "LIST" );
|
||||
response = lst();
|
||||
Serial.println( response );
|
||||
}
|
||||
// on the second space
|
||||
} else if( amnt == 2 ) {
|
||||
// capture everything after third word
|
||||
String argument = command.substring( i + 1, len );
|
||||
// if user is asking ( should make argument one word )
|
||||
if( ask ) {
|
||||
// if user asks for color
|
||||
if( argument == "color" ) {
|
||||
response = color; // set response to current color
|
||||
// if user wants status
|
||||
} else if( argument == "status" ) {
|
||||
// if status is true, led is off, else on
|
||||
response = statusRGB ? "off" : "on";
|
||||
} else { // doesn't want status or color, arg unknown
|
||||
response = "field unrecognized";
|
||||
}
|
||||
// if user is telling ( some args can be one word )
|
||||
} else if( tell ) {
|
||||
// only args can be on and off
|
||||
if( argument == "off" || argument == "on" ) {
|
||||
// set status, and set return string
|
||||
statusRGB = argument == "off";
|
||||
response = argument;
|
||||
} else { // if user didn't tell on or off
|
||||
// print argument
|
||||
Serial.print( "argument: " );
|
||||
Serial.println( argument );
|
||||
// capture number of letters in argument
|
||||
int arglen = argument.length();
|
||||
// bool to keep track of if a space was seen
|
||||
// if there was no space seen, arg is very incorrect
|
||||
bool space = false;
|
||||
// iterate over characters in argument
|
||||
for( int j = 0; j < arglen; j++ ) {
|
||||
// if letter is a space
|
||||
if( argument[j] == ' ' ) {
|
||||
// mark space as true
|
||||
space = true;
|
||||
// grab everything before the space, subcommand
|
||||
String subcom = argument.substring( 0, j );
|
||||
// grab everything after the space, subargument
|
||||
String subarg = argument.substring( j + 1, arglen );
|
||||
|
||||
// if subcommand is color
|
||||
if( subcom == "color" ) {
|
||||
// and subarg matches a supported color
|
||||
if( subarg == "red" || subarg == "magenta"
|
||||
|| subarg == "blue" || subarg == "cyan"
|
||||
|| subarg == "green" || subarg == "yellow"
|
||||
|| subarg == "white" ) {
|
||||
// set color to the input color
|
||||
color = subarg;
|
||||
// set response to the same color
|
||||
response = color;
|
||||
// turn on led
|
||||
statusRGB = false;
|
||||
} else { // if color isn't supported
|
||||
// say so, don't change anything
|
||||
response = "argument unrecognized";
|
||||
}
|
||||
// if subcommand is for status
|
||||
} else if( subcom == "status" ) {
|
||||
// if subarg is for either on or off
|
||||
if( subarg == "off" || subarg == "on" ) {
|
||||
// set status to input
|
||||
statusRGB = subarg == "off";
|
||||
// if status is true, led is off, else on
|
||||
response = statusRGB ? "off" : "on";
|
||||
} else { // if subarg isn't on or off
|
||||
// say so, don't change anything
|
||||
response = "argument unrecognized";
|
||||
}
|
||||
} else { // command is neither color nor status
|
||||
// say so, don't change anything
|
||||
response = "command unrecognized";
|
||||
}
|
||||
// break out once space is found
|
||||
// no need to keep iterating once space is found
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if space was never found, argument was very wrong
|
||||
if( !space ) {
|
||||
// say so, don't change anything
|
||||
response = "/" + argument + "/ invalid";
|
||||
}
|
||||
}
|
||||
} else { // if user is neither asking nor telling
|
||||
// also not list
|
||||
// say so, don't change anything
|
||||
response = "command unrecognized";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
refresh(); // update the led
|
||||
// print response
|
||||
Serial.print( "resp IN:" );
|
||||
Serial.println( response );
|
||||
return response; // return response
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Loop
|
||||
// ===================================================================
|
||||
void loop() {
|
||||
// returns client one exists
|
||||
WiFiClient client = server.available();
|
||||
|
||||
if( client ) { // if server.available() finds client
|
||||
if( client.connected() ) { // client has connected
|
||||
Serial.println( "Client Connected" );
|
||||
}
|
||||
|
||||
String response = ""; // init response variable
|
||||
|
||||
// for as long as client stays connected
|
||||
while( client.connected() ) {
|
||||
// for as long as there are bytes to be read, read em
|
||||
while( client.available() > 0 ) {
|
||||
// read data from the connected client
|
||||
String command = client.readStringUntil( '\n' );
|
||||
//digitalWrite( pinBI, statusBI = !statusBI );
|
||||
Serial.println( command ); // print to serial monitor
|
||||
|
||||
int count = 0;
|
||||
int previous = 0; // keep track of spaces
|
||||
// iterate over string
|
||||
for( int i = 0; i <= command.length(); i++ ) {
|
||||
// if char is space or end of string
|
||||
if( command[i] == ' ' || command[i] == '\0') {
|
||||
// print each word in command (except last one)
|
||||
Serial.println( command.substring( previous, i ) );
|
||||
if( count == 1 ) { // check second word for name
|
||||
// if command was meant for me...
|
||||
if( command.substring( previous, i ) == NAME ) {
|
||||
// parse command
|
||||
response = prse( command );
|
||||
Serial.print( "resp OUT:" );
|
||||
Serial.println( response );
|
||||
//response = "not just yet";
|
||||
} else { // tell user message doesn't belong here
|
||||
// this shouldn't be possible, but
|
||||
response = "node mismatch";
|
||||
}
|
||||
// once response is set, leave loop and send
|
||||
break;
|
||||
}
|
||||
// set previous to AFTER space, to capture ONLY the word
|
||||
previous = i + 1;
|
||||
count++; // increment count of spaces
|
||||
}
|
||||
}
|
||||
// print rest of message to monitor
|
||||
Serial.println( command.substring( previous, command.length() ) );
|
||||
client.println( response ); // send entire command to client
|
||||
}
|
||||
}
|
||||
client.stop(); // stop client when done reading
|
||||
Serial.println( "Client disconnected" ); // print
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
@@ -0,0 +1,4 @@
|
||||
status ^v
|
||||
on
|
||||
off
|
||||
list v
|
||||
+6
-2
@@ -1,7 +1,11 @@
|
||||
color ^v
|
||||
red
|
||||
green
|
||||
blue
|
||||
cyan
|
||||
green
|
||||
magenta
|
||||
red
|
||||
white
|
||||
yellow
|
||||
status ^v
|
||||
on
|
||||
off
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
piled|:1212
|
||||
led2|:1203
|
||||
led|192.168.1.69:1210
|
||||
range|192.168.1.30:1211
|
||||
@@ -0,0 +1,364 @@
|
||||
// ===================================================================
|
||||
// Auth: Alex
|
||||
// File: led.ino
|
||||
// Revn: 07-27-2022 1.0
|
||||
// Func: End node, to run on ESP8266. Operate as server, process
|
||||
// incoming messages, react to them, send responses
|
||||
//
|
||||
// TODO: incorporate interrupt example for builtin led
|
||||
// update to match lst()
|
||||
// ===================================================================
|
||||
// CHANGE LOG
|
||||
// -------------------------------------------------------------------
|
||||
// 07-25-2022: pulled from led.ino
|
||||
// 07-26-2022: added /fill/ and units to /fill/ and /dist/
|
||||
// made distance calc values into constants
|
||||
// comments
|
||||
// rewrote lst() a little bit
|
||||
// 07-27-2022: made quick getDepth() function to fix bad unit bug
|
||||
// filled in /tell/
|
||||
// commented
|
||||
//
|
||||
// ===================================================================
|
||||
|
||||
// ESP8266 version of Wifi.h
|
||||
// API Documentation located at:
|
||||
//
|
||||
// Pinout located at:
|
||||
// https://microcontrollerslab.com/led-blinking-using-esp8266-nodemcu/#ESP8266_Pinout_in_Arduino_IDE
|
||||
#include <ESP8266WiFi.h>
|
||||
// documentation at
|
||||
// https://arduino.cc/reference/en/libraries/esp8266timerinterrupt/
|
||||
#include <ESP8266TimerInterrupt.h>
|
||||
|
||||
// real shit, not certain why this is important
|
||||
#define SendKey 0 // button to send data Flash BTN on NodeMCU
|
||||
#define Vs 0.034 // speed of sound [cm/s]
|
||||
#define CMtoIN 0.393701 // convert cm to inches [in/cm]
|
||||
|
||||
int port = 1211; // port of server
|
||||
WiFiServer server(port);
|
||||
|
||||
IPAddress self( 192, 168, 1, 30 ); // ip address of self
|
||||
IPAddress gate( 192, 168, 1, 1 ); // ip address of gateway
|
||||
IPAddress subn( 255, 255, 0, 0 ); // subnet mask
|
||||
IPAddress pDNS( 8, 8, 8, 8 ); // primary DNS server ip
|
||||
IPAddress sDNS( 8, 8, 4, 4 ); // secondary DNS server ip
|
||||
|
||||
// credentials for WiFi Network
|
||||
const char *ssid = "waystation";
|
||||
const char *password = "homophobiaR0X";
|
||||
|
||||
// pin definitions
|
||||
int trig = 10; // GPIO10 --> SDD3 on the board
|
||||
int echo = 9; // GPIO9 --> SDD2 on the board
|
||||
|
||||
// state variables
|
||||
// permanently set to [cm]
|
||||
int depth = 30; // depth of cat food container [cm]
|
||||
bool inch = false; // keep track of units
|
||||
String NAME = "range"; // variable to semi-hardcode program name
|
||||
|
||||
// ===================================================================
|
||||
// Power on setup
|
||||
// ===================================================================
|
||||
void setup() {
|
||||
// this really dumb fucking board is active low, I am fucking weeping
|
||||
|
||||
// init rgb led pins as output
|
||||
pinMode( trig, OUTPUT );
|
||||
pinMode( echo, INPUT );
|
||||
|
||||
Serial.begin( 115200 ); // board works at 115,200 [baud]
|
||||
pinMode( SendKey, INPUT_PULLUP ); // Btn to send data (NMC NMM)
|
||||
|
||||
WiFi.mode( WIFI_STA ); // set mode to station
|
||||
// set static ip address ( only way it would let me do it )
|
||||
WiFi.config( self, gate, subn, pDNS, sDNS );
|
||||
WiFi.begin( ssid, password ); // connect to wifi
|
||||
|
||||
// Serial.prints all considered verbose, because you can only see
|
||||
// them if you're trying to
|
||||
// wait for connection
|
||||
Serial.println( "Connecting to Wifi" );
|
||||
// iterate until connected
|
||||
while( WiFi.status() != WL_CONNECTED ) {
|
||||
delay( 1000 );
|
||||
Serial.print( "." );
|
||||
}
|
||||
|
||||
// print connection status
|
||||
Serial.println();
|
||||
Serial.print( "Connected to " );
|
||||
Serial.println( ssid );
|
||||
|
||||
server.begin(); // bring server online
|
||||
// print server address
|
||||
Serial.print( "On at: " );
|
||||
Serial.print( WiFi.localIP() );
|
||||
Serial.print( ":" );
|
||||
Serial.println( port );
|
||||
|
||||
}
|
||||
|
||||
|
||||
String lst() {
|
||||
//craft list string and return
|
||||
String resp = "";
|
||||
|
||||
resp = resp + "dist v\n";
|
||||
resp = resp + " fill v\n";
|
||||
resp = resp + " depth ^v\n";
|
||||
resp = resp + " /int/\n";
|
||||
resp = resp + " unit ^v\n";
|
||||
resp = resp + " in[ch]\n";
|
||||
resp = resp + " cm";
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
int getDist() {
|
||||
long duration, distance;
|
||||
|
||||
digitalWrite( trig, LOW ); // init pin low
|
||||
delayMicroseconds( 2 ); // probably not exactly necessary
|
||||
digitalWrite( trig, HIGH ); // start trigger
|
||||
delayMicroseconds( 10 ); // hold a little bit
|
||||
digitalWrite( trig, LOW ); // end trigger
|
||||
|
||||
// get time until pulse in?
|
||||
duration = pulseIn( echo, HIGH );
|
||||
Serial.print( "duration (raw): " );
|
||||
Serial.println( duration );
|
||||
|
||||
Serial.print( "half TOF: " );
|
||||
Serial.println( duration / 2 );
|
||||
// calculate distance from time of flight (TOF)
|
||||
// duration / 2 -> TOF is there and back, get there
|
||||
// * 0.034 -> cm / us
|
||||
distance = ( duration / 2 ) * Vs;
|
||||
|
||||
Serial.print( "dist: " );
|
||||
Serial.println( distance );
|
||||
|
||||
Serial.print( "string: " );
|
||||
Serial.println( String( distance ) );
|
||||
|
||||
return distance;
|
||||
}
|
||||
|
||||
|
||||
String getDepth() {
|
||||
// if units are inches, convert, else scale by 1
|
||||
int deepness = inch ? depth * CMtoIN : depth;
|
||||
// convert to string
|
||||
String response = String( deepness );
|
||||
// append correct units
|
||||
response += inch ? " [in]" : " [cm]";
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
String prse( String command ) {
|
||||
int amnt = 0; // keep track of amount of spaces
|
||||
int len = command.length(); // capture length
|
||||
|
||||
// quick variables to keep track of command
|
||||
bool ask = false;
|
||||
bool tell = false;
|
||||
bool list = false;
|
||||
|
||||
// init failure string
|
||||
String response = "error: command unrecognized";
|
||||
|
||||
// iterate over each letter of incoming message
|
||||
for( int i = 0; i < command.length(); i++ ) {
|
||||
// when letter is space...
|
||||
if( command[i] == ' ' ) {
|
||||
amnt++; // increment count for number of spaces
|
||||
// on the first space
|
||||
if( amnt == 1 ) {
|
||||
// print first command
|
||||
Serial.print( "ask/tell: " );
|
||||
Serial.println( command.substring( 0, i ) );
|
||||
// snatch bools for various commands
|
||||
ask = command.substring( 0, i ) == "ask";
|
||||
tell = command.substring( 0, i ) == "tell";
|
||||
list = command.substring( 0, i ) == "list";
|
||||
|
||||
// print bools
|
||||
Serial.println( ask );
|
||||
Serial.println( tell );
|
||||
Serial.println( list );
|
||||
|
||||
// seemed hacky but it fuckin works
|
||||
// if command was list, get list and return it
|
||||
if( list ) {
|
||||
Serial.println( "LIST" );
|
||||
response = lst();
|
||||
Serial.println( response );
|
||||
}
|
||||
// on the second space
|
||||
} else if( amnt == 2 ) {
|
||||
// capture everything after third word
|
||||
String argument = command.substring( i + 1, len );
|
||||
// if user is asking ( should make argument one word )
|
||||
if( ask ) {
|
||||
// get distance before doing anything
|
||||
// not always necessary, but isn't resource intensive
|
||||
int distance = getDist();
|
||||
if( argument == "dist" ) { // user wants dist
|
||||
// if units are inches, convert, else scale by 1
|
||||
distance *= inch ? CMtoIN : 1;
|
||||
response = String( distance ); // set return var
|
||||
// append correct units
|
||||
response += inch ? " [in]" : " [cm]";
|
||||
} else if( argument == "fill" ) { // user wants fill
|
||||
// if distance is smaller than depth, distance / depth will
|
||||
// be 0, because int. scale up before taking fraction to find
|
||||
// percent empty space
|
||||
// sub from 100 to find the actual fill percent
|
||||
distance = 100 - ( distance * 100 ) / depth;
|
||||
response = String( distance ) + "%"; // append unit
|
||||
} else if( argument == "depth" ) { // user wants depth
|
||||
response = getDepth();
|
||||
} else if( argument == "unit" ) { // user wants units
|
||||
response = inch ? "[in]" : "[cm]";
|
||||
} else { // doesn't want status or color, arg unknown
|
||||
response = "field unrecognized";
|
||||
}
|
||||
// node doesn't work with tell
|
||||
} else if( tell ) {
|
||||
response = "/tell/ is under construction";
|
||||
// capture number of letters in argument
|
||||
int arglen = argument.length();
|
||||
// bool to keep track of if a space was seen
|
||||
// if there was no space seen, arg is very incorrect
|
||||
bool space = false;
|
||||
// iterate over characters in argument
|
||||
for( int j = 0; j < arglen; j++ ) {
|
||||
// if letter is a space
|
||||
if( argument[j] == ' ' ) {
|
||||
// mark space as true
|
||||
space = true;
|
||||
// grab everything before the space, subcommand
|
||||
String subcom = argument.substring( 0, j );
|
||||
// grab everything after the space, subargument
|
||||
String subarg = argument.substring( j + 1, arglen );
|
||||
|
||||
// user is redefining food depth
|
||||
if( subcom == "depth" ) {
|
||||
if( subarg.toInt() != 0 ) {
|
||||
depth = subarg.toInt();
|
||||
depth /= inch ? CMtoIN : 1;
|
||||
response = getDepth();
|
||||
} else {
|
||||
response = "depth argument must be an int";
|
||||
}
|
||||
// user is redefining units
|
||||
} else if( subcom == "unit" ) {
|
||||
// check if subarg is valid
|
||||
if( subarg == "cm" ) {
|
||||
inch = false; // false for cm
|
||||
response = getDepth();
|
||||
} else if( subarg == "in" || subarg == "inch"
|
||||
|| subarg == "inches" ){
|
||||
inch = true; // true for inches
|
||||
response = getDepth();
|
||||
} else { // if input is invalid, don't change
|
||||
// say so, don't change anything
|
||||
response = "argument unrecognized";
|
||||
}
|
||||
} else { // command is neither depth nor unit
|
||||
// say so, don't change anything
|
||||
response = "command unrecognized";
|
||||
}
|
||||
// break out once space is found
|
||||
// no need to keep iterating once space is found
|
||||
break;
|
||||
}
|
||||
}
|
||||
// if space was never found, argument was very wrong
|
||||
if( !space ) {
|
||||
// say so, don't change anything
|
||||
response = "/" + argument + "/ invalid";
|
||||
}
|
||||
} else { // if user is neither asking nor telling
|
||||
// also not list
|
||||
// say so, don't change anything
|
||||
response = "command unrecognized";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Serial.print( "resp IN:" );
|
||||
Serial.println( response );
|
||||
return response; // return response
|
||||
}
|
||||
|
||||
|
||||
// ===================================================================
|
||||
// Loop
|
||||
// ===================================================================
|
||||
void loop() {
|
||||
// returns client one exists
|
||||
WiFiClient client = server.available();
|
||||
|
||||
if( client ) { // if server.available() finds client
|
||||
if( client.connected() ) { // client has connected
|
||||
Serial.println( "Client Connected" );
|
||||
}
|
||||
|
||||
String response = ""; // init response variable
|
||||
|
||||
// for as long as client stays connected
|
||||
while( client.connected() ) {
|
||||
// for as long as there are bytes to be read, read em
|
||||
while( client.available() > 0 ) {
|
||||
// read data from the connected client
|
||||
String command = client.readStringUntil( '\n' );
|
||||
//digitalWrite( pinBI, statusBI = !statusBI );
|
||||
Serial.println( command ); // print to serial monitor
|
||||
|
||||
int count = 0;
|
||||
int previous = 0; // keep track of spaces
|
||||
// iterate over string
|
||||
for( int i = 0; i <= command.length(); i++ ) {
|
||||
// if char is space or end of string
|
||||
if( command[i] == ' ' || command[i] == '\0') {
|
||||
// print each word in command (except last one)
|
||||
Serial.println( command.substring( previous, i ) );
|
||||
if( count == 1 ) { // check second word for name
|
||||
// if command was meant for me...
|
||||
if( command.substring( previous, i ) == NAME ) {
|
||||
// parse command
|
||||
response = prse( command );
|
||||
Serial.print( "resp OUT:" );
|
||||
Serial.println( response );
|
||||
//response = "not just yet";
|
||||
} else { // tell user message doesn't belong here
|
||||
// this shouldn't be possible, but
|
||||
response = "node mismatch";
|
||||
}
|
||||
// once response is set, leave loop and send
|
||||
break;
|
||||
}
|
||||
// set previous to AFTER space, to capture ONLY the word
|
||||
previous = i + 1;
|
||||
count++; // increment count of spaces
|
||||
}
|
||||
}
|
||||
// print rest of message to monitor
|
||||
Serial.println( command.substring( previous, command.length() ) );
|
||||
client.println( response ); // send entire command to client
|
||||
}
|
||||
}
|
||||
client.stop(); // stop client when done reading
|
||||
Serial.println( "Client disconnected" ); // print
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
+131
-23
@@ -1,11 +1,12 @@
|
||||
// =============================================================================
|
||||
// Auth: Alex Celani
|
||||
// File: sentinel.go
|
||||
// Revn: 06-27-2022 1.3
|
||||
// Revn: 07-14-2022 3.0
|
||||
// Func: Receive message, determine recipient, forward, get response,
|
||||
// forward back
|
||||
//
|
||||
// TODO:
|
||||
// TODO: add time flag
|
||||
// use tail command line args to send single message and quit
|
||||
// =============================================================================
|
||||
// CHANGE LOG
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -19,6 +20,13 @@
|
||||
// 06-26-2022: refined a new route() function to check for destination
|
||||
// validity
|
||||
// 06-27-2022: added flag package
|
||||
// 07-05-2022: added support for kill messages
|
||||
//*07-06-2022: added support for mulitplexing multiple endpoints
|
||||
// so long as their name and ip is in /nodes/ file
|
||||
// 07-11-2022: added solo mode and flag
|
||||
// changed how list works
|
||||
// 07-12-2022: comments
|
||||
//*07-14-2022: changed input/output prompt to arrow
|
||||
//
|
||||
// =============================================================================
|
||||
|
||||
@@ -31,9 +39,20 @@ import (
|
||||
"fmt" // Println, Fprintf
|
||||
"strings" // ToLower, ToUpper
|
||||
"flag" // Parse, String, Bool
|
||||
"io/ioutil" // ReadFile
|
||||
"bufio" // input()
|
||||
)
|
||||
|
||||
|
||||
// quick function to take user input
|
||||
func input( ps1 string ) string {
|
||||
fmt.Print( ps1 ) // print prompt
|
||||
scanner := bufio.NewScanner( os.Stdin ) // link to stdin
|
||||
scanner.Scan() // pull data
|
||||
return strings.ToLower( scanner.Text() ) // return lower text
|
||||
}
|
||||
|
||||
|
||||
// quick error checking
|
||||
func check( err error ){
|
||||
// if user checks an error, it better be nil
|
||||
@@ -46,16 +65,17 @@ func check( err error ){
|
||||
|
||||
|
||||
// read the given message and route to the right endpoint
|
||||
func route( recv []string ) bool {
|
||||
return recv[1] == "led" // only option right now is led
|
||||
func route( recv []string ) string {
|
||||
ip := nodes[recv[1]] // get correlating ip to given node name
|
||||
return ip
|
||||
}
|
||||
|
||||
|
||||
// function to send message to third party and get response
|
||||
func send( toSend string ) string {
|
||||
func send( toSend, ip string ) string {
|
||||
|
||||
// "resolve" ip & host according to TCP rules
|
||||
tcpAddr, err := net.ResolveTCPAddr( "tcp", *ip )
|
||||
tcpAddr, err := net.ResolveTCPAddr( "tcp", ip )
|
||||
check( err ) // check error
|
||||
|
||||
// "dial" ( establish connection ) to destination ip & port
|
||||
@@ -81,6 +101,64 @@ func send( toSend string ) string {
|
||||
}
|
||||
|
||||
|
||||
// parse input, send to node, return response
|
||||
func forward( recv string ) string {
|
||||
|
||||
// break commands into words
|
||||
keywords := strings.Split( recv, " " )
|
||||
length := len( keywords ) // store length for later use
|
||||
|
||||
// declare return variable
|
||||
var resp string
|
||||
|
||||
if length == 1 { // if length of input is only 1
|
||||
if keywords[0] == "list" { // command better be /list/
|
||||
var i int = 0 // var to keep track of iterations
|
||||
// iterate over keys in map to get list of node names
|
||||
for name, _ := range nodes {
|
||||
if i != 0 {
|
||||
// do not prepend spaces to first node
|
||||
resp = resp + " "
|
||||
}
|
||||
resp = resp + name + "\n" // append node name
|
||||
i++ // keep track of iterations
|
||||
}
|
||||
resp = resp[:len( resp ) - 1] // remove last newline
|
||||
} else { // command is not /list/, ergo
|
||||
// not supported
|
||||
resp = "command unrecognized"
|
||||
}
|
||||
} else if length > 1 { // command is more than one word
|
||||
// user wants a comprehensive list of nodes and fields
|
||||
if keywords[0] == "list" && keywords[1] == "-v" {
|
||||
// iterate over all nodes
|
||||
for name, addr := range nodes {
|
||||
// add name, ip, newline, and justifying spaces
|
||||
resp = resp + name + " --> " + addr + "\n "
|
||||
// send command /list/ to node
|
||||
resp = resp + send( "list " + name, addr )
|
||||
// add newline and justifying spaces
|
||||
resp = resp + "\n "
|
||||
}
|
||||
// remove trailing newline and spaces
|
||||
resp = resp[:len( resp ) - 4]
|
||||
} else { // user wants a different command
|
||||
ip := route( keywords ) // find appropriate ip
|
||||
if ip == "" { // ip not found, node DNE
|
||||
resp = "node unrecognized" // print error
|
||||
} else { // node does exist
|
||||
// send message to node, get response
|
||||
resp = send( recv, ip )
|
||||
}
|
||||
}
|
||||
} else { // length of command was 0
|
||||
resp = "command unrecognized"
|
||||
}
|
||||
|
||||
return resp // return response
|
||||
}
|
||||
|
||||
|
||||
// function to handle incoming connections
|
||||
func handleClient( conn net.Conn ) {
|
||||
defer conn.Close() // barring any error, still close connection
|
||||
@@ -103,46 +181,76 @@ func handleClient( conn net.Conn ) {
|
||||
fmt.Println( "recv: ", recv )
|
||||
}
|
||||
|
||||
keywords := strings.Split( recv, " " )
|
||||
|
||||
// parse the input in some way
|
||||
var resp string // declare response variable
|
||||
if route( keywords ) { // is destination valid?
|
||||
resp = send( recv ) // send message and get response
|
||||
// if user wants a list of endpoints
|
||||
} else if keywords[1] == "list" {
|
||||
resp = "led" // return list of endpoints
|
||||
}
|
||||
|
||||
if *verbose {
|
||||
fmt.Println( "node: ", resp ) // print response
|
||||
}
|
||||
// parse input, send out to node, get response
|
||||
resp := forward( recv )
|
||||
|
||||
// write that response back to original client
|
||||
_, err = conn.Write( []byte( resp ) )
|
||||
if err != nil { // erroring on write will simply leave the
|
||||
return // function so it can start again later
|
||||
}
|
||||
|
||||
if resp == "kill" { // if received kill message
|
||||
os.Exit( 1 ) // kill process
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// function to read in initialization data for nodes
|
||||
func initNodes() {
|
||||
|
||||
// open and read config file
|
||||
file, err := ioutil.ReadFile( "nodes" )
|
||||
check( err ) // error checking on read
|
||||
|
||||
// cast file to string, split string over newlines
|
||||
node := strings.Split( string( file ), "\n" )
|
||||
|
||||
for i, kvp := range node { // iterate over lines
|
||||
// XXX for whatever reason, the EOF is seen as a newline?
|
||||
// so this only works for all but the "last line"
|
||||
if i != len( node ) - 1 {
|
||||
// kvp is delimited by a bar, split over bar
|
||||
// key is the name of the endpoint
|
||||
// ip is the ip of the same endpoint
|
||||
nameip := strings.Split( kvp, "|" )
|
||||
// insert kvp into map
|
||||
nodes[nameip[0]] = nameip[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var ( // declare global variables for flag
|
||||
ip *string
|
||||
self *string
|
||||
verbose *bool
|
||||
solo *bool
|
||||
)
|
||||
|
||||
// declare global variable to contain names and ips of endpoints
|
||||
var nodes = make( map[string]string )
|
||||
|
||||
|
||||
func main() {
|
||||
|
||||
// get flags for verbose, self ip and destination ip
|
||||
verbose = flag.Bool( "v", false, "flag to print extra info" )
|
||||
ip = flag.String( "ip", "192.168.1.169:1202", "end node ip and port" )
|
||||
self = flag.String( "self", ":1201", "port of self" )
|
||||
solo = flag.Bool( "s", false, "run sentinel in solo mode" )
|
||||
flag.Parse() // parse
|
||||
|
||||
// "resolve" ip & host according to TCP rules
|
||||
// read /nodes/ file and populate nodes map
|
||||
initNodes()
|
||||
|
||||
if *solo { // if user requested stand-alone action
|
||||
for { // iterate forever ( until user quits )
|
||||
in := input( "-> " ) // print prompt, take input
|
||||
resp := forward( in ) // forward directly to node
|
||||
fmt.Println( "<-", resp ) // print response
|
||||
}
|
||||
}
|
||||
|
||||
tcpAddr, err := net.ResolveTCPAddr( "tcp", *self )
|
||||
check( err ) // check error
|
||||
|
||||
|
||||
Reference in New Issue
Block a user