Changed LED handling

master
phantomix-github 2022-11-14 08:55:41 +01:00
parent 8b308e0404
commit e6655cb9b5
6 changed files with 374 additions and 84 deletions

56
source/Pca9554.cpp Normal file
View File

@ -0,0 +1,56 @@
#include <Wire.h>
#include "Pca9554.h"
enum class Pca9554_Registers : uint8_t {
INPUT_PORT = 0x00,
OUTPUT_PORT = 0x01,
POLARITY_INVERSION = 0x02,
CONFIGURATION = 0x03,
};
Pca9554::Pca9554(uint8_t slaveAddress) :
outputValues { 0 }, slaveAddress { slaveAddress }, inputMask { 0 }
{
}
Pca9554::~Pca9554()
{
}
void Pca9554::begin(uint8_t inputMask, uint8_t outputs)
{
SetInputPins(inputMask);
SendOutputValues(outputValues = outputs);
}
void Pca9554::SetInputPins(uint8_t inputMask)
{
this->inputMask = inputMask;
Wire.beginTransmission(slaveAddress | 0x00);
Wire.write((uint8_t) Pca9554_Registers::CONFIGURATION);
Wire.write(inputMask);
Wire.endTransmission();
}
uint8_t Pca9554::ReadInputs()
{
Wire.beginTransmission(slaveAddress | 0x01);
int result = Wire.read() & inputMask;
Wire.endTransmission();
return (uint8_t) result;
}
void Pca9554::SendOutputValues()
{
SendOutputValues(outputValues);
}
void Pca9554::SendOutputValues(uint8_t values)
{
Wire.beginTransmission(slaveAddress | 0x00);
Wire.write((uint8_t) Pca9554_Registers::OUTPUT_PORT);
Wire.write(values & ~inputMask);
Wire.endTransmission();
}

26
source/Pca9554.h Normal file
View File

@ -0,0 +1,26 @@
#ifndef PCA9554_H_
#define PCA9554_H_ 1
#include <cstdint>
#define PCA9554_ADDR 0x20 //PCA9554 = 0 1 0 0 a2 a1 a0
class Pca9554 {
public:
Pca9554(uint8_t slaveAddress = PCA9554_ADDR);
~Pca9554();
void begin(uint8_t inputMask = 0, uint8_t outputs = 0);
void SetInputPins(uint8_t inputMask);
uint8_t ReadInputs();
void SendOutputValues();
void SendOutputValues(uint8_t values);
uint8_t outputValues;
private:
const uint8_t slaveAddress;
uint8_t inputMask;
};
#endif //PCA9554_H_

View File

@ -3,28 +3,16 @@
#define TCS_OVERSAMPLING 8
#define TCS_BAUDRATE 475
//tcs_bus datagrams
static const unsigned char acknowledge[] = {0,0,0,1,0,1,0,1,1,0};
static const unsigned char ack_audio_on[] = {0,0,0,1,0,1,0,0,1,1,0,0};
static const unsigned char doorbell[] = {0,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,0,1,0,1,0,0,1};
static const unsigned char door_open[] = {0,0,0,1,0,1,0,1,1,0,1,0,1,1,0,0,1,0,1,0,1,0,1,0};
static const unsigned char master_hmmmm[] = {0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,1};
static const unsigned char pickup[] = {0,0,0,1,1,0,1,0,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,0,1,0,1,0,0};
//volatile uint8_t bitIndex = 25;
//const uint8_t datagram[] = { 0,0,0,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,0, 1 };
static const unsigned char hang_up[] = {0,0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0};
static const unsigned char post_hang_up[] = {0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,0};
static const unsigned char light[] = {0,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0};
#define TCS_IDLE_TIMEOUT 64 //8 bits
TcsBus::TcsBus(int sendPin, int receivePin) :
sendPin { sendPin },
receivePin { receivePin },
state { SamplingState::IDLE },
rxBits { 0 },
oversamplingStep { 0 }
oversamplingStep { 0 },
defaultRxEvent { 0 },
txEvent { 0 }
{
}
@ -37,16 +25,25 @@ static void onTimer(void)
static bool TimerSetup(TcsBus* inst)
{
if(timer != NULL) return false; //already set up
if(inst) {
if(timer != NULL) return false; //already set up
tcsInstance = inst;
//time base is 80 MHz, which will be divided by the value from timerBegin, and then
//a counter increments until it reaches the value from timerAlarmWrite. onTimer will then be fired as a callback.
//80000000 / 50 / 421 = 3800.47 Hz = 8 * 475.06
timer = timerBegin(0, 50, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 421, true);
timerAlarmEnable(timer);
tcsInstance = inst;
//time base is 80 MHz, which will be divided by the value from timerBegin, and then
//a counter increments until it reaches the value from timerAlarmWrite. onTimer will then be fired as a callback.
//80000000 / 50 / 421 = 3800.47 Hz = 8 * 475.06
timer = timerBegin(0, 50, true);
timerAttachInterrupt(timer, &onTimer, true);
timerAlarmWrite(timer, 421, true);
timerAlarmEnable(timer);
} else {
if(timer == NULL) return false; //not set up
timerAlarmDisable(timer);
timerDetachInterrupt(timer);
timerEnd(timer);
timer = NULL;
tcsInstance = NULL;
}
return true;
}
@ -56,66 +53,142 @@ void TcsBus::begin()
pinMode(receivePin, INPUT);
pinMode(sendPin, OUTPUT);
digitalWrite(sendPin, LOW); //disable sending for now
pinMode(0, OUTPUT);
//pinMode(0, OUTPUT);
TimerSetup(this);
}
void TcsBus::end()
{
pinMode(sendPin, INPUT);
TimerSetup(NULL);
}
void TcsBus::TimeBase()
{
static int tmp = 0;
static bool send = false;
static int sendIdx = 0;
static int over = 0;
tmp++;
bool sample = digitalRead(receivePin);
if(tmp == 3000) {
send = true;
sendIdx = 0;
over = 0;
do {
if(state != SamplingState::IDLE) {
if(sample) {
oversamplingSum++;
}
if(oversamplingStep) oversamplingStep--;
if(oversamplingStep) {
return;
}
}
switch(state) {
case SamplingState::IDLE: {
if(!sample) {
state = SamplingState::RECEIVE;
oversamplingStep = TCS_OVERSAMPLING;
oversamplingSum = 0;
currentBitIndex = 0;
memset(rxBits, 0x00, (sizeof(rxBits) / sizeof(uint8_t)));
continue;
}
} break;
case SamplingState::RECEIVE: {
if(oversamplingSum <= TCS_OVERSAMPLING / 4) {
ReceiveBit(0);
} else if(oversamplingSum >= (TCS_OVERSAMPLING * 3) / 4) {
ReceiveBit(1);
} else {
//If received bit is invalid, go to idle wait
EnterWaitIdle();
}
} break;
case SamplingState::TRANSMIT: {
TransmitBit();
} break;
case SamplingState::WAIT_IDLE: {
WaitIdle();
}
}
} while(0);
}
void TcsBus::RegisterDefaultRxEvent(EventData_t* evt)
{
defaultRxEvent = evt;
}
void TcsBus::RegisterEvent(const EventData_t* evt)
{
events.push_back(evt);
}
void TcsBus::UnRegisterEvent(const EventData_t* evt)
{
for(int i = 0; i < events.size(); i++) {
if(evt == events[i]) {
//events.erase(evt); //no, needs iterators
return;
}
}
}
if(send) {
over++;
if(over == 8) {
over = 0;
if(sendIdx >= sizeof(door_open)) {
digitalWrite(sendPin, LOW);
send = false;
tmp = 0;
} else {
digitalWrite(sendPin, (door_open[sendIdx++]) ? LOW : HIGH);
void TcsBus::ReceiveBit(uint8_t currentBit)
{
//push received bit to buffer.
rxBits[currentBitIndex++] = currentBit;
//check against event list
const EventData_t* found = 0;
for(const EventData_t* evt: events) {
//std::cout << value << "\n";
if(currentBitIndex >= evt->bitCount) {
if(!memcmp(rxBits, evt->bits, evt->bitCount)) {
if(found != 0) {
//duplicate, skip
found = 0;
break;
} else {
found = evt;
}
}
}
}
bool sample = digitalRead(receivePin);
digitalWrite(0, sample == 0 ? LOW : HIGH);
return;
switch(state) {
case SamplingState::IDLE: {
if(sample) {
state = SamplingState::RECEIVE;
} else {
break;
}
} //fall through
case SamplingState::RECEIVE: {
} break;
case SamplingState::TRANSMIT: {
static int i = 0;
i++;
if(i == 1000)
{
digitalWrite(sendPin, HIGH);
} else if(i > 1000) {
digitalWrite(sendPin, LOW);
i = 0;
}
} break;
if(found) {
found->func(found);
}
}
if(found || (currentBitIndex >= (sizeof(rxBits) / sizeof(uint8_t)))) {
//if done or buffer is full, switch to idle wait state
EnterWaitIdle();
}
}
void TcsBus::EnterWaitIdle()
{
state = SamplingState::WAIT_IDLE;
oversamplingStep = TCS_IDLE_TIMEOUT;
oversamplingSum = 0;
}
void TcsBus::TransmitBit()
{
if(currentBitIndex < txEvent->bitCount) {
digitalWrite(sendPin, !txEvent->bits[currentBitIndex++]);
} else {
//disable if done and return to WAIT_IDLE state
digitalWrite(sendPin, 0); //disable tx mosfet
EnterWaitIdle();
}
}
void TcsBus::WaitIdle()
{
//At this point, the error condition was triggered and the timout is over. If the bus is in idle state, we can
//go over to IDLE, otherwise, we must reset the timeout to ensure an idle time on the bus
if(oversamplingSum >= TCS_IDLE_TIMEOUT) {
state = SamplingState::IDLE;
} else {
oversamplingStep = TCS_IDLE_TIMEOUT;
oversamplingSum = 0;
}
}

View File

@ -1,14 +1,33 @@
#ifndef TCS_BUS_H_
#define TCS_BUS_H_ 1
#include <cstdint>
#include <vector>
class TcsBus {
public:
TcsBus(int sendPin, int receivePin);
struct EventData_t;
typedef struct EventData_t {
void (*func)(const EventData_t* evt);
const uint8_t* bits;
size_t bitCount;
} EventData_t;
TcsBus(int sendPin, int receivePin);
void begin();
void end();
void TimeBase();
void RegisterDefaultRxEvent(EventData_t* evt);
void RegisterEvent(const EventData_t* evt);
void UnRegisterEvent(const EventData_t* evt);
bool StartTransmit(EventData_t* evt);
private:
void EnterWaitIdle();
void ReceiveBit(uint8_t currentBit);
void TransmitBit();
void WaitIdle();
int sendPin;
int receivePin;
@ -17,12 +36,17 @@ private:
IDLE = 0,
RECEIVE = 1,
TRANSMIT = 2,
WAIT_IDLE = 3,
};
SamplingState state;
uint16_t rxBits;
uint8_t rxBits[256];
uint16_t currentBitIndex;
uint8_t oversamplingStep;
bool lastSample;
uint8_t oversamplingSum;
std::vector<const EventData_t*> events;
EventData_t* defaultRxEvent;
EventData_t* txEvent;
};
#endif //TCS_BUS_H_

21
source/TcsBusMessages.h Normal file
View File

@ -0,0 +1,21 @@
#ifndef TCS_BUS_MESSAGES_H_
#define TCS_BUS_MESSAGES_H_ 1
//tcs_bus datagrams
static const unsigned char acknowledge[] = {0,0,0,1,0,1,0,1,1,0};
static const unsigned char ack_audio_on[] = {0,0,0,1,0,1,0,0,1,1,0,0};
static const unsigned char doorbell[] = {0,0,0,1,1,0,1,0,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,0,1,0,1,0,0,1};
static const unsigned char door_open[] = {0,0,0,1,0,1,0,1,1,0,1,0,1,1,0,0,1,0,1,0,1,0,1,0};
static const unsigned char master_hmmmm[] = {0,0,0,1,0,1,0,0,1,0,1,0,0,1,0,0,1,0,1,0,1,0,1,0,1};
static const unsigned char pickup[] = {0,0,0,1,1,0,1,0,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,1,1,0,0,1,1,0,1,0,1,0,1,0,0,1,1,0,0,1,0,1,0,1,0,1,0,0};
//volatile uint8_t bitIndex = 25;
//const uint8_t datagram[] = { 0,0,0,1,0,1,0,1,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,0, 1 };
static const unsigned char hang_up[] = {0,0,0,1,0,1,0,0,1,1,0,1,0,1,0,0,1,0,1,0,1,0,1,0};
static const unsigned char post_hang_up[] = {0,0,0,1,0,1,0,0,1,0,1,0,1,1,0,1,0,1,0,1,0,1,0,0};
static const unsigned char light[] = {0,0,0,1,0,1,0,1,1,0,1,0,0,1,0,1,0,1,0,1,0,1,0,0};
#endif //TCS_BUS_MESSAGES_H_

View File

@ -1,7 +1,7 @@
#include <Wire.h>
#include "Pca9554.h"
#include "TcsBus.h"
#define PCA9554_ADDR 0x20 //PCA9554 = 0 1 0 0 a2 a1 a0
#include "TcsBusMessages.h"
#define PIN_AUDIO_READ 0
#define PIN_API_SWITCH 4
@ -9,10 +9,73 @@
#define PIN_TCS_SEND 14
#define PIN_AUDIO_SEND 17
TcsBus tcs(PIN_TCS_SEND, PIN_TCS_READ);
#define SREG_PIN_API_SWITCH 0x01u
#define SREG_PIN_LED1R 0x02u
#define SREG_PIN_REL1CTRL 0x04u
#define SREG_PIN_AUDIO_SEND_EN 0x08u
#define SREG_PIN_REL2CTRL 0x10u
#define SREG_PIN_LED1G 0x20u
#define SREG_PIN_LED2R 0x40u
#define SREG_PIN_LED2G 0x80u
#define LEDS 2
enum class LedColor : uint8_t {
OFF = 0,
RED = 1,
GREEN = 2,
YELLOW = 3,
UBOUND
};
typedef struct LedState_s {
enum LedColor color;
bool blink;
} LedState_t;
const uint8_t LedBitmask[LEDS][(uint8_t) LedColor::UBOUND] = {
{
0, SREG_PIN_LED1R, SREG_PIN_LED1G, (SREG_PIN_LED1R | SREG_PIN_LED1G)
},
{
0, SREG_PIN_LED2R, SREG_PIN_LED2G, (SREG_PIN_LED2R | SREG_PIN_LED2G)
},
};
static void DoorbellEvt(const TcsBus::EventData_t* evt)
{
}
static const TcsBus::EventData_t doorbellEvt = {
.func = DoorbellEvt,
.bits = doorbell,
.bitCount = sizeof(doorbell),
};
static LedState_t ledStates[LEDS] = {
{ LedColor::OFF, false },
{ LedColor::OFF, false }
};
static uint32_t ms_old = 0;
static TcsBus tcs = TcsBus(PIN_TCS_SEND, PIN_TCS_READ);
static Pca9554 sreg = Pca9554();
static bool blinkOn = false;
static void SetLed(uint8_t ledNr, LedState_t newState) {
uint8_t ledBitmask = LedBitmask[ledNr][(uint8_t) newState.color];
uint8_t ledAll = LedBitmask[ledNr][(uint8_t) LedColor::YELLOW];
if(newState.blink && !blinkOn) {
ledBitmask = LedBitmask[ledNr][(uint8_t) LedColor::OFF];
}
sreg.outputValues = (sreg.outputValues & ~ledAll) | ledBitmask;
}
void setup() {
// put your setup code here, to run once:
Wire.begin();
@ -20,7 +83,20 @@ void setup() {
tcs.begin();
tcs.RegisterEvent(&doorbellEvt);
//const uint8_t sregOutputs = (uint8_t) (SREG_PIN_LED1R | SREG_PIN_REL1CTRL | SREG_PIN_AUDIO_SEND_EN | SREG_PIN_REL2CTRL | SREG_PIN_LED1G | SREG_PIN_LED2R | SREG_PIN_LED2G);
const uint8_t sregInputs = (uint8_t) (SREG_PIN_API_SWITCH | SREG_PIN_AUDIO_SEND_EN);
sreg.begin(sregInputs);
sreg.outputValues = 0;
ms_old = millis();
ledStates[1].color = LedColor::YELLOW;
ledStates[0].blink = true;
//ledStates[1].color = LedColor::YELLOW;
//ledStates[1].blink = true;
}
@ -37,8 +113,22 @@ void loop() {
if(ms_old != ms) {
if(ms_old < ms) ms_old++; else ms_old = ms; //prevent overflow
if(!(ms & 1023)) {
i2cScan();
static uint32_t blinkCountdown = 500;
blinkCountdown--;
if(!blinkCountdown) {
blinkCountdown = 500;
blinkOn = !blinkOn;
SetLed(0, ledStates[0]);
SetLed(1, ledStates[1]);
Serial.printf("0x%02x\r\n", sreg.outputValues);
sreg.SendOutputValues();
}
uint8_t inputs = sreg.ReadInputs();
static uint8_t inputs_old = 0;
if((inputs & SREG_PIN_API_SWITCH) != (inputs_old & SREG_PIN_API_SWITCH)) {
Serial.printf("Switch=%u\n", inputs & SREG_PIN_API_SWITCH);
}
inputs_old = inputs;
}
}