Skip to content
Snippets Groups Projects

Arduino networking code

Merged Kyrre Ness Sjobaek requested to merge arduinoServer into master
Compare and
4 files
+ 1215
0
Compare changes
  • Side-by-side
  • Inline
Files
4
+ 899
0
/*
* Server for controling 4D robot for moving samples in/out of the beam at CLEAR.
* Access via telnet-like interface at port 23.
*
* Example for accessing over text interface:
* nc 192.168.1.31 23
* Netcat (nc) is the best client: it is a clean TCP client,
* which makes no attempts to negotiate anything.
*
* Kyrre Ness Sjobak, 24 April 2021
* University of Oslo / CERN
*
* Inspired by PositionGaugeServer, also in use at CLEAR.
*/
#include <Arduino.h>
#include <SPI.h>
#include <Ethernet.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <Servo.h>
//This file holds all the configurations
// to be modified for deployment
#include "4DrobotServer_config.h"
// ***** GLOBAL VARIABLES ***********************
// Sockets for TCP communications
EthernetServer telnet_socket(telnet_port);
EthernetClient telnet_connection[telnet_numConnections];
// ASCII IO Buffers
// buffCount is the number of elements = idx of first free element
char telnet_buff[telnet_numConnections][telnet_bufflen];
size_t telnet_buffCount[telnet_numConnections];
char serial_buff[telnet_bufflen];
size_t serial_buffCount;
char output_buff[output_bufflen];
size_t output_buffCount;
// Temperature sensor access & buffers
OneWire temp_oneWire(temp_oneWire_pin);
DallasTemperature temp_sensors(&temp_oneWire);
float temp_data[temp_numSensors]; //[degC]
unsigned long temp_update_prev = 0; //[ms]
// Sample grabber servo
Servo grabber_servo;
bool grabber_go = false;
int grabber_pos = grabber_closed; //Assumed initial position
int grabber_goto = grabber_closed;
// Stepper motors
bool stepper_go = false; //Move a stepper on the next loop?
uint8_t stepper_go_zero = false; //Move-to-position (false) or
// move-to-switchLOW (true)?
uint8_t stepper_go_axis = 0; //Which stepper to move?
int stepper_goto = 0; //[steps] Target position
// (used if stepper_go_zero==false)
int stepper_pos[] = {0,0,0}; //Current stepper position
bool stepper_mode_absolute[] = {false,false,false}; //Do we have a valid zeroing?
// If true, pos represents the absolute
// position of that axis
// ***** CODE ***********************************
void setup() {
//Serial setup, for debugging
Serial.begin(9600);
// wait for serial port to connect. Needed for native USB port only
int serialCounter=0;
while (!Serial) {
//However only wait for 1 second before giving up,
// so that it can work also when not connected to USB
delay(100);
serialCounter++;
if (serialCounter > 10) break;
}
Serial.print('\n');
Serial.print("4DrobotServer initializing...\n");
//Network setup
Serial.print("Starting networking...\n");
#ifdef USE_DHCP
Ethernet.begin(mac);
#else
Ethernet.begin(mac, ip, myDns, gateway, subnet);
#endif
// Check for Ethernet hardware present
if (Ethernet.hardwareStatus() == EthernetNoHardware) {
Serial.println("Ethernet shield was not found. Sorry, can't run without hardware. :(");
while (true) {
// Do nothing, no point running without Ethernet hardware
// TODO: Not actually true, we could also run with just serial...
delay(1);
}
}
while(true)
if (Ethernet.linkStatus() == LinkOFF) {
Serial.print("Ethernet cable is not connected\n");
}
else {
Serial.print("Ethernet cable connected / status unknown\n");
break;
}
byte buffMAC[6];
Serial.print("MAC address: ");
Ethernet.MACAddress(buffMAC);
for (byte octet=0; octet<6;octet++) {
Serial.print(buffMAC[octet],HEX);
if(octet < 5) {
Serial.print(":");
}
}
Serial.print('\n');
Serial.print("IP address: "); Serial.print(Ethernet.localIP()); Serial.print('\n');
Serial.print("DNS address: "); Serial.print(Ethernet.dnsServerIP()); Serial.print('\n');
Serial.print("Gateway address: "); Serial.print(Ethernet.gatewayIP()); Serial.print('\n');
Serial.print("Subnet: "); Serial.print(Ethernet.subnetMask()); Serial.print('\n');
//Server setup
telnet_socket.begin();
for (uint8_t i=0; i<telnet_numConnections; i++) {
memset(telnet_buff[i], '\0', sizeof(telnet_buff[i]));
telnet_buffCount[i] = 0;
}
memset(serial_buff, '\0', sizeof(serial_buff));
serial_buffCount = 0;
memset(output_buff, '\0', sizeof(output_buff));
output_buffCount = 0;
//Initialize temperature sensors to something nonsensical
for (size_t i=0; i<temp_numSensors; i++) {
temp_data[i] = -500.0f; //(it's float not Farenheit)
}
//Sanity check grabber config
if (not (grabber_open >= grabber_min && grabber_open <= grabber_max)) {
Serial.print(F("Grabber config error; grabber_open outside of legal range\n"));
while(true) {
delay(1);
}
}
if (not (grabber_closed >= grabber_min && grabber_closed <= grabber_max)) {
Serial.print(F("Grabber config error; grabber_closed outside of legal range\n"));
while(true) {
delay(1);
}
}
//Serial is ready for input!
Serial.print(F("@ INFO MSG Say 'HELP' to get started\n"));
Serial.print("$\n");
}
//Run all the "programs" in order
void loop() {
// Run actuators (one at a time)
servo_control();
stepper_control();
// Update sensor readings
temperatures_update();
// Communicate
telnet_server();
// Housekeeping
#ifdef USE_DHCP
DHCPhousekeeping();
#endif
}
//Program for refreshing the temperatures
void temperatures_update() {
//Poll temperature sensors no faster than the given interval
//If too short, some sensors may heat up and give inaccurate results
unsigned long thisUpdateTime = millis();
if (not (thisUpdateTime - temp_update_prev >= temp_update_interval)) {
//Not yet
return;
}
temp_update_prev = thisUpdateTime;
//Refresh temp_data
#ifndef DUMMY_TEMP
temp_sensors.requestTemperatures();
for (size_t i=0; i<temp_numSensors; i++) {
temp_data[i] = temp_sensors.getTempCByIndex(i);
}
#else
for (size_t i=0; i< temp_numSensors; i++) {
temp_data[i] = random(-1000L,15000L)/100.0f;
}
#endif
}
//Program for controlling the servomotor for the grabber
void servo_control() {
if (grabber_go) {
do {
if (grabber_pos < grabber_goto) {
grabber_pos++;
}
else {
grabber_pos--;
}
#ifndef DUMMY_SERVO
grabber_servo.write(grabber_pos);
#else
Serial.print("Grabber to: ");
Serial.print(grabber_pos);
Serial.print('\n');
#endif
delay(grabber_stepWait);
} while (grabber_pos != grabber_goto);
grabber_go = false;
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< GRABBER GO FINISHED\n"));
}
}
void stepper_control() {
if(not stepper_go) {
return;
}
//Check XY interlock
// error if we try to move locked axis
if( (stepper_go_axis != STEPPER_Z) and
( (not stepper_mode_absolute[STEPPER_Z]) or
(stepper_pos[STEPPER_Z] <= stepper_Zpos_unlockXY)
)
) {
//We are trying to move a locked axis
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< STEPPER ERROR XY INTERLOCK\n"));
goto resetGO;
}
//Move!
//Task: Zero an axis
if (stepper_go_zero) {
//Always move in negative direction when zeroing
digitalWrite(stepper_go_axis, stepper_backward[stepper_go_axis]);
//Move until we trigger the low interlock switch
bool onMAX = (digitalRead(stepper_switchMAX_pin[stepper_go_axis]) == stepper_switch_active);
bool onMIN = (digitalRead(stepper_switchMIN_pin[stepper_go_axis]) == stepper_switch_active);
int onLimitCount = 0;
while (not onMIN) {
//Check the other-end switch that we aren't moving in the wrong direction or stuck
if(onMAX) {
onLimitCount++;
}
if(onLimitCount > stepper_onlimit_steps) {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< STEPPER ERROR LIMIT SWITCH\n"));
goto resetGO;
}
//Move (slowly)
digitalWrite(stepper_go_axis,HIGH);
delayMicroseconds(stepper_onTime);
digitalWrite(stepper_go_axis,LOW);
delayMicroseconds(stepper_delay_slow);
stepper_pos[stepper_go_axis] -= 1;
//Poll switches
onMAX = (digitalRead(stepper_switchMAX_pin[stepper_go_axis]) == stepper_switch_active);
onMIN = (digitalRead(stepper_switchMIN_pin[stepper_go_axis]) == stepper_switch_active);
}
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< STEPPER ZERO MOVED "));
char buff[9];
snprintf(buff,sizeof(buff), "%-07d\n",stepper_pos[stepper_go_axis]);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
//Movement to switch completed successfully,
stepper_pos[stepper_go_axis] = 0;
stepper_mode_absolute[stepper_go_axis] = true;
}
//Task: Move to position (either relative or absolute)
else {
int stepping = 0;
if (stepper_goto > stepper_pos[stepper_go_axis]) {
digitalWrite(stepper_go_axis, stepper_forward[stepper_go_axis]);
stepping = 1;
}
else if(stepper_goto < stepper_pos[stepper_go_axis]) {
digitalWrite(stepper_go_axis, stepper_backward[stepper_go_axis]);
stepping = -1;
}
// Note: No 'else' needed; if they are equal, the while loop doesn't iterate.
//Move until goto==pos or we trigger an interlock switch stepper_onlimit_steps times
bool onMAX = (digitalRead(stepper_switchMAX_pin[stepper_go_axis]) == stepper_switch_active);
bool onMIN = (digitalRead(stepper_switchMIN_pin[stepper_go_axis]) == stepper_switch_active);
int onLimitCount = 0;
while (stepper_pos[stepper_go_axis] != stepper_goto) {
//Check limit switches
if(onMAX or onMIN) {
onLimitCount++;
}
if(onLimitCount > stepper_onlimit_steps) {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< STEPPER ERROR LIMIT SWITCH\n"));
goto resetGO;
}
//Move (slowly)
//TODO: Implement acceleration
digitalWrite(stepper_go_axis,HIGH);
delayMicroseconds(stepper_onTime);
digitalWrite(stepper_go_axis,LOW);
delayMicroseconds(stepper_delay_slow);
stepper_pos[stepper_go_axis] += stepping;
//Poll switches
onMAX = (digitalRead(stepper_switchMAX_pin[stepper_go_axis]) == stepper_switch_active);
onMIN = (digitalRead(stepper_switchMIN_pin[stepper_go_axis]) == stepper_switch_active);
}
}
//Reset the flags which tells it where to go
//Can also jump (GOTO) here directly on error
resetGO: //Yep this is a GOTO label.
// Please read XKCD297 & XKCD292
stepper_go = false;
stepper_go_zero = false;
stepper_go_axis = 0;
stepper_goto = 0;
//Message '< STEPPER GO FINISHED AXIS <X/Y/Z/?> POS <POSITION>\n'
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< STEPPER GO FINISHED AXIS "));
if (stepper_go_axis == STEPPER_X) {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("X"));
}
else if(stepper_go_axis == STEPPER_Y) {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("Y"));
}
else if(stepper_go_axis == STEPPER_Z) {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("Z"));
}
else {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("?"));
}
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F(" POS "));
char buff[9];
snprintf(buff,sizeof(buff), "%-07d\n",stepper_pos[stepper_go_axis]);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
return;
}
void telnet_server() {
// Program for running the telnet- and serial communication
//1. Check for new connections
while (true) {
//Loop in case there are multiple new connections
EthernetClient newConnection = telnet_socket.accept();
if (newConnection) {
//Find a new connection slot
for (size_t i=0; i<telnet_numConnections; i++) {
if (!telnet_connection[i]) {
telnet_connection[i] = newConnection;
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< INFO CONN MAKE: "));
IPAddress IP = telnet_connection[i].remoteIP();
char IP_buff[16];
snprintf(IP_buff, sizeof(IP_buff), "%d.%d.%d.%d", IP[0],IP[1],IP[2],IP[3]);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, IP_buff);
snprintf(IP_buff, sizeof(IP_buff), " ON #%-2d\n", i);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, IP_buff);
telnet_connection[i].print(F("@ INFO MSG Say 'HELP' to get started\n"));
telnet_connection[i].print("$\n");
break;
}
}
}
else {
break;
}
}
//2. Check for incoming data (telnet & serial) and buffer it
for (size_t i = 0; i < telnet_numConnections; i++) {
while (telnet_connection[i] &&
telnet_connection[i].connected() &&
telnet_connection[i].available() > 0 ) {
bufferWrite(telnet_buff[i], sizeof(telnet_buff[i]), telnet_buffCount[i], telnet_connection[i].read());
#ifdef PARSER_DEBUG
Serial.print("Got '");
Serial.print(telnet_buff[i][telnet_buffCount[i]-1]);
Serial.print("' = ");
Serial.print((byte)telnet_buff[i][telnet_buffCount[i]-1]);
Serial.print(", pos = ");
Serial.print(telnet_buffCount[i]-1);
Serial.print(", connection = ");
Serial.println(i);
#endif
}
}
while (Serial.available() > 0) {
bufferWrite(serial_buff, sizeof(serial_buff), serial_buffCount, Serial.read());
#ifdef PARSER_DEBUG
Serial.print("Got '");
Serial.print(serial_buff[serial_buffCount-1]);
Serial.print("' = ");
Serial.print((byte)serial_buff[serial_buffCount-1]);
Serial.print(", pos = ");
Serial.print(serial_buffCount-1);
Serial.print(", connection = ");
Serial.println("SERIAL");
#endif
}
//3. Feed the clients & serial with the content of the output buffer
output_buff_flush();
//4. Parse input buffers & notify that we are ready for more
bool keepParsing = true;
for (size_t i = 0; (i < telnet_numConnections) && keepParsing; i++) {
keepParsing = input_parser(telnet_buff[i], sizeof(telnet_buff[i]), telnet_buffCount[i], &(telnet_connection[i]));
}
input_parser(serial_buff, sizeof(serial_buff), serial_buffCount, &(Serial));
//5. Feed the clients & serial with the content of the output buffer generated during parsing
output_buff_flush();
//6. Check for telnet disconnects & handle
for (size_t i = 0; i < telnet_numConnections; i++) {
if ( telnet_connection[i] &&
!telnet_connection[i].connected() ) {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< INFO CONN BREAK: "));
IPAddress IP = telnet_connection[i].remoteIP();
char IP_buff[16];
snprintf(IP_buff, sizeof(IP_buff), "%d.%d.%d.%d", IP[0],IP[1],IP[2],IP[3]);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, IP_buff);
snprintf(IP_buff, sizeof(IP_buff), " ON #%-2d\n", i);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, IP_buff);
telnet_connection[i].stop();
memset(telnet_buff[i],'\0',sizeof(telnet_buff[i]));
telnet_buffCount[i]=0;
}
}
//7. Feed the clients & serial with disconnect messages
output_buff_flush();
}
void output_buff_flush() {
if(output_buffCount) {
for (size_t i = 0; i < telnet_numConnections; i++) {
if (telnet_connection[i] &&
telnet_connection[i].connected() ) {
telnet_connection[i].print(output_buff);
}
}
Serial.print(output_buff);
memset(output_buff, '\0', sizeof(output_buff));
output_buffCount = 0;
}
}
bool input_parser(char* in, const size_t buffSize, size_t& buffCount, Stream* originatingStream) {
// Attempt to parse the commands in the buffer.
// It will only attempt to parse commands that end with a '\n', '\r', or a combination thereof
// Return true to continue parsing lines from the next input buffer,
// or false to tell telnet_parser() to stop parsing now,
// do the cleanup, and let loop() iterate to act on the command that was recieved.
//1. Sanity-check the buffer size
// (Note: Last entry is always a \0, buffSize cannot point to it)
if (buffCount == buffSize-1) {
output_buff_flush();
originatingStream->print(F("@ INFO BUFFER FULL\n"));
originatingStream->print(F("@ INFO BUFFER RESET\n"));
memset(in,'\0', buffSize);
buffCount=0;
// Ready for more
originatingStream->print("$\n");
return true;
}
//2. Look for whole lines & parse each of them in order
char line_buff[buffSize];
memset(line_buff,'\0', sizeof(line_buff));
size_t line_next = 0; //Index of the first valid character
bool lastchar_was_newline = true;
bool gotCommand = false; //Print a `$` when done, after having run commands
bool keepParsing = true; //Switches to false if a command we need to treat
// *right now* comes through (i.e. a motor movement)
for (size_t i = 0; (i<buffCount); i++) {
if(in[i] == '\0') {
//Sanity check: There should be no NULL before the end of the buffer `in`
output_buff_flush();
#ifdef PARSER_DEBUG
Serial.println("Buffer contains NULL");
#endif
originatingStream->print(F("@ INFO BUFFER NULL"));
originatingStream->print(F("@ INFO BUFFER RESET"));
memset(line_buff,'\0', sizeof(line_buff));
memset(in,'\0', buffSize);
line_next = 0;
buffCount = 0;
// Ready for more
originatingStream->print("$\n");
return keepParsing;
}
else if (lastchar_was_newline) {
//Skip repeated newlines, and place line_next correctly
line_next = i;
if(in[i] != '\n' and in[i] != '\r') {
//Double newline or newline at start
lastchar_was_newline = false;
}
//If needed, break the loop here,
// with line_next set corectly for the array shift
if (not keepParsing) {
break;
}
}
else if (in[i] == '\n' or in[i] == '\r') {
//Newline not following start or another newline
memcpy(line_buff, in+line_next, i-line_next);
line_buff[i-line_next]='\0';
keepParsing = parse_line(line_buff);
lastchar_was_newline = true;
//Note: line_next is valid before lastchar_was_newline is false
line_next = i;
memset(line_buff,'\0', sizeof(line_buff));
gotCommand = true;
}
//Else: Just keep counting chars
}
#ifdef PARSER_DEBUG
if (buffCount > 0) {
Serial.println();
Serial.print ("buffCount = ");
Serial.println(buffCount);
Serial.print ("line_next = ");
Serial.println(line_next);
Serial.print ("lastchar_was_newline = ");
Serial.println(lastchar_was_newline);
Serial.print ("keepParsing = ");
Serial.println(keepParsing);
for(size_t i = 0; i < ((buffCount+5) < buffSize ? (buffCount+5) : buffSize); i++) {
Serial.print(i);
Serial.print(i<buffCount ? " '" : " X '");
Serial.print(in[i]);
Serial.print("' = ");
Serial.print((byte)in[i]);
Serial.print(i==line_next ? " <-\n" : "\n");
}
}
#endif
//3. Prepare buffers for next round
if (lastchar_was_newline && buffCount == line_next+1) {
//All data was parsed;
// reset buffer and continue
#ifdef PARSER_DEBUG
Serial.println();
Serial.println("Buffer reset");
#endif
if(not in[line_next+1] == '\0') {
//Internal error!
output_buff_flush();
originatingStream->print(F("@ INFO BUFFER UNTERMINATED\n"));
originatingStream->print(F("@ INFO BUFFER RESET\n"));
//TODO:
// This may indicate a serious bug (array overrun)
// consider resetting the CPU!
}
//All treated, let's reset
memset(line_buff,'\0', sizeof(line_buff));
memset(in,'\0', buffSize);
buffCount = 0;
line_next = 0;
// Ready for more
originatingStream->print("$\n");
}
else if (line_next>0) {
//Some data remains in buffer (whole or partial lines);
// shift the remaining content of `in` to start of `in`
#ifdef PARSER_DEBUG
Serial.println();
Serial.println("Shifting:");
#endif
size_t j = 0;
for(size_t i = line_next; i < buffCount; i++) {
in[j] = in[i];
j += 1;
}
memset(in+j,'\0', buffSize-j);
buffCount = j;
line_next = 0;
#ifdef PARSER_DEBUG
for(size_t i = 0; i < ((buffCount+5) < buffSize ? (buffCount+5) : buffSize); i++) {
Serial.print(i);
Serial.print(i<buffCount ? " '" : " X '");
Serial.print(in[i]);
Serial.print("' = ");
Serial.print((byte)in[i]);
Serial.print(i==line_next ? " <-\n" : "\n");
}
#endif
}
return keepParsing;
}
bool parse_line(char* line_buff) {
//Parse one command line, given in "line_buff".
// Return true to continue parsing lines from the input buffer,
// or false to tell input_parser() to stop parsing lines now,
// do the cleanup, and let loop() iterate to act on the command that was recieved.
// This function assumes that line_buff is correctly NULL terminated.
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, "> ");
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, line_buff);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, '\n');
size_t len = strlen(line_buff);
if (len >= 4 and strncmp(line_buff, "HELP", 4)==0) {
char buff[7];
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< USAGE:\n"));
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< 'HELP' : Get help\n"));
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< 'TEMP' : Get temperature(s)\n"));
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< 'GRABBER STATUS' : Get grabber status\n"));
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< 'GRABBER POS int' : Goto the given position (integer)\n"));
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< 'GRABBER CLOSE' : Close the grabber (goto POS = "));
snprintf(buff, sizeof(buff), "%03d )\n", grabber_closed);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< 'GRABBER OPEN' : Open the grabber (goto POS = "));
snprintf(buff, sizeof(buff), "%03d )\n", grabber_open);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
}
else if (len >= 4 and strncmp(line_buff, "TEMP", 4)==0) {
for (size_t i=0; i<temp_numSensors; i++) {
char buff[23];
float f = temp_data[i];
int tmp_int = (int) (f*100);
int tmp_dec = abs(tmp_int-tmp_int/100*100);
tmp_int = tmp_int/100;
snprintf(buff, sizeof(buff), "< TEMP #%03d %+04d.%02d C\n", i, tmp_int,tmp_dec);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
}
}
else if (len >= 7 and strncmp(line_buff, "GRABBER", 7)==0) {
//Note: Not writing out the sub-options to save RAM
if (len >= 14 and strncmp(line_buff+7, " STATUS", 7)==0) { //'GRABBER STATUS'
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< POS = "));
char buff[5];
snprintf(buff,sizeof(buff), "%03d\n", grabber_pos);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
}
else if (len >= 13 and strncmp(line_buff+7, " CLOSE", 6)==0) { //'GRABBER CLOSE'
if(grabber_go) {
// This should not be possible!
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< ERROR GRABBER ALREADY SET"));
return true;
}
grabber_goto = grabber_closed;
grabber_go = true;
return false;
}
else if (len >= 12 and strncmp(line_buff+7, " OPEN", 5)==0) { //'GRABBER OPEN'
if(grabber_go) {
// This should not be possible!
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< ERROR GRABBER ALREADY SET"));
return true;
}
grabber_goto = grabber_open;
grabber_go = true;
return false;
}
else if (len >= 11 and strncmp(line_buff+7, " POS", 4) == 0) { //'GRABBER POS'
int scanStatus = 0;
if (len < 13) {
//no new POS integer given?
scanStatus = 0;
}
else if (len > 15) {
//More than three digits given?
scanStatus = 0;
}
else if (line_buff[11] != ' ') {
//No separating space?
scanStatus = 0;
}
else {
//Passed sanity checks -> scan!
scanStatus = sscanf(line_buff+12," %d",&grabber_goto);
}
if (scanStatus == 1){
//Got one thing from sscanf()!
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< GRABBER GOTO "));
char buff[5];
snprintf(buff,sizeof(buff), "%03d\n", grabber_goto);
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, buff);
if (grabber_goto >= grabber_min && grabber_goto <= grabber_max) {
grabber_go=true;
return false;
}
else {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< ERROR GRABBER POS OUTSIDE LEGAL RANGE\n"));
grabber_goto = grabber_pos;
}
}
else {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< ERROR GRABBER POS PARSE FAILURE\n"));
}
}
else {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< ERROR GRABBER COMMAND NOT RECOGNIZED\n"));
}
}
else {
bufferWrite(output_buff, sizeof(output_buff), output_buffCount, F("< ERROR COMMAND NOT RECOGNIZED\n"));
}
//Default: Don't halt the parsing
return true;
}
int bufferWrite(char* buff, const size_t buffSize, size_t& buffCount, const char* in) {
/* Add a zero-terminated string to a buffer,
* checking for buffer overruns and
* (SIDE EFFECT!) incrementing the buffCount.
* If the buffer will overrun, truncate the input string.
* Return number of chars written, or return <0 on error.
* If buffer overrun, chars may still be written -> positive return.
*/
size_t len = strlen(in);
int ret = snprintf(buff+buffCount, buffSize-buffCount, in);
buffCount += ret;
return ret;
}
int bufferWrite(char* buff, const size_t buffSize, size_t& buffCount, const char in) {
/* Add a single char to a buffer,
* checking that there is space for it and
* (SIDE EFFECT!) incrementing the buffCount.
* Returns the number of chars written (0 or 1).
*/
if (buffCount == buffSize-1) {
//Pointing at terminating \0,
// no more space!
return 0;
}
else {
buff[buffCount] = in;
buffCount++;
return 1;
}
}
int bufferWrite(char* buff, const size_t buffSize, size_t& buffCount, const __FlashStringHelper *ifsh) {
//Copy flash contents into buffer, otherwise functionally identical to the const char* version.
// Used to save RAM from big hardcoded strings.
//
// Based on ArduinoCore-avr/cores/arduino/Print.cpp->Print::Print(const __FlashStringHelper *ifsh)
// If it doesn't work (future arch), try removing the 'F()' around the strings and comment out this function.
PGM_P p = reinterpret_cast<PGM_P>(ifsh);
size_t n = 0;
while (1) {
char c = pgm_read_byte(p++);
if (c == 0) break;
if (bufferWrite(buff, buffSize, buffCount, c)) n++;
else break;
}
return n;
}
#ifdef USE_DHCP
void DHCPhousekeeping() {
switch (Ethernet.maintain()) {
//output_buff_flush();
case 1:
//renewed fail
Serial.print(F("@ DHCP Error: renewed fail\n"));
break;
case 2:
//renewed success
Serial.print(F("@ DHCP Renewed success\n"));
//print your local IP address:
Serial.print(F("@ DHCP My IP address: "));
Serial.print(Ethernet.localIP());
Serial.print('\n');
break;
case 3:
//rebind fail
Serial.print(F("@ DHCP Error: rebind fail"));
break;
case 4:
//rebind success
Serial.print(F("@ DHCP Rebind success\n"));
//print your local IP address:
Serial.print(F("@ DHCP My IP address: "));
Serial.print(Ethernet.localIP());
Serial.print('\n');
break;
default:
//nothing happened
break;
}
}
#endif
Loading