Publication

main
madrocketsci 6 months ago
parent efce1c3756
commit b54cdb0688

@ -0,0 +1,11 @@
Copyright 2023 Aaron M. Schinder
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

@ -0,0 +1,9 @@
Aaron M. Schinder
October 2023
Embedded software serial communications protocol
This is a way to have my various arduino-nano controlled embedded perhipherals talk to each other, and to the Raspberry pi using any 3 available GPIO ports. Sometimes I need more than one perhipheral to talk to a controller, and I run out of dedicated serial ports. This allows the use of any 3 GPIO pins on the controller and perhipheral to facilitate two-way non-blocking communications.

@ -0,0 +1,238 @@
#include "ams20x4LCD.hpp"
#include "amswirelib.hpp"
const static unsigned long rwdelay = 1000;
lcd20x4::lcd20x4()
{
int I;
pin_RS = 0;
pin_RW = 0;
pin_E = 0;
for(I=0;I<8;I++) pin_DB[I] = 0;
}
lcd20x4::~lcd20x4()
{
int I;
pin_RS = 0;
pin_RW = 0;
pin_E = 0;
for(I=0;I<8;I++) pin_DB[I] = 0;
}
void lcd20x4::setup(uint8_t RSpin, uint8_t RWpin, uint8_t Epin, const uint8_t* DBpins)
{
int I;
pin_RS = RSpin;
pin_RW = RWpin;
pin_E = Epin;
set_pinmode(pin_RS,1);
set_pinmode(pin_RW,1);
set_pinmode(pin_E,1);
for(I=0;I<8;I++)
{
pin_DB[I] = DBpins[I];
set_pinmode(pin_DB[I],1);
}
cursx = 0;
cursy = 0;
return;
}
void lcd20x4::loop()
{
//nothing really
}
uint8_t lcd20x4::read_op(uint8_t b, uint8_t RS)
{
uint8_t ret = 0;
uint8_t bt = 0;
int I;
for(I=0;I<8;I++)
{
set_pinmode(pin_DB[I],0);
}
write_pin(pin_E,1);
write_pin(pin_RW,1);
write_pin(pin_RS,RS);
delayMicroseconds(rwdelay);
for(I=0;I<8;I++)
{
bt = read_pin(pin_DB[I]);
ret = ret + bt<<I;
}
delayMicroseconds(rwdelay);
write_pin(pin_E,0);
for(I=0;I<8;I++)
{
set_pinmode(pin_DB[I],1);
}
delayMicroseconds(rwdelay);
return ret;
}
void lcd20x4::write_op(uint8_t b, uint8_t RS)
{
int I;
write_pin(pin_E,1);
write_pin(pin_RW,0);
write_pin(pin_RS,RS);
delayMicroseconds(rwdelay);
for(I=0;I<8;I++)
{
write_pin(pin_DB[I],(b & (1<<I))>>I);
}
delayMicroseconds(rwdelay);
write_pin(pin_E,0);
delayMicroseconds(rwdelay);
}
void lcd20x4::display_clear()
{
write_op(0b00000001,0);
}
void lcd20x4::cursor_home()
{
write_op(0b00000010,0);
cursx = 0; cursy = 0;
}
void lcd20x4::entrymode(bool ID, bool S)
{
write_op((1<<2) | (ID<<1) | S,0);
}
void lcd20x4::display_toggle(bool display, bool cursor, bool charblink)
{
write_op((1<<3) | (display<<2) | (cursor<<1) | charblink, 0);
}
void lcd20x4::cursor_shift(bool screen_cursor, bool left_right)
{
write_op((1<<4) | (screen_cursor<<3) | (left_right<<2),0);
}
//void lcd20x4::function_set(uint8_t q)
//{
// write_op((1<<5) | (q & 0b00001111) , 0);
//}
//DL: data length: 0 - 4-bit, 1 - 8-bit
//N: display lines: 0 - 1-line-mode 1 - 2-line-mode
//F: font: 0 - 5x8 1 - 5x10
void lcd20x4::function_set(bool DL,bool N,bool F)
{
write_op((1<<5)|(DL<<4)|(N<<3)|(F<<2),0);
return;
}
void lcd20x4::CGRAM_set(uint8_t Acg_6bits)
{
write_op((1<<6)|(Acg_6bits & 0b00111111),0);
}
void lcd20x4::DDRAM_set(uint8_t Add_7bits)
{
write_op((1<<7)|(Add_7bits & 0b01111111),0);
}
void lcd20x4::setmydefs()
{
write_pin(pin_E,1);
delay(50);
write_op(0x30,0); //wake up 0x30 0b00110000
delay(50);
write_op(0x30,0); //wake up
delay(50);
write_op(0x30,0); //wake up
delay(50);
//write_op(0x38,0); //function set 8-bit, 2 lines 0b00111000
function_set(1,1,1);
delay(50);
//write_op(0x10,0); //set cursor? (looks like a function set to me?)
entrymode(1,0);
delay(50);
//write_op(0x0c,0); //0x0c 0b00001100
display_toggle(1,0,0);
//write_op(0x0c,0); //0x06 0b00000110
entrymode(1,0);
// display_clear();
// cursor_home();
// entrymode(1,0);
// display_toggle(1,0,0);
// DDRAM_set(0);
}
void lcd20x4::set_pos(uint8_t x, uint8_t y)
{
uint8_t b;
switch(y)
{
case 0: b = 0x00; break;
case 1: b = 0x40; break;
case 2: b = 0x14; break;
case 3: b = 0x54; break;
default: b = 0x00;
}
b += (x%20);
DDRAM_set(b);
}
void lcd20x4::write_char(char b, uint8_t x, uint8_t y)
{
set_pos(x,y);
write_op((uint8_t) b, 1);
}
void lcd20x4::write_char(char b)
{
//may have to do translation of ASCII code
//01000001: A on the chart, 41h on ASCII chart - should be good
//write_op((uint8_t) b,1);
write_char(b,cursx,cursy);
cursx = cursx+1;
if(cursx>=20) {cursy = (cursy+1)%4; cursx = 0;}
}
void lcd20x4::newline()
{
cursx = 0;
cursy = (cursy+1)%4;
}
void lcd20x4::write_chars(const char *bytes)
{
int I;
for(I=0;I<80;I++)
{
if(bytes[I]=='\0')
{
break;
}
else if(bytes[I] == '\n')
{
newline();
}
else
{
write_char(bytes[I]);
}
}
return;
}

@ -0,0 +1,78 @@
#ifndef __AMS_20x4LCD_HPP__
#define __AMS_20x4LCD_HPP__
#include <stdint.h>
#include <Arduino.h>
//https://electronicsforu.com/resources/learn-electronics/16x2-lcd-pinout-diagram
// Most LCDs contain Hitachi HD4478 controller.
// Arduino may already have a driver for this, but I need to learn
// to write my own drivers.
class lcd20x4
{
public:
lcd20x4();
~lcd20x4();
uint8_t cursx,cursy;
void setup(uint8_t RSpin, uint8_t RWpin, uint8_t Epin, const uint8_t* DBpins);
void loop();
//11 pin control for 16-pin LCD screen
uint8_t pin_RS; //pin 4 register-select
//-0 instruction register (read), 1 data register (read/write)
uint8_t pin_RW; //pin 5 (read-write)
//-0 write, 1 read
uint8_t pin_E; //pin 6 enable
//high - enable read/write (clock for read/write?)
uint8_t pin_DB[8]; //pins 7-14 on LCD
//data bus
//blocking read/write operations
uint8_t read_op(uint8_t b, uint8_t RS);
void write_op(uint8_t b, uint8_t RS);
//control commands
void display_clear();
void cursor_home();
void entrymode(bool ID, bool S); //cursor advance direction and shift mode
//I/D - 1:increment/0:decrement S:1 display shift 0:cursor shift?
void display_toggle(bool display, bool cursor, bool charblink);
void cursor_shift(bool screen_cursor, bool left_right);
void CGRAM_set(uint8_t Acg_6bits); //sets CGRAM address - subsequent data is CG data
//user generated characters
void DDRAM_set(uint8_t Add_7bits); //sets DDRAM address - subsequent data is DD data
//00 - 4F (when display not shifted)
//DL: data length: 0 - 4-bit, 1 - 8-bit
//N: display lines: 0 - 1-line-mode 1 - 2-line-mode
//F: font: 0 - 5x8 1 - 5x10
void function_set(bool DL,bool N,bool F);
//D: display
//C: cursor
//B: blink
void displayonoff(bool D, bool C, bool B);
void setmydefs(); //sets reasonable screen defaults and clears screen
//writes a char and advances cursor
void set_pos(uint8_t x, uint8_t y);
void write_char(char b, uint8_t x, uint8_t y);
void write_char(char b);
//clears screen and writes a string (32 bytes max)
void write_chars(const char *bytes);
void newline();
};
#endif

@ -0,0 +1,50 @@
#include "amsgenlib.hpp"
utimer::utimer()
{
t = micros();
}
utimer::~utimer()
{
t = 0;
}
void utimer::set()
{
t = micros();
}
bool utimer::isafter(unsigned long N)
{
bool ret = 0;
unsigned long t2,lmx;
if(t+N<t)
{
//wraparound
lmx = 0-1;
t2 = micros();
if(t2> ((t-lmx)+N))
{
ret = 1;
}
}
else
{
t2 = micros();
if(t2>t+N)
{
ret = 1;
}
}
return ret;
}
void utimer::delay(unsigned long N)
{
while(!this->isafter(N))
{
}
return;
}

@ -0,0 +1,29 @@
#ifndef __AMS_GENLIB_HPP__
#define __AMS_GENLIB_HPP__
#include <stdint.h>
#include <Arduino.h>
class utimer
{
public:
utimer();
~utimer();
unsigned long t;
//sets the time in memory
void set();
//blocking delay
void delay(unsigned long N);
//is it N microseconds after the set time?
//solves wraparound at long overflow
bool isafter(unsigned long N);
};
#endif

@ -0,0 +1,411 @@
#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;
}

@ -0,0 +1,86 @@
#ifndef __AMSSWCOMM_HPP__
#define __AMSSWCOMM_HPP__
#define AMSSWCOMM_BUFFSIZE 64
//the size of the message buffer
class amsswcomm
{
public:
uint8_t ms;
uint8_t clkpin;
uint8_t sendpin;
uint8_t recvpin;
//time
int8_t divisor;
int8_t clockticks;
uint8_t lastclockstate;
uint8_t clockstate;
int16_t recvmessage_size;
uint16_t recvmessage_byte; //extended bit that is being received
int8_t recvstate;
//0 - no starting bit has been received
//1 - receive message start byte
//2 - receiving message bytes
//3 - message received - read and/or clear
int16_t recvbytepointer; //0 - 10, pointer to bit being received
uint8_t recvbitpointer; //pointer to byte being received
int16_t sendmessage_size;
uint16_t sendmessage_byte; //extended byte that is being sent
int8_t sendstate;
//0 - no message being sent
//1 - message exists in queue, send start byte
//2 - message exists in queue, send message bytes
//3 - send end message byte
//4 - clear message and reset
int16_t sendbytepointer; //0 - 10, pointer to byte being sent
uint8_t sendbitpointer; //pointer to byte being sent
char sendmessage[AMSSWCOMM_BUFFSIZE];
char recvmessage[AMSSWCOMM_BUFFSIZE];
//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
void init(uint8_t _ms, uint8_t _clkpin, uint8_t _sendpin, uint8_t _recvpin, int _divisor);
//called on each timestep to update the state of the communicator
void update_step();
//called by update_step
void update_send();
void update_recv();
//communicator has received a complete message
//int is the size of the message, or -1 for no message received
bool has_message();
//receives the message and resets the receive queue
//return value is message size, or -1 for no message
int recv_message(char *outputbuff, int outputbuffsize);
//clears a received message and prepares to receive again
void clearrecvqueue();
void clearsendqueue();
//places a message in the send queue
//1 - success
//0 - failure - a message is being sent, must wait to send
bool send_message(char *inputbuff, int messagesize);
};
#endif

@ -0,0 +1,172 @@
#include "amswirelib.hpp"
uint8_t read_portsD()
{
return PIND;
}
uint8_t read_portsB()
{
return PINB;
}
uint8_t read_portsC()
{
return PINC;
}
uint8_t read_portD(uint8_t N)
{
return (PIND & (1<<N))>>N;
}
uint8_t read_portB(uint8_t N)
{
return (PINB & (1<<N))>>N;
}
uint8_t read_portC(uint8_t N)
{
return (PINC & (1<<N))>>N;
}
void write_portsD(uint8_t V)
{
PORTD = V;
}
void write_portsB(uint8_t V)
{
PORTB = V;
}
void write_portsC(uint8_t V)
{
PORTC = V;
}
void write_portD(uint8_t N, uint8_t V)
{
PORTD = (PORTD & ~(1<<N)) | ((V & 0x01)<<N);
}
void write_portB(uint8_t N, uint8_t V)
{
PORTB = (PORTB & ~(1<<N)) | ((V & 0x01)<<N);
}
void write_portC(uint8_t N, uint8_t V)
{
PORTC = (PORTC & ~(1<<N)) | ((V & 0x01)<<N);
}
void set_portsmodeD(uint8_t iomode)
{
DDRD = iomode;
}
void set_portsmodeB(uint8_t iomode)
{
DDRB = iomode;
}
void set_portsmodeC(uint8_t iomode)
{
DDRC = iomode;
}
void set_portmodeD(uint8_t N, uint8_t iomode)
{
DDRD = (DDRD & ~(1<<N)) | ((iomode & 0x01)<<N);
}
void set_portmodeB(uint8_t N, uint8_t iomode)
{
DDRB = (DDRB & ~(1<<N)) | ((iomode & 0x01)<<N);
}
void set_portmodeC(uint8_t N, uint8_t iomode)
{
DDRC = (DDRC & ~(1<<N)) | ((iomode & 0x01)<<N);
}
//Numbered Pin Digital IO
//amsPN mapping for Arduino Nano
//0-7 - PORTD
//8-15 - PORTB
//16-23 - PORTC (Analog Pins)
//1 - output, 0 - input
void set_pinmode(uint8_t amsPN, uint8_t iomode)
{
uint8_t N;
if(amsPN>=0&&amsPN<=7)
{
N = amsPN-0;
DDRD = (DDRD & ~(1<<N)) | ((iomode & 0x01)<<N);
}
else if(amsPN>=8 && amsPN<=15)
{
N = amsPN-8;
DDRB = (DDRB & ~(1<<N)) | ((iomode & 0x01)<<N);
}
else if(amsPN>=16&&amsPN<=23)
{
N = amsPN-16;
DDRC = (DDRC & ~(1<<N)) | ((iomode & 0x01)<<N);
}
else
{
//nothing;
}
return;
}
void write_pin(uint8_t amsPN, uint8_t V)
{
uint8_t N;
if(amsPN>=0&&amsPN<=7)
{
N = amsPN-0;
PORTD = (PORTD & ~(1<<N)) | ((V & 0x01)<<N);
}
else if(amsPN>=8 && amsPN<=15)
{
N = amsPN-8;
PORTB = (PORTB & ~(1<<N)) | ((V & 0x01)<<N);
}
else if(amsPN>=16&&amsPN<=23)
{
N = amsPN-16;
PORTC = (PORTC & ~(1<<N)) | ((V & 0x01)<<N);
}
else
{
//nothing;
}
return;
}
uint8_t read_pin(uint8_t amsPN)
{
uint8_t ret = 0;
uint8_t N;
if(amsPN>=0&&amsPN<=7)
{
N = amsPN-0;
ret = (PIND & (1<<N))>>N;
}
else if(amsPN>=8 && amsPN<=15)
{
N = amsPN-8;
ret = (PINB & (1<<N))>>N;
}
else if(amsPN>=16&&amsPN<=23)
{
N = amsPN-16;
ret = (PINC & (1<<N))>>N;
}
else
{
//nothing;
}
return ret;;
}

@ -0,0 +1,45 @@
#ifndef __AMS_WIRELIB_HPP__
#define __AMS_WIRELIB_HPP__
#include <Arduino.h>
#include <stdint.h>
//Routines for fast digital read/write from the PORTs, PINs, DDRs
//This is specific to Arduino Nano
uint8_t read_portsD();
uint8_t read_portsB();
uint8_t read_portsC();
uint8_t read_portD(uint8_t N);
uint8_t read_portB(uint8_t N);
uint8_t read_portC(uint8_t N);
void write_portsD(uint8_t V);
void write_portsB(uint8_t V);
void write_portsC(uint8_t V);
void write_portD(uint8_t N, uint8_t V);
void write_portB(uint8_t N, uint8_t V);
void write_portC(uint8_t N, uint8_t V);
void set_portsmodeD(uint8_t iomode);
void set_portsmodeB(uint8_t iomode);
void set_portsmodeC(uint8_t iomode);
void set_portmodeD(uint8_t N, uint8_t iomode);
void set_portmodeB(uint8_t N, uint8_t iomode);
void set_portmodeC(uint8_t N, uint8_t iomode);
//Numbered Pin Digital IO
//amsPN mapping for Arduino Nano
//0-7 - PORTD
//8-15 - PORTB
//16-23 - PORTC (Analog Pins)
//1 - output, 0 - input
void set_pinmode(uint8_t amsPN, uint8_t iomode);
uint8_t read_pin(uint8_t amsPN);
void write_pin(uint8_t amsPN, uint8_t V);
#endif

@ -0,0 +1,69 @@
//#include "ams_swserial.hpp"
#include "amswirelib.hpp"
#include "amsgenlib.hpp"
#include "ams20x4LCD.hpp"
#include "amsswcomm.hpp"
#include <stdio.h>
lcd20x4 lcd;
amsswcomm comm;
char buff1[128];
unsigned long loopcount;
void setup()
{
const uint8_t q[8] = {9,10,21,20,19,18,17,16};
lcd.setup(6,7,8,q);
lcd.setmydefs();
//initialize
lcd.display_clear();
lcd.cursor_home();
lcd.write_chars("INIT");
//set up comm as a servant receiver
//C1 - D2 - pin 2 - using as CLK
//C2 - D3 - pin 3 - using as sendpin
//C3 - D4 - pin 4 - using as recvpin
//C4 - D5 - pin 5
// divisor = 5 ticks
comm.init(0,2,3,4,5);
}
void loop()
{
comm.update_step();
if(comm.has_message())
{
comm.recv_message(buff1,128);
buff1[127] = 0;
comm.send_message("ACK",4);
lcd.display_clear();
lcd.cursor_home();
lcd.write_chars(buff1);
}
}
//void setup()
//{
// set_pinmode(2,1);
// set_pinmode(3,1);
// set_pinmode(4,1);
// loopcount = 0;
//}
//// Test pins
//void loop()
//{
// delay(100);
// write_pin(2, loopcount%2);
// write_pin(3, (loopcount/2)%2);
// write_pin(4, (loopcount/4)%2);
//
//
// loopcount = loopcount + 1;
// loopcount = loopcount % 16;
//}

@ -0,0 +1,303 @@
#!/usr/bin/python
import os,sys,math
import numpy as np
#whatever arduino GPIO library
import RPi.GPIO as GPIO
import time
## dummy functions for now - work through the logic while you still have it in your head!
def set_pinmode(pinnumber, mode):
#set GPIO mode to BOARD
if(mode==1):
GPIO.setup(pinnumber, GPIO.OUT)
elif(mode==0):
GPIO.setup(pinnumber, GPIO.IN)
return
def read_pin(pinnumber):
ret = 0
val = GPIO.input(pinnumber)
ret = int(val)
return ret
def write_pin(pinnumber, val):
#print("dummy: sending {} on {}".format(pinnumber, val))
if(val==1):
GPIO.output(pinnumber,GPIO.HIGH)
else:
GPIO.output(pinnumber,GPIO.LOW)
return
#3-wire software-defined terminal class
#mirrors the logic of the arduino class, for talking with
#arduino-nano controlled perhipheral devices
class amsswcomm():
def __init__(self):
return
def comminit(self, _ms, _clkpin, _sendpin, _recvpin, _divisor = 1):
self.ms = int(_ms)
self.clkpin = int(_clkpin)
self.sendpin = int(_sendpin)
self.recvpin = int(_recvpin)
self.divisor = _divisor
self.sendmessage = np.uint8([])
self.recvmessage = np.uint8([])
self.clearrecvqueue()
self.clearsendqueue()
self.clockstate = 0
self.lastclockstate = 0
self.clockticks = 0
if(self.ms==1):
#master, most often the case for the raspberry pi
set_pinmode(self.clkpin,1)
set_pinmode(self.recvpin,0)
set_pinmode(self.sendpin,1)
elif(self.ms==0):
#servant
set_pinmode(self.clkpin,0)
set_pinmode(self.recvpin,0)
set_pinmode(self.sendpin,1)
else:
pass
return
def update_step(self):
if(self.ms==1):
#master, most often the case for the raspberry pi
if(self.clockticks<self.divisor):
self.clockticks = self.clockticks+1
else:
self.clockticks = 0
self.lastclockstate = self.clockstate
self.clockstate = int(not self.lastclockstate)
write_pin(self.clkpin,self.clockstate)
if(self.clockstate==1 and self.lastclockstate==0):
self.update_send()
if(self.clockstate==0 and self.lastclockstate==1):
self.update_recv()
elif(self.ms==0):
self.lastclockstate = self.clockstate
self.clockstate = read_pin(self.clkpin)
if(self.clockstate==1 and self.lastclockstate==0):
self.update_send()
if(self.clockstate==0 and self.lastclockstate==1):
self.update_recv()
else:
pass
return
def clearrecvqueue(self):
self.recvmessage_byte = np.uint16(0)
self.recvbytepointer = 0
self.recvbitpointer = 0
self.recvstate = 0
self.recvmessage = np.uint8([])
return
def clearsendqueue(self):
self.sendmessage_byte = np.uint16(0)
self.sendbytepointer = 0
self.sendbitpointer = 0
self.sendstate = 0
self.sendmessage = np.uint8([])
return
def update_send(self):
if(self.sendstate==0):
#do nothing, no message in queue
write_pin(self.sendpin,0)
elif(self.sendstate==1):
self.sendmessage_byte = 0b0000001111111111
bit = (self.sendmessage_byte & 1<<(9-self.sendbitpointer)) >> (9-self.sendbitpointer)
write_pin(self.sendpin,bit)
self.sendbitpointer = self.sendbitpointer+1
if(self.sendbitpointer>=10):
self.sendbitpointer = 0
self.sendbytepointer = 0
self.sendstate = 2
elif(self.sendstate==2):
#send message byte
if(len(self.sendmessage)>=0):
self.sendmessage_byte = 0b0000001100000000 + self.sendmessage[self.sendbytepointer]
bit = (self.sendmessage_byte & 1<<(9-self.sendbitpointer)) >> (9-self.sendbitpointer)
write_pin(self.sendpin,bit)
self.sendbitpointer = self.sendbitpointer + 1
if(self.sendbitpointer>=10):
self.sendbitpointer = 0
self.sendbytepointer = self.sendbytepointer + 1
if(self.sendbytepointer>=len(self.sendmessage)):
self.sendbitpointer = 0
self.sendbytepointer = 0
self.sendstate = 3
else:
#size 0 message
self.sendbitpointer = 0
self.sendbytepointer = 0
self.sendstate = 3
elif(self.sendstate==3):
#send ending byte
self.sendmessage_byte = 0
bit = (self.sendmessage_byte & 1<<(9-self.sendbitpointer)) >> (9-self.sendbitpointer)
write_pin(self.sendpin,bit)
self.sendbitpointer = self.sendbitpointer+1
if(self.sendbitpointer>=10):
self.sendbitpointer = 0
self.sendbytepointer = 0
self.sendstate = 4
elif(self.sendstate==4):
#Finish and reset
self.clearsendqueue()
else:
#improper condition, should not occur
self.clearsendqueue()
return
def update_recv(self):
if(self.recvstate==0):
bit = read_pin(self.recvpin)
if(bit==1):
self.recvstate = 1
self.recvbitpointer = 1
self.recvmessage_byte = 0b0000001000000000
self.recvbytepointer = 0
elif(self.recvstate==1):
bit = read_pin(self.recvpin)
self.recvmessage_byte = self.recvmessage_byte + (bit<<(9-self.recvbitpointer));
self.recvbitpointer = self.recvbitpointer + 1
if(self.recvbitpointer>=10):
self.recvbitpointer = 0
if(self.recvmessage_byte == 0b0000001111111111):
self.recvstate = 2
self.recvbytepointer = 0
#append to message
#byte2 = np.uint8(self.recvmessage_byte & 0b0000000011111111)
#self.recvmessage = np.append(self.recvmessage,byte2)
self.recvmessage_byte = 0
else:
#garbled message
self.clearrecvqueue()
elif(self.recvstate==2):
#receive messsage byte
bit = read_pin(self.recvpin)
self.recvmessage_byte = self.recvmessage_byte + (bit<<(9-self.recvbitpointer));
self.recvbitpointer = self.recvbitpointer + 1
if(self.recvbitpointer>=10):
self.recvbitpointer = 0
if(self.recvmessage_byte==0):
#end of message byte
self.recmessage_byte = 0
self.recvstate = 3
else:
#append to message
byte2 = np.uint8(self.recvmessage_byte & 0b0000000011111111)
self.recvmessage = np.append(self.recvmessage,byte2)
self.recvmessage_byte = 0
#DEBUG
# if(len(self.recvmessage)>10):
# self.recmessage_byte = 0
# self.recvstate = 3
elif(self.recvstate==3):
#has a message, - wait until this is handled
pass
else:
#invalid state
self.clearrecvqueue()
return
def has_message(self):
ret = False
if(self.recvstate==3):
ret = True
return ret
def recv_message(self):
message = None
if(self.has_message()):
message = self.recvmessage
self.clearrecvqueue()
return message
def send_message(self,message):
ret = False
if(type(message) is type(str)):
message = message.decode("utf-8")
if(type(message) is type(bytes)):
message = np.frombuffer(message,dtype=np.uint8)
if(self.sendstate==0):
ret = True
self.sendmessage = message
self.sendstate = 1
self.sendmessage_byte = 0
self.sendbitpointer = 0
self.sendbytepointer = 0
return ret

@ -0,0 +1,35 @@
#!/usr/bin/python
import os,sys,math
import numpy as np
from amsswcomm import *
import time
## Setup
GPIO.setmode(GPIO.BOARD);
#other mode is GPIO.BCM - pin numberings are different?
com = amsswcomm()
com.comminit(1,3,7,5,4)
while(True):
msg = input("Cmd: ")
msgb = msg.encode(encoding="utf-8")
msgb = np.frombuffer(msgb, dtype=np.uint8)
t0 = time.time()
t = time.time()
com.send_message(msgb)
while(com.has_message()==False and (t<t0+1)):
com.update_step()
t = time.time()
reply = com.recv_message()
print("reply: {}".format(reply))
Loading…
Cancel
Save