Reputation: 1965
I am having a problem using a state machine setup. I am knew to these so I am having a problem. So there are some methods here can be ignored. The main problem is for some reason it sends a message for every byte it receives, but I thought Serial.read() clears the buffer after reading. So here is the bulk of the code:
#include "Arduino_Structures.h"
#include <SPI.h>
#include <Ethernet.h>
#include "Time.h"
//GLOBAL DECLARATIONS
enum { STANDBY, SEND, RECEIVE, PROCESS} state = SEND;
enum { STATUS, CONFIG, CURRENT, TIME, VOLTAGE} messageType = STATUS;
char lcv;
char lcv2; //loop control variables
MESSAGE_STRUCT outgoing; //changing outgoing message
MESSAGE_STRUCT incoming; //changing incoming message
OODLES_BLOCK oodles; //oodles of information from the following 5 blocks
STATUS_BLOCK temp_status; //temporary status block
CONFIG_BLOCK temp_config; //temporary config block
CURRENT_BLOCK temp_current; //temporary current block
TIME_BLOCK temp_time; //temporary time block
VOLTAGE_BLOCK temp_voltage; //temporary voltage block
//FUNCATION DECLARATIONS
void sendMsg(MESSAGE_STRUCT* outgoing);
void receiveMsg(MESSAGE_STRUCT* incoming);
//ARDUINO SETUP
void setup()
{
delay(TIMEOUT); //wait for the boards to start up
Serial.begin(BAUD); //set the arduino to be at the Micro-AT baud rate
do
{
lcv = Ethernet.begin(mac); //start etherent board, get IP
}while(!lcv);
}
//ARDUINO LOOP
void loop()
{
switch(state)
{
case STANDBY:
delay(1000);
state = SEND;
break;
case SEND:
switch(messageType)
{
case STATUS:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_STATUS;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case CONFIG:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_CONFIG;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case CURRENT:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_CURRENT;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case TIME:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_TIME;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
case VOLTAGE:
outgoing.start_byte = 0x00;
outgoing.length = 0x00;
outgoing.address_1 = 0xFF;
outgoing.address_2 = 0xFF;
outgoing.code_word = REQUEST_VOLTAGE;
outgoing.checksum = 0;
sendMsg(&outgoing);
state = RECEIVE;
break;
default:
break;
}
break;
case RECEIVE:
if(Serial.available())
{
state = SEND;
receiveMsg(&incoming);
//NEED TO CHECK TO MAKE SURRE START BYTE AND ADDRESS ARE CORRECT
//ALSO THIS IS WHERE I SHOULD CHECK THE CHECKSUM
//ONCE INSIDE SWITCHES NEED TO MAKE SURE THE RESPONSE IS CORRECT
switch(messageType)
{
case STATUS:
//copy information from incoming's data array to the temp_status block so that it retains its structure
memcpy(&temp_status, &incoming.data, sizeof(STATUS_BLOCK));
//these are directly taken from the status block information (Arduino_Structures.h)
oodles.left_source = temp_status.left_source;
oodles.right_source = temp_status.right_source;
oodles.left_overcurrent = temp_status.left_overcurrent;
oodles.right_overcurrent = temp_status.right_overcurrent;
oodles.automatic_transfer = temp_status.ready;
oodles.event_led = temp_status.event;
oodles.bus_type = temp_status.bus_type;
oodles.preferred = temp_status.preferred;
oodles.lockout_installed = temp_status.lockout_installed;
oodles.supervisory_control = temp_status.supervisory_control;
//put the time into the TimeElement then convert it to unix time
TimeElements timeInfo; //will be used (from Time.h library)
timeInfo.Year = temp_status.year;
timeInfo.Month = temp_status.month;
timeInfo.Day = temp_status.day;
timeInfo.Hour = temp_status.hour;
timeInfo.Minute = temp_status.minute;
timeInfo.Second = temp_status.second;
oodles.unix_time = makeTime(timeInfo);
//might want to wipe incoming and outogoing messages to make sure they get correctly rewritten
//messageType = CONFIG;
//state = SEND;
break;
case CONFIG:
break;
case CURRENT:
break;
case TIME:
break;
case VOLTAGE:
break;
}
}
break;
case PROCESS:
break;
}
}
void sendMsg(MESSAGE_STRUCT* message)
{
//brake up integers from MESSAGE_STRUCT to bytes (see intByte in Arduino_Structures.h)
intByte code_word, checksum;
code_word.intValue = message->code_word;
checksum.intValue = message->checksum;
//send byte by byte
Serial.write(message->start_byte);
Serial.write(message->length);
Serial.write(message->address_1);
Serial.write(message->address_2);
Serial.write(code_word.byte1);
Serial.write(code_word.byte2);
for(lcv = 0; lcv < message->length; lcv++)
Serial.write(message->data[lcv]);
Serial.write(checksum.byte1);
Serial.write(checksum.byte2);
}
void receiveMsg(MESSAGE_STRUCT* message)
{
//receive bytes and put them back as integers (see intByte in Arduino_Structures.h)
intByte code_word, checksum;
//receive byte by byte
message->start_byte = Serial.read();
message->length = Serial.read();
message->address_1 = Serial.read();
message->address_2 = Serial.read();
code_word.byte1 = Serial.read();
code_word.byte2 = Serial.read();
message->code_word = code_word.intValue;
for(lcv = 0; lcv < message->length; lcv++)
message->data[lcv] = Serial.read();
checksum.byte1 = Serial.read();
checksum.byte2 = Serial.read();
message->checksum = checksum.intValue;
}
And here is the Serial monitor showing the error, it should only respond once, and if I send it only one byte it responds once. If I send it an 8 byte response as below, it responds 8 times("Answer" means arduino to laptop, and "request" means laptop to arduino):
Answer: 6/26/2013 4:30:59 PM.56364 (+11.3133 seconds)
00 00 FF FF 00 01 00 00
Request: 6/26/2013 4:31:00 PM.48564 (+0.9219 seconds)
00 00 FF FF 01 01 00 00
Answer: 6/26/2013 4:31:00 PM.51664 (+0.0156 seconds)
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00
Upvotes: 0
Views: 426
Reputation: 4685
It looks like you're checking to see that Serial.available()
is not zero and then reading a bunch of data. It could be that you are not done recieving the data when you begin your receiveMsg
function. You should:
Just as an example:
void receiveMsg(MESSAGE_STRUCT* message)
{
// receive bytes and put them back as integers
intByte code_word, checksum;
// receive byte by byte, wait for it if need be
while( Serial.available() < 1 ) {delay(10);}
message->start_byte = Serial.read();
while( Serial.available() < 1 ) {delay(10);}
message->length = Serial.read();
There are better, more robust ways to do it, but this is pretty simple and easily implemented for a test to see if the input buffer is not getting filled.
Upvotes: 1