Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Connect two SIMHUB devices using I2C. #43

Draft
wants to merge 30 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
50c0276
Added I2C sending as serial
Mar 17, 2024
9017277
Added main byppass to serial function, As example only buttonStatusCh…
Mar 17, 2024
b1ef413
Updated Approach. Uses I2CTransport.h which uses the I2CSerialBridge …
Mar 20, 2024
cac8fcd
Enabling slave bypass to serial and refactoring the I2C Transport layer.
Mar 20, 2024
f30fa92
Moved I2C FILES to libs.
Mar 21, 2024
99a49f8
Added serial interceptor, later will change class naming. This is the…
Mar 21, 2024
94bcfc4
Generalize to Streams.
Mar 21, 2024
c49feb3
Renamed I2C Classess and files
Mar 21, 2024
609e752
Slave impl not tested yet. The idea behind is that de StreamWrite mac…
Mar 21, 2024
df21309
Added new logic to send via serial de axis changed state with a callback
Mar 21, 2024
926f500
Active shAxisCallBack execution
Mar 21, 2024
e12d190
Analog Joystick support sending via customPacket 0x13
Mar 21, 2024
ca8d76f
Analog Axis implementation and analog axis simulation
Mar 22, 2024
08c7cd5
Merge pull request #1 from eCrowneEng/main
wapophis Mar 30, 2024
f0496c5
Merge pull request #2 from eCrowneEng/main
wapophis Mar 30, 2024
71ef04f
Settled high button count
Mar 31, 2024
e4e7f75
Added buttons types, 0 is a physycall button, 0 is a serialed button
Mar 31, 2024
3da22d3
Fixed build, sending at least two buttons.
Apr 1, 2024
6cca584
wip testing
Apr 2, 2024
e423a8c
UPDATED BUTONSTATUS_CHANGED
Apr 9, 2024
bd23f16
BUTTONMATRIXSTATUDCHANGED UPDATED TO SEND VIA ARQSERIAL WHEN I2C_BYPA…
Apr 9, 2024
d96bb73
synced with AVR-SIMHUB
Apr 14, 2024
be94ac8
MINOR FIXES
Apr 19, 2024
d4386ea
updated protocol decoder from avr-simhub
Apr 19, 2024
899fa4b
rebased I2CSerialBrdige module and ADDED SHVIRTUALROTARY
Apr 19, 2024
6ae38be
rebase SHRotaryEncoder from AVR-SIMHUB
Apr 19, 2024
468d57a
working in master mode encoders via i2c
Apr 20, 2024
010d959
Merge branch 'main' of https://github.com/eCrowneEng/ESP-SimHub
Apr 20, 2024
9196fe8
Merge pull request #3 from wapophis/i2c_encoders
wapophis Apr 20, 2024
dcf1049
Merge branch 'main' of https://github.com/wapophis/ESP-SimHub
Apr 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"files.associations": {
"array": "cpp",
"string": "cpp",
"string_view": "cpp",
"ranges": "cpp",
"deque": "cpp",
"list": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"initializer_list": "cpp",
"regex": "cpp",
"*.tcc": "cpp",
"optional": "cpp",
"istream": "cpp",
"ostream": "cpp",
"system_error": "cpp",
"functional": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"bitset": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"typeinfo": "cpp",
"random": "cpp",
"algorithm": "cpp",
"iterator": "cpp",
"map": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"set": "cpp",
"cstddef": "cpp"
},
"cmake.configureOnOpen": false
}
54 changes: 54 additions & 0 deletions lib/AnalogAxisSimulator/AnalogAxis.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#include "AnalogAxis.h"

int pot = -1;
bool AnalogAxisSimulator::read(int samplingRate){


if(millis()-lastGeneratedReading>300){
pot=analogReadXXbit(samplingRate);
lastGeneratedReading=millis();
}

if (lastAxisValue != pot) {
Serial.println("\nAnalogAxisSimulator::setAnalogReading");
Serial.println(pot);
lastAxisValue = pot;

int mapped = map(pot, minimumInputValue, maximumInputValue, 0, 1024);
Serial.print("\nMapped:");
Serial.print(mapped);
float mapped2 = min((float)1, max((float)0,(float) ((float)mapped / (float)1024)));
Serial.print("\nMapped2:");
Serial.print(mapped2);

if (exponentialFactor != 1) {
mapped2 = pow(mapped2, 1.0 / (float)exponentialFactor);
}

mapped2 = mapped2 * 1024;
Serial.print("\nMapped2 Powed:");
Serial.print(mapped2);
if(this->shAxisChangedCallback!=nullptr){
Serial.println("\nCallback defined");
shAxisChangedCallback(axisIdx,mapped2);
}
}
return false;

}

float AnalogAxisSimulator::analogReadXXbit(byte bits_of_precision)
{
uint8_t n = bits_of_precision - 10;
unsigned long oversample_num = 1 << (2 * n);
uint8_t divisor = 1 << n;
unsigned long reading_sum = 0;
unsigned long inner_sum = 0;
for (unsigned long j = 0; j < oversample_num; j++)
{
inner_sum +=random(-1024,1024);
}
unsigned int reading = (inner_sum + (unsigned long)divisor / 2UL) >> n;
reading_sum += reading;
return (float)reading_sum;
}
25 changes: 25 additions & 0 deletions lib/AnalogAxisSimulator/AnalogAxis.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include <Arduino.h>
typedef void(*SHAxisChanged) (int, int);

class AnalogAxisSimulator{
int axisIdx=1;
int lastAxisValue = -1;
int minimumInputValue=0;
int maximumInputValue=1024;
int samplingRate=10;
float exponentialFactor=1;
unsigned long lastGeneratedReading=millis();
SHAxisChanged shAxisChangedCallback=nullptr;
public:

AnalogAxisSimulator(int axisIdx){
this->axisIdx=axisIdx;
}
bool read(int samplingRate);

void setCallBack(SHAxisChanged callback){
shAxisChangedCallback=callback;
}

float analogReadXXbit(byte bits_of_precision);
};
69 changes: 69 additions & 0 deletions lib/I2CSerialBridge/I2CManager.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#pragma once
#include "I2CTransportMaster.h"
#include "I2CTransportSlave.h"

/***
* "This Manager is responsible for configuring the behavior based on the master-slave role for I2C communication."
*/
class I2CTransportManager {
public:
#if I2C_BYPASS_MASTER
static I2CTransportMaster tm;
#endif
static I2CTransportSlave ts;

static void setup(FullLoopbackStream *outgoingStream){
#if I2C_BYPASS_MASTER
#if I2C_SERIAL_BYPASS_DEBUG
Serial.print("\nSetup as Master\n");
Serial.flush();
#endif
tm.setup(outgoingStream);
#endif

#if I2C_BYPASS_SLAVE
Serial.print("Setup as Slave");
Serial.flush();
ts.setup(outgoingStream);
#endif
}
static void loop(){
#if I2C_BYPASS_MASTER
tm.loop();
#endif

#if I2C_BYPASS_SLAVE
ts.loop();
#endif
}

static void flush(){
#if I2C_BYPASS_MASTER
tm.flush();
#endif

#if I2C_BYPASS_SLAVE
ts.flush();
#endif
}
};

#if I2C_BYPASS_MASTER
#define StreamRead outgoingStream.read
#define StreamAvailable outgoingStream.available
#define FlowSerialFlush Serial.flush
#define StreamFlush I2CTransportManager::flush
#define StreamWrite outgoingStream.write
//#define StreamWrite WIRE.write
#define StreamPrint outgoingStream.print
/** SETUP SERIAL BYPASS I2C SLAVE, USE WHEN THIS DEVICE IS CONNECTED TO SIMHUB*/
#define FlowSerialBegin [](unsigned long baud) { Serial.print("Hola mundo");}
#endif
#if I2C_BYPASS_SLAVE
#define StreamRead Serial.read
#define StreamFlush Serial.flush
#define StreamWrite Serial.write
#define StreamPrint Serial.print
#define StreamAvailable Serial.available
#define FlowSerialBegin [](unsigned long baud) { Serial.begin(baud);}
#endif
149 changes: 149 additions & 0 deletions lib/I2CSerialBridge/I2CSerialBridge.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@

#include <FullLoopbackStream.h>
#include <Wire.h>

#ifndef WIRE
#error WIRE must be settled to have a correct custom wire config in your MASTER config.
#endif

class I2CSerialBridge{
FullLoopbackStream *outgoingStream;
uint8_t address;
public:

I2CSerialBridge(uint8_t address) {
this->address=address;
// CONFIG AS MASTER OR SLAVE WITH ADDRESS
}

void setup(FullLoopbackStream *outgoingStream){
this->outgoingStream = outgoingStream;
}

void loop() {
#if I2C_SERIAL_BYPASS_DEBUG
// Serial.print("\n I2CSerialBridge - loop");
// Serial.flush();
#endif
// put your main code here, to run repeatedly
check_status();
this->flush();
}

void flush() {
// if there is data available in the stream, it's meant
// to go from Serial port to the slave
size_t availableLength = this->outgoingStream->available();
if (availableLength)
{
#if I2C_SERIAL_BYPASS_DEBUG
Serial.println("\n I2CSerialBridge - flush");
Serial.print("\nflushing with this much data:");
Serial.print(availableLength);
#endif


// read the available data from the stream, and put in in the buffer
char sbuf[availableLength];
this->outgoingStream->readBytes(sbuf, availableLength);

// send data to client
WIRE.beginTransmission(address);
size_t total = WIRE.write(sbuf, availableLength);
WIRE.endTransmission();
//endWireTransmission(false);
// DEBUG OUTPUT STREAM
for (int i=0;i<availableLength;i++){
Serial.write(sbuf[i]);
}
Serial.flush();
/// END DEBUG OUTPUT STREAM

#if I2C_SERIAL_BYPASS_DEBUG
// Serial.println("\n I2CSerialBridge - flush");
// Serial.printf("\n ---> data sent to client %s: %d bytes \n", I2C_ADDRESS, total);
// Serial.printf("%d %d\n",sbuf[0], sbuf[1]);
#endif
}
}


/** SETUP SERIAL BYPASS I2C MASTER, USE WHEN THIS DEVICE COMMAND THE SENDING WORKFLOW*/
void i2cSetupMaster(){
#if I2C_SERIAL_BYPASS_DEBUG
Serial.print("WIRE.BEGIN(), initializing....");
#endif
WIRE.begin();
#if I2C_SERIAL_BYPASS_DEBUG
Serial.print("WIRE CONFIGURING TIMEOUT 300 ms .... ");
#endif
WIRE.setTimeout(300);

while(!isSlaveAvailable()){
#if I2C_SERIAL_BYPASS_DEBUG
Serial.print("\n Slave device not available, retrying 1 sec later");
#endif
delay(1000);
};
}

private:
/** TODO CONTROL THAT TRANSPORT LAYER IS READY AND CONNECTED*/
void check_status(){
#if I2C_SERIAL_BYPASS_DEBUG
// Serial.println("\n I2CSerialBridge - check_status");
// Serial.flush();
#endif
}




uint8_t endWireTransmission(bool stop){
uint8_t error=WIRE.endTransmission(stop);
if(error==0){
Serial.print("\n Correct wire close \n");
}
if(error==1){
Serial.print("\n Wire buffer exausted \n");
}
if(error==2){
Serial.print("\n received NACK on transmit of address.\n");
}
if(error==3){
Serial.print("received NACK on transmit of data.");
}
if(error==4){
Serial.print(" other error.");
}
if(error==5){
Serial.print("timeout");
}
Serial.print("\n Error code is ");
Serial.print(error);
Serial.println();
Serial.flush();
return error;

}

bool isSlaveAvailable(){
#if I2C_SERIAL_BYPASS_DEBUG
Serial.print("\n Testing slave availability -> Beging transmission to ");
Serial.print(I2C_ADDRESS);
Serial.println("\n");
#endif
WIRE.beginTransmission(I2C_ADDRESS);
uint8_t error = endWireTransmission(true);

if(error==0){
Serial.print("\n Slave device detected at address ");
Serial.print(I2C_ADDRESS);
Serial.print("\n");
return true;
}
return false;
}


};
12 changes: 12 additions & 0 deletions lib/I2CSerialBridge/I2CTransport.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once
#include <Wire.h>

#include <FullLoopbackStream.h>

class I2CTransport {
public:
I2CTransport(){}
virtual void loop() = 0 ;
virtual void flush() = 0;
virtual void setup(Stream *) = 0;
};
Loading