From b54cdb0688cb505b414147f2cd8c8decd60f466b Mon Sep 17 00:00:00 2001 From: madrocketsci Date: Wed, 6 Dec 2023 12:52:59 -0500 Subject: [PATCH] Publication --- License.txt | 11 + README.md | 9 + arduino_commlcd/ams20x4LCD.cpp | 238 ++++++++++++++++++ arduino_commlcd/ams20x4LCD.hpp | 78 ++++++ arduino_commlcd/amsgenlib.cpp | 50 ++++ arduino_commlcd/amsgenlib.hpp | 29 +++ arduino_commlcd/amsswcomm.cpp | 411 ++++++++++++++++++++++++++++++++ arduino_commlcd/amsswcomm.hpp | 86 +++++++ arduino_commlcd/amswirelib.cpp | 172 +++++++++++++ arduino_commlcd/amswirelib.hpp | 45 ++++ arduino_commlcd/ard_commlcd.ino | 69 ++++++ raspberry_pi/amsswcomm.py | 303 +++++++++++++++++++++++ raspberry_pi/terminalprogram.py | 35 +++ 13 files changed, 1536 insertions(+) create mode 100644 arduino_commlcd/ams20x4LCD.cpp create mode 100644 arduino_commlcd/ams20x4LCD.hpp create mode 100644 arduino_commlcd/amsgenlib.cpp create mode 100644 arduino_commlcd/amsgenlib.hpp create mode 100644 arduino_commlcd/amsswcomm.cpp create mode 100644 arduino_commlcd/amsswcomm.hpp create mode 100644 arduino_commlcd/amswirelib.cpp create mode 100644 arduino_commlcd/amswirelib.hpp create mode 100644 arduino_commlcd/ard_commlcd.ino create mode 100644 raspberry_pi/amsswcomm.py create mode 100644 raspberry_pi/terminalprogram.py diff --git a/License.txt b/License.txt index e69de29..88b4bed 100644 --- a/License.txt +++ b/License.txt @@ -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. diff --git a/README.md b/README.md index e69de29..90e76e7 100644 --- a/README.md +++ b/README.md @@ -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. + + diff --git a/arduino_commlcd/ams20x4LCD.cpp b/arduino_commlcd/ams20x4LCD.cpp new file mode 100644 index 0000000..e3d61b8 --- /dev/null +++ b/arduino_commlcd/ams20x4LCD.cpp @@ -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); + 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; +} diff --git a/arduino_commlcd/ams20x4LCD.hpp b/arduino_commlcd/ams20x4LCD.hpp new file mode 100644 index 0000000..5df3319 --- /dev/null +++ b/arduino_commlcd/ams20x4LCD.hpp @@ -0,0 +1,78 @@ +#ifndef __AMS_20x4LCD_HPP__ +#define __AMS_20x4LCD_HPP__ + +#include +#include + +//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 diff --git a/arduino_commlcd/amsgenlib.cpp b/arduino_commlcd/amsgenlib.cpp new file mode 100644 index 0000000..6126b5c --- /dev/null +++ b/arduino_commlcd/amsgenlib.cpp @@ -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-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; +} diff --git a/arduino_commlcd/amsgenlib.hpp b/arduino_commlcd/amsgenlib.hpp new file mode 100644 index 0000000..974e69a --- /dev/null +++ b/arduino_commlcd/amsgenlib.hpp @@ -0,0 +1,29 @@ +#ifndef __AMS_GENLIB_HPP__ +#define __AMS_GENLIB_HPP__ + +#include +#include + +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 diff --git a/arduino_commlcd/amsswcomm.cpp b/arduino_commlcd/amsswcomm.cpp new file mode 100644 index 0000000..1455ee8 --- /dev/null +++ b/arduino_commlcd/amsswcomm.cpp @@ -0,0 +1,411 @@ + +#include +#include +#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> (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> (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>N; +} + +uint8_t read_portB(uint8_t N) +{ + return (PINB & (1<>N; +} + +uint8_t read_portC(uint8_t N) +{ + return (PINC & (1<>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<=0&&amsPN<=7) + { + N = amsPN-0; + DDRD = (DDRD & ~(1<=8 && amsPN<=15) + { + N = amsPN-8; + DDRB = (DDRB & ~(1<=16&&amsPN<=23) + { + N = amsPN-16; + DDRC = (DDRC & ~(1<=0&&amsPN<=7) + { + N = amsPN-0; + PORTD = (PORTD & ~(1<=8 && amsPN<=15) + { + N = amsPN-8; + PORTB = (PORTB & ~(1<=16&&amsPN<=23) + { + N = amsPN-16; + PORTC = (PORTC & ~(1<=0&&amsPN<=7) + { + N = amsPN-0; + ret = (PIND & (1<>N; + } + else if(amsPN>=8 && amsPN<=15) + { + N = amsPN-8; + ret = (PINB & (1<>N; + } + else if(amsPN>=16&&amsPN<=23) + { + N = amsPN-16; + ret = (PINC & (1<>N; + } + else + { + //nothing; + } + return ret;; +} diff --git a/arduino_commlcd/amswirelib.hpp b/arduino_commlcd/amswirelib.hpp new file mode 100644 index 0000000..628386b --- /dev/null +++ b/arduino_commlcd/amswirelib.hpp @@ -0,0 +1,45 @@ +#ifndef __AMS_WIRELIB_HPP__ +#define __AMS_WIRELIB_HPP__ + +#include +#include + +//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 diff --git a/arduino_commlcd/ard_commlcd.ino b/arduino_commlcd/ard_commlcd.ino new file mode 100644 index 0000000..3fbac58 --- /dev/null +++ b/arduino_commlcd/ard_commlcd.ino @@ -0,0 +1,69 @@ +//#include "ams_swserial.hpp" +#include "amswirelib.hpp" +#include "amsgenlib.hpp" +#include "ams20x4LCD.hpp" + +#include "amsswcomm.hpp" + +#include + +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; +//} diff --git a/raspberry_pi/amsswcomm.py b/raspberry_pi/amsswcomm.py new file mode 100644 index 0000000..f3ca7f9 --- /dev/null +++ b/raspberry_pi/amsswcomm.py @@ -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> (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 + diff --git a/raspberry_pi/terminalprogram.py b/raspberry_pi/terminalprogram.py new file mode 100644 index 0000000..d8e986a --- /dev/null +++ b/raspberry_pi/terminalprogram.py @@ -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