-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from guido4096/support-complete-arbitration
Support the complete ebus arbitration protocol
- Loading branch information
Showing
12 changed files
with
899 additions
and
110 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
#ifndef _ARBITRATION_H_ | ||
#define _ARBITRATION_H_ | ||
|
||
#include "busstate.hpp" | ||
|
||
// Implements the arbitration algorithm. Uses the state of the bus to decide what to do. | ||
// Typical usage: | ||
// - try to start the arbitration with "start" method | ||
// - pass each received value on the bus to the "data" method | ||
// which will then tell you what the state of the arbitration is | ||
class Arbitration | ||
{ | ||
public: | ||
enum state {none, // no arbitration ongoing | ||
arbitrating, // arbitration ongoing | ||
won1, // won | ||
won2, // won | ||
lost1, // lost | ||
lost2, // lost | ||
error, // error | ||
restart1, // restart the arbitration | ||
restart2, // restart the arbitration | ||
}; | ||
|
||
Arbitration() | ||
: _arbitrating(false) | ||
, _participateSecond(false) | ||
, _arbitrationAddress(0) | ||
, _restartCount(0) | ||
{} | ||
// Try to start arbitration for the specified master. | ||
// Return values: | ||
// - started : arbitration started. Make sure to pass all bus data to this object through the "data" method | ||
// - not_started : arbitration not started. Possible reasons: | ||
// + the bus is not in a state that allows to start arbitration | ||
// + another arbitration is already ongoing | ||
// + the master address is SYN | ||
// - late : arbitration not started because the start is too late compared to the SYN symbol received | ||
enum result {started, not_started, late}; | ||
result start(BusState& busstate, uint8_t master, unsigned long startBitTime); | ||
|
||
// A symbol was received on the bus, what does this do to the arbitration state? | ||
// Return values: | ||
// - see description of state enum value | ||
Arbitration::state data (BusState& busstate, uint8_t symbol, unsigned long startBitTime); | ||
|
||
private: | ||
bool _arbitrating; | ||
bool _participateSecond; | ||
uint8_t _arbitrationAddress; | ||
int _restartCount; | ||
}; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#ifndef _BUS_H_ | ||
#define _BUS_H_ | ||
#include "main.hpp" | ||
#include "busstate.hpp" | ||
#include "arbitration.hpp" | ||
#include "queue" | ||
|
||
#ifdef ESP32 | ||
#include "atomic" | ||
#define ATOMIC_INT std::atomic<int> | ||
#else | ||
#define ATOMIC_INT int | ||
#endif | ||
// This object retrieves data from the Serial object and let's | ||
// it flow through the arbitration process. The "read" method | ||
// will return data with meta information that tells what should | ||
// be done with the returned data. This object hides if the | ||
// underlying implementation is synchronous or asynchronous | ||
class BusType | ||
{ | ||
public: | ||
// "receive" data should go to all clients that are not in arbitration mode | ||
// "enhanced" data should go only to the arbitrating client | ||
// a client is in arbitration mode if _client is not null | ||
struct data { | ||
bool _enhanced; // is this an enhanced command? | ||
uint8_t _c; // command byte, only used when in "enhanced" mode | ||
uint8_t _d; // data byte for both regular and enhanced command | ||
WiFiClient* _client; // the client that is being arbitrated | ||
WiFiClient* _logtoclient; // the client that needs to log | ||
}; | ||
BusType(); | ||
~BusType(); | ||
|
||
// begin and end, like with Serial | ||
void begin(); | ||
void end(); | ||
|
||
// Is there a value available that should be send to a client? | ||
bool read(data& d); | ||
size_t write(uint8_t symbol); | ||
int availableForWrite(); | ||
int available(); | ||
|
||
// std::atomic seems not well supported on esp12e, besides it is also not needed there | ||
ATOMIC_INT _nbrRestarts1; | ||
ATOMIC_INT _nbrRestarts2; | ||
ATOMIC_INT _nbrArbitrations; | ||
ATOMIC_INT _nbrLost1; | ||
ATOMIC_INT _nbrLost2; | ||
ATOMIC_INT _nbrWon1; | ||
ATOMIC_INT _nbrWon2; | ||
ATOMIC_INT _nbrErrors; | ||
ATOMIC_INT _nbrLate; | ||
private: | ||
inline void push (const data& d); | ||
void receive (uint8_t symbol, unsigned long startBitTime); | ||
BusState _busState; | ||
Arbitration _arbitration; | ||
WiFiClient* _client; | ||
|
||
#if USE_ASYNCHRONOUS | ||
// handler to be notified when there is signal change on the serial input | ||
static void IRAM_ATTR receiveHandler(); | ||
|
||
// queue from Bus to read method | ||
QueueHandle_t _queue; | ||
|
||
// task to read bytes form the serial object and process them with receive methods | ||
TaskHandle_t _serialEventTask; | ||
|
||
static void readDataFromSoftwareSerial(void *args); | ||
#else | ||
std::queue<data> _queue; | ||
#endif | ||
}; | ||
|
||
extern BusType Bus; | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
#ifndef _BUSSTATE_H_ | ||
#define _BUSSTATE_H_ | ||
#include "main.hpp" | ||
#include "enhanced.hpp" | ||
|
||
|
||
// Implements the state of the bus. The arbitration process can | ||
// only start at well defined states of the bus. To asses the | ||
// state, all data received on the bus needs to be send to this | ||
// object. The object takes care of startup of the bus and | ||
// recovery when an unexpected event happens. | ||
class BusState { | ||
public: | ||
enum eState { | ||
eStartup, // In startup mode to analyze bus state | ||
eStartupFirstSyn, // Either the bus is busy, it is arbitrating, or it is free to start an arbitration | ||
eStartupSymbolAfterFirstSyn, | ||
eStartupSecondSyn, | ||
eReceivedFirstSYN, // Received SYN | ||
eReceivedAddressAfterFirstSYN, // Received SYN ADDRESS | ||
eReceivedSecondSYN, // Received SYN ADDRESS SYN | ||
eReceivedAddressAfterSecondSYN,// Received SYN ADDRESS SYN ADDRESS | ||
eBusy // Bus is busy; _master is master that won, _byte is first symbol after the master address | ||
}; | ||
static const char* enumvalue(eState e) | ||
{ | ||
const char* values[] = { | ||
"eStartup", | ||
"eStartupFirstSyn", | ||
"eStartupSymbolAfterFirstSyn", | ||
"eStartupSecondSyn", | ||
"eReceivedFirstSYN", | ||
"eReceivedAddressAfterFirstSYN", | ||
"eReceivedSecondSYN", | ||
"eReceivedAddressAfterSecondSYN", | ||
"eBusy" | ||
}; | ||
return values[e]; | ||
} | ||
BusState() | ||
: _state(eStartup) | ||
, _previousState(eStartup) | ||
{} | ||
// Evaluate a symbol received on UART and determine what the new state of the bus is | ||
inline void data(uint8_t symbol) | ||
{ | ||
switch (_state) | ||
{ | ||
case eStartup: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eStartupFirstSyn) : eStartup; | ||
break; | ||
case eStartupFirstSyn: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eReceivedFirstSYN) : eStartupSymbolAfterFirstSyn; | ||
break; | ||
case eStartupSymbolAfterFirstSyn: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eStartupSecondSyn) : eBusy; | ||
break; | ||
case eStartupSecondSyn: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eReceivedFirstSYN) : eBusy; | ||
break; | ||
case eReceivedFirstSYN: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eReceivedFirstSYN) : eReceivedAddressAfterFirstSYN; | ||
_master = symbol; | ||
break; | ||
case eReceivedAddressAfterFirstSYN: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eReceivedSecondSYN ): eBusy; | ||
_symbol = symbol; | ||
break; | ||
case eReceivedSecondSYN: | ||
_previousState = _state; | ||
_state = symbol == SYN ? error(_state, eReceivedFirstSYN) : eReceivedAddressAfterSecondSYN; | ||
_master = symbol; | ||
break; | ||
case eReceivedAddressAfterSecondSYN: | ||
_previousState = _state; | ||
_state = symbol == SYN ? error(_state, eReceivedFirstSYN) : eBusy; | ||
_symbol = symbol; | ||
break; | ||
case eBusy: | ||
_previousState = _state; | ||
_state = symbol == SYN ? syn(eReceivedFirstSYN) : eBusy; | ||
break; | ||
} | ||
} | ||
inline eState syn(eState newstate) | ||
{ | ||
_previousSYNtime = _SYNtime; | ||
_SYNtime = micros(); | ||
return newstate; | ||
} | ||
eState error(eState currentstate, eState newstate) | ||
{ | ||
_previousSYNtime = _SYNtime; | ||
_SYNtime = micros(); | ||
DEBUG_LOG ("unexpected SYN on bus while state is %s, setting state to %s m=0x%02x, b=0x%02x %lu us\n", enumvalue(currentstate), enumvalue(newstate), _master, _symbol, microsSincePreviousSyn()); | ||
return newstate; | ||
} | ||
|
||
void reset() | ||
{ | ||
_state = eStartup; | ||
} | ||
|
||
unsigned long microsSinceLastSyn() | ||
{ | ||
return micros() - _SYNtime; | ||
} | ||
|
||
unsigned long microsSincePreviousSyn() | ||
{ | ||
return micros() - _previousSYNtime; | ||
} | ||
|
||
eState _state; | ||
eState _previousState; | ||
uint8_t _master; | ||
uint8_t _symbol; | ||
unsigned long _SYNtime; | ||
unsigned long _previousSYNtime; | ||
}; | ||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
#ifndef _ENHANCED_H_ | ||
#define _ENHANCED_H_ | ||
#include <WiFiClient.h> | ||
|
||
enum symbols { | ||
SYN = 0xAA | ||
}; | ||
|
||
enum requests { | ||
CMD_INIT = 0, | ||
CMD_SEND, | ||
CMD_START, | ||
CMD_INFO | ||
}; | ||
|
||
enum responses { | ||
RESETTED = 0x0, | ||
RECEIVED = 0x1, | ||
STARTED = 0x2, | ||
INFO = 0x3, | ||
FAILED = 0xa, | ||
ERROR_EBUS = 0xb, | ||
ERROR_HOST = 0xc | ||
}; | ||
|
||
enum errors { | ||
ERR_FRAMING = 0x00, | ||
ERR_OVERRUN = 0x01 | ||
}; | ||
|
||
void enhArbitrationDone(); | ||
WiFiClient* enhArbitrationRequested(uint8_t& arbitration_client); | ||
|
||
int pushEnhClient(WiFiClient* client, uint8_t c, uint8_t d, bool log); | ||
void handleEnhClient(WiFiClient* client); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,37 @@ | ||
#ifndef _MAIN_HPP_ | ||
#define _MAIN_HPP_ | ||
|
||
#include <WiFiClient.h> | ||
#include <WiFiServer.h> | ||
|
||
#define MAX_SRV_CLIENTS 4 | ||
#define RXBUFFERSIZE 1024 | ||
#define RXBUFFERSIZE 512 // On ESP8266, maximum 512 icw SoftwareSerial, otherwise you run out of heap | ||
#define QUEUE_SIZE 480 | ||
#define STACK_PROTECTOR 512 // bytes | ||
#define HOSTNAME "esp-eBus" | ||
#define RESET_MS 1000 | ||
|
||
#ifdef ESP32 | ||
// https://esp32.com/viewtopic.php?t=19788 | ||
#define AVAILABLE_THRESHOLD 0 | ||
#define UART_TX 20 | ||
#define UART_RX 21 | ||
#define USE_SOFTWARE_SERIAL 1 | ||
#define USE_ASYNCHRONOUS 1 // requires USE_SOFTWARE_SERIAL | ||
#define AVAILABLE_THRESHOLD 0 // https://esp32.com/viewtopic.php?t=19788 | ||
#else | ||
#define UART_TX 1 | ||
#define UART_RX 3 | ||
#define USE_SOFTWARE_SERIAL 0 | ||
#define USE_ASYNCHRONOUS 0 // requires USE_SOFTWARE_SERIAL | ||
#define AVAILABLE_THRESHOLD 1 | ||
#endif | ||
|
||
inline int DEBUG_LOG(const char *format, ...) { return 0;} | ||
int DEBUG_LOG_IMPL(const char *format, ...); | ||
//#define DEBUG_LOG DEBUG_LOG_IMPL | ||
|
||
bool handleNewClient(WiFiServer &server, WiFiClient clients[]); | ||
int pushClient(WiFiClient* client, uint8_t B); | ||
int pushClient(WiFiClient* client, uint8_t B); | ||
void handleClient(WiFiClient* client); | ||
|
||
int pushEnhClient(WiFiClient* client, uint8_t B); | ||
void handleEnhClient(WiFiClient* client); | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,6 +26,7 @@ build_flags = | |
lib_deps = | ||
https://github.com/tzapu/WiFiManager | ||
https://github.com/marvinroger/ESP8266TrueRandom | ||
https://github.com/guido4096/espsoftwareserial.git#add-startbit-timestamp | ||
|
||
[env:esp12e-ota] | ||
extends = env:esp12e | ||
|
@@ -48,6 +49,9 @@ platform = espressif32 | |
board = esp32-c3-devkitm-1 | ||
build_flags = | ||
-DRESET_PIN=20 | ||
lib_deps = | ||
https://github.com/tzapu/WiFiManager | ||
https://github.com/guido4096/espsoftwareserial.git#add-startbit-timestamp | ||
|
||
[env:esp32-c3-ota] | ||
extends = env:esp32-c3 | ||
|
@@ -57,4 +61,4 @@ upload_protocol = espota | |
[env:esp32-c3-ota-vpn] | ||
extends = env:esp32-c3-ota | ||
upload_protocol = custom | ||
upload_command = scp $SOURCE [email protected]:firmware.bin && ssh [email protected] espota.py -i esp-ebus.local -p 3232 -f firmware.bin -d -r | ||
upload_command = scp $SOURCE [email protected]:firmware.bin && ssh [email protected] espota.py -i esp-ebus.local -p 3232 -f firmware.bin -d -r |
Oops, something went wrong.