You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
412 lines
9.2 KiB
C++
412 lines
9.2 KiB
C++
1 year ago
|
|
||
|
#include <Arduino.h>
|
||
|
#include <stdint.h>
|
||
|
#include "amswirelib.hpp"
|
||
|
#include "amsgenlib.hpp"
|
||
|
|
||
|
#include "amsswcomm.hpp"
|
||
|
|
||
|
//initialize the sw communication channel
|
||
|
// each swcomm channel has 3 pins, the clock pin (controlled by the master),
|
||
|
// the input pin (receiving a signal from the other device)
|
||
|
// and an output pin (sending a signal to the other device)
|
||
|
//Inputs:
|
||
|
// ms - master or slave
|
||
|
// clkpin - the clock pin number
|
||
|
// outpin - the output pin number
|
||
|
// inpin - the input pin number
|
||
|
// divisor - how many updates to skip between clock changes
|
||
|
void amsswcomm::init(uint8_t _ms, uint8_t _clkpin, uint8_t _sendpin, uint8_t _recvpin, int _divisor)
|
||
|
{
|
||
|
|
||
|
ms = _ms;
|
||
|
clkpin = _clkpin;
|
||
|
sendpin = _sendpin;
|
||
|
recvpin = _recvpin;
|
||
|
|
||
|
|
||
|
divisor = _divisor;
|
||
|
clockticks = 0;
|
||
|
clockstate = 0;
|
||
|
lastclockstate = 0;
|
||
|
|
||
|
if(ms==1)
|
||
|
{
|
||
|
//master
|
||
|
set_pinmode(clkpin,1);
|
||
|
set_pinmode(recvpin,0);
|
||
|
set_pinmode(sendpin,1);
|
||
|
|
||
|
}
|
||
|
else if(ms==0)
|
||
|
{
|
||
|
//slave
|
||
|
set_pinmode(clkpin,0);
|
||
|
set_pinmode(recvpin,0);
|
||
|
set_pinmode(sendpin,1);
|
||
|
|
||
|
}
|
||
|
|
||
|
clearrecvqueue();
|
||
|
clearsendqueue();
|
||
|
|
||
|
// recvmessage_size = -1;
|
||
|
// sendmessage_size = -1; //no message
|
||
|
// recvmessage_bit = 0;
|
||
|
// sendmessage_bit = 0;
|
||
|
|
||
|
// sendstate = 0;
|
||
|
// recvstate = 0;
|
||
|
// sendbytepointer = 0;
|
||
|
// recvbytepointer = 0;
|
||
|
// sendbitpointer = 0;
|
||
|
// recvbitpointer = 0;
|
||
|
|
||
|
int8_t I;
|
||
|
for(I=0;I<AMSSWCOMM_BUFFSIZE;I++)
|
||
|
{
|
||
|
sendmessage[I] = 0;
|
||
|
recvmessage[I] = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void amsswcomm::clearrecvqueue()
|
||
|
{
|
||
|
int8_t I;
|
||
|
|
||
|
recvmessage_size = -1;
|
||
|
recvmessage_byte = 0;
|
||
|
recvstate = 0;
|
||
|
recvbytepointer = 0;
|
||
|
recvbitpointer = 0;
|
||
|
|
||
|
// for speed, deal with this by sendmessage_size
|
||
|
// for(I=0;I<AMSSWCOMM_BUFFSIZE;I++)
|
||
|
// {
|
||
|
// recvmessage[I] = 0;
|
||
|
// }
|
||
|
|
||
|
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void amsswcomm::clearsendqueue()
|
||
|
{
|
||
|
int8_t I;
|
||
|
|
||
|
sendmessage_size = -1;
|
||
|
sendmessage_byte = 0;
|
||
|
sendstate = 0;
|
||
|
sendbytepointer = 0;
|
||
|
sendbitpointer = 0;
|
||
|
|
||
|
// for speed, deal with this by recvmessage_size
|
||
|
// for(I=0;I<AMSSWCOMM_BUFFSIZE;I++)
|
||
|
// {
|
||
|
// sendmessage[I] = 0;
|
||
|
// }
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void amsswcomm::update_step()
|
||
|
{
|
||
|
|
||
|
if(ms==1)
|
||
|
{
|
||
|
//if master
|
||
|
|
||
|
if(clockticks<divisor)
|
||
|
{
|
||
|
clockticks++;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
clockticks = 0;
|
||
|
|
||
|
lastclockstate = clockstate;
|
||
|
clockstate = !lastclockstate;
|
||
|
write_pin(clkpin,clockstate);
|
||
|
|
||
|
//update_send triggers on rising edge of clkpin
|
||
|
if(clockstate==1 && lastclockstate==0)
|
||
|
{
|
||
|
update_send();
|
||
|
}
|
||
|
//update recv triggers on falling edge of clkpin
|
||
|
if(clockstate==0 && lastclockstate==1)
|
||
|
{
|
||
|
update_recv();
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
}
|
||
|
else if(ms==0)
|
||
|
{
|
||
|
//if servant
|
||
|
|
||
|
//check clock every passthrough
|
||
|
|
||
|
lastclockstate = clockstate;
|
||
|
clockstate = read_pin(clkpin);
|
||
|
|
||
|
//update_send triggers on rising edge of clkpin
|
||
|
if(clockstate==1 && lastclockstate==1)
|
||
|
{
|
||
|
update_send();
|
||
|
}
|
||
|
//update recv triggers on falling edge of clkpin
|
||
|
if(clockstate==0 && lastclockstate==1)
|
||
|
{
|
||
|
update_recv();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
//called by update_step
|
||
|
void amsswcomm::update_send()
|
||
|
{
|
||
|
|
||
|
uint8_t bit;
|
||
|
|
||
|
if(sendstate==0)
|
||
|
{
|
||
|
//do nothing, no message
|
||
|
write_pin(sendpin,0); //send zeroes until messaging
|
||
|
}
|
||
|
else if(sendstate==1)
|
||
|
{
|
||
|
//send starting byte
|
||
|
sendmessage_byte = 0b0000001111111111;
|
||
|
|
||
|
bit = (sendmessage_byte & 1<<(9-sendbitpointer)) >> (9-sendbitpointer);
|
||
|
write_pin(sendpin,bit);
|
||
|
|
||
|
sendbitpointer++; //advance pointer
|
||
|
if(sendbitpointer>=10)
|
||
|
{
|
||
|
//if finished, advance state
|
||
|
sendbitpointer=0;
|
||
|
sendbytepointer=0;
|
||
|
sendstate=2;
|
||
|
}
|
||
|
}
|
||
|
else if(sendstate==2)
|
||
|
{
|
||
|
if(sendmessage_size>=0 && sendbytepointer<sendmessage_size)
|
||
|
{
|
||
|
sendmessage_byte = 0b0000001100000000 + sendmessage[sendbytepointer];
|
||
|
|
||
|
bit = (sendmessage_byte & 1<<(9-sendbitpointer)) >> (9-sendbitpointer);
|
||
|
write_pin(sendpin,bit);
|
||
|
|
||
|
sendbitpointer++; //advance pointer
|
||
|
if(sendbitpointer>=10)
|
||
|
{
|
||
|
//if finished, advance bytepointer
|
||
|
sendbitpointer=0;
|
||
|
sendbytepointer++;
|
||
|
}
|
||
|
if(sendbytepointer>sendmessage_size)
|
||
|
{
|
||
|
//if finished with message, advance state to send ending byte
|
||
|
sendbitpointer=0;
|
||
|
sendbytepointer=0;
|
||
|
sendstate=3;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//size 0 message
|
||
|
sendbitpointer=0;
|
||
|
sendbytepointer=0;
|
||
|
sendstate=3;
|
||
|
}
|
||
|
}
|
||
|
else if(sendstate==3)
|
||
|
{
|
||
|
//send ending byte
|
||
|
sendmessage_byte = 0; //if zero is received for more than 10 bits, end message
|
||
|
|
||
|
bit = (sendmessage_byte & 1<<(9-sendbitpointer)) >> (9-sendbitpointer);
|
||
|
write_pin(sendpin,bit);
|
||
|
|
||
|
sendbitpointer++; //advance pointer
|
||
|
if(sendbitpointer>=10)
|
||
|
{
|
||
|
//if finished, advance state
|
||
|
sendbitpointer=0;
|
||
|
sendbytepointer=0;
|
||
|
sendstate=4;
|
||
|
}
|
||
|
}
|
||
|
else if(sendstate==4)
|
||
|
{
|
||
|
clearsendqueue();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//this shouldn't happen, but if it does, reset things
|
||
|
clearsendqueue();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void amsswcomm::update_recv()
|
||
|
{
|
||
|
uint8_t bit;
|
||
|
|
||
|
if(recvstate==0)
|
||
|
{
|
||
|
bit = read_pin(recvpin);
|
||
|
if(bit==1)
|
||
|
{
|
||
|
recvstate=1; //advance to receive state
|
||
|
recvbitpointer=1;
|
||
|
recvmessage_byte = 0b0000001000000000; //set first leading bit
|
||
|
recvbytepointer = 0;
|
||
|
}
|
||
|
}
|
||
|
else if(recvstate==1)
|
||
|
{
|
||
|
bit = read_pin(recvpin);
|
||
|
recvmessage_byte = recvmessage_byte + (bit<<(9-recvbitpointer));
|
||
|
recvbitpointer++;
|
||
|
|
||
|
if(recvbitpointer>=10)
|
||
|
{
|
||
|
recvbitpointer = 0;
|
||
|
if(recvmessage_byte = 0b0000001111111111)
|
||
|
{
|
||
|
recvstate = 2;
|
||
|
recvmessage_byte = 0;
|
||
|
recvbytepointer = 0;
|
||
|
recvmessage_size = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//byte received not part of message or garbled message, ignore
|
||
|
recvstate = 0;
|
||
|
recvbytepointer = 0;
|
||
|
clearrecvqueue();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if(recvstate==2)
|
||
|
{
|
||
|
bit = read_pin(recvpin);
|
||
|
recvmessage_byte = recvmessage_byte + (bit<<(9-recvbitpointer));
|
||
|
recvbitpointer++;
|
||
|
|
||
|
if(recvbitpointer>=10)
|
||
|
{
|
||
|
if(recvmessage_byte==0)
|
||
|
{
|
||
|
//end of message byte has been received
|
||
|
recvbitpointer = 0;
|
||
|
recvbytepointer = 0;
|
||
|
recvstate = 3; //has message
|
||
|
recvmessage_byte = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
recvbitpointer = 0;
|
||
|
recvmessage[recvbytepointer] = (uint8_t)(recvmessage_byte & 0b0000000011111111);
|
||
|
recvbytepointer++;
|
||
|
recvmessage_size++;
|
||
|
recvmessage_byte = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if(recvstate==3)
|
||
|
{
|
||
|
//has message, do nothing and wait until message has been processed
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
clearrecvqueue();
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
bool amsswcomm::has_message()
|
||
|
{
|
||
|
if(recvstate==3)
|
||
|
{
|
||
|
return 1;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
//receives the message and resets the receive queue
|
||
|
//return value is message size, or -1 for no message
|
||
|
int amsswcomm::recv_message(char *outputbuff, int outputbuffsize)
|
||
|
{
|
||
|
int ret = -1;
|
||
|
int I;
|
||
|
|
||
|
if(has_message())
|
||
|
{
|
||
|
ret = recvmessage_size;
|
||
|
for(I=0;I<recvmessage_size && I<outputbuffsize && I<AMSSWCOMM_BUFFSIZE; I++)
|
||
|
{
|
||
|
outputbuff[I] = recvmessage[I];
|
||
|
}
|
||
|
if(I<outputbuffsize) outputbuff[I] = 0; //NULL terminate if possible to help string logic
|
||
|
|
||
|
for(I=0;I<AMSSWCOMM_BUFFSIZE;I++)
|
||
|
{
|
||
|
recvmessage[I] = 0;
|
||
|
}
|
||
|
recvmessage_size = -1;
|
||
|
// recvmessage_byte = 0;
|
||
|
// recvstate = 0;
|
||
|
// recvbytepointer = 0;
|
||
|
// recvbitpointer = 0;
|
||
|
clearrecvqueue();
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
//places a message in the send queue
|
||
|
//1 - success
|
||
|
//0 - failure - a message is being sent, must wait to send
|
||
|
bool amsswcomm::send_message(char *inputbuff, int messagesize)
|
||
|
{
|
||
|
bool ret = 0;
|
||
|
int I;
|
||
|
|
||
|
if(sendstate==0)
|
||
|
{
|
||
|
ret = 1;
|
||
|
if(messagesize<=AMSSWCOMM_BUFFSIZE) sendmessage_size = messagesize; else sendmessage_size = AMSSWCOMM_BUFFSIZE;
|
||
|
for(I=0;I<sendmessage_size;I++)
|
||
|
{
|
||
|
sendmessage[I] = inputbuff[I];
|
||
|
}
|
||
|
for(I=sendmessage_size;I<AMSSWCOMM_BUFFSIZE;I++)
|
||
|
{
|
||
|
sendmessage[I] = 0;
|
||
|
}
|
||
|
|
||
|
sendstate = 1; //start sending message
|
||
|
sendmessage_byte = 0;
|
||
|
sendbitpointer = 0;
|
||
|
sendbytepointer = 0;
|
||
|
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|