1
0
Fork 0
mirror of https://github.com/benkuper/FlowtoysConnectBridge synced 2025-02-22 14:54:02 +01:00
FlowtoysConnectBridge/RFManager.h
2021-01-18 10:34:28 +01:00

309 lines
8.1 KiB
C++

#pragma once
#include <SPI.h>
#include "nRF24L01.h"
#include "RF24.h"
#include "Config.h"
#include "SerialManager.h"
#include "RFGroup.h"
#include <FastLED.h>
/*
GROUP IDS
orange = 1
green = 2
aqua = 3
blue = 4
purple = 5
*/
#define NUM_PUBLIC_GROUPS 5
#define PUBLIC_GROUP_START_ID 1
#define MAX_PRIVATE_GROUPS 100
#define AUTOADD_PRIVATES 1
#define SEND_TIME 30 //ms
#define FORCESEND_TIME 1000
class RFManager :
public CommandProvider
{
public:
RFManager() : CommandProvider("RF"), radio(4, 33) {}
~RFManager() {}
RF24 radio; //CE and CS pins for SPI bus on NRF24+
RFGroup publicGroups[5];
RFGroup privateGroups[MAX_PRIVATE_GROUPS];
uint8_t address[5] = { 0x01, 0x07, 0xf1, 0, 0 };
SyncPacket receivingPacket;
long lastSendTime = 0;
long lastForceSendTime = 0;
int numActivePrivateGroups;
bool syncing;
long syncTime;
long timeAtSync;
bool radioIsConnected; //to implement
void init()
{
syncing = false;
for (int i = 0; i < NUM_PUBLIC_GROUPS; i++) publicGroups[i].setup(PUBLIC_GROUP_START_ID + i, &radio);
numActivePrivateGroups = Config::instance->getNumPrivateGroups();
for (int i = 0; i < numActivePrivateGroups; i++)
{
privateGroups[i].setup(Config::instance->getRFNetworkId(i), &radio);
DBG(" > Loading private group "+String(i+1)+" : "+String(privateGroups[i].groupID));
}
setRFDataCallback(&RFManager::onRFDataDefaultCallback);
setupRadio();
DBG("RF Manager is init.");
}
void update()
{
if (millis() > lastSendTime + SEND_TIME)
{
lastSendTime = millis();
sendPackets();
}
if (millis() > lastForceSendTime + FORCESEND_TIME)
{
lastForceSendTime = millis();
sendPackets(true);
}
if(syncing && syncTime > 0 && millis() > timeAtSync + syncTime)
{
stopSync();
}
receivePacket();
}
void setupRadio()
{
radio.begin();
radio.setAutoAck(false);
radio.setDataRate(RF24_250KBPS);
radio.setChannel(2);
radio.setAddressWidth(3);
radio.setPayloadSize(sizeof(SyncPacket));
radio.setCRCLength(RF24_CRC_16);
radio.stopListening();
radio.openReadingPipe(1, address);
radio.openWritingPipe(address);
radio.startListening();
#if SERIAL_DEBUG
radio.printDetails();
#endif
}
void sendPackets(bool force = false)
{
radio.stopListening();
//for (int i = 0; i < NUM_PUBLIC_GROUPS; i++) publicGroups[i].sendPacket(force);
for (int i = 0; i < numActivePrivateGroups; i++) privateGroups[i].sendPacket(force);
radio.startListening();
}
void setSolidColors(CRGB * colors)
{
for(int i=0;i < numActivePrivateGroups ;i++)
{
CommandProvider::PatternData data = CommandProvider::getSolidColorPattern(colors[i]);
data.brightness *= globalBrightness;
privateGroups[i].setData(data, true);
}
}
void setPattern(CommandProvider::PatternData data)
{
if(data.groupID == 0)
{
for(int i=0;i<NUM_PUBLIC_GROUPS;i++) publicGroups[i].setData(data);
for(int i=0;i<numActivePrivateGroups;i++) privateGroups[i].setData(data);
}else
{
int index = data.groupID - 1;
if (data.groupIsPublic) //public groups
{
if(index >= 0 && NUM_PUBLIC_GROUPS) publicGroups[index].setData(data);
} else
{
if(index >= 0 && numActivePrivateGroups) privateGroups[index].setData(data);
}
}
}
void wakeUp(int groupID, bool groupIsPublic) {
if(groupID == 0)
{
for(int i=0;i<NUM_PUBLIC_GROUPS;i++) publicGroups[i].wakeUp();
for(int i=0;i<numActivePrivateGroups;i++) privateGroups[i].wakeUp();
}else
{
int index = groupID - 1;
if (groupIsPublic) //public groups
{
if(index >= 0 && NUM_PUBLIC_GROUPS) publicGroups[index].wakeUp();
} else
{
if(index >= 0 && numActivePrivateGroups) privateGroups[index].wakeUp();
}
}
}
void powerOff(int groupID, bool groupIsPublic) {
if(groupID == 0)
{
for(int i=0;i<NUM_PUBLIC_GROUPS;i++) publicGroups[i].powerOff();
for(int i=0;i<numActivePrivateGroups;i++) privateGroups[i].powerOff();
}else
{
int index = groupID - 1;
if (groupIsPublic) //public groups
{
if(index >= 0 && NUM_PUBLIC_GROUPS) publicGroups[index].powerOff();
} else
{
if(index >= 0 && numActivePrivateGroups) privateGroups[index].powerOff();
}
}
}
//SEND / RECEIVE
bool receivePacket() {
if ( radio.available()) {
while (radio.available()) {
radio.read(&receivingPacket, sizeof(SyncPacket));
//reverse group bytes because address is reversed in rf packet but we read end of address as data to get groupID
receivingPacket.groupID = (receivingPacket.groupID >> 8 & 0xff) | ((receivingPacket.groupID & 0xff) << 8);
if (receivingPacket.groupID >= PUBLIC_GROUP_START_ID && receivingPacket.groupID < PUBLIC_GROUP_START_ID + NUM_PUBLIC_GROUPS)
{
if(publicGroups[receivingPacket.groupID - PUBLIC_GROUP_START_ID].updateFromPacket(receivingPacket))
{
sendCommand(RF_DATA);
}
}else
{
bool found = false;
for(int i=0;i<numActivePrivateGroups;i++)
{
if(receivingPacket.groupID == privateGroups[i].groupID)
{
bool newPadding = privateGroups[i].updateFromPacket(receivingPacket);
if(newPadding) sendCommand(RF_DATA);
found = true;
break;
}
}
if(!found)
{
if(syncing)
{
bool syncingPage = 1; //page 2
bool syncingMode = 0; //mode 1
bool acceptAll = false;
if(acceptAll || (receivingPacket.page == syncingPage && receivingPacket.mode == syncingMode))
{
if(numActivePrivateGroups < MAX_PRIVATE_GROUPS)
{
DBG("Adding group : "+String(receivingPacket.groupID)+" at index "+String(numActivePrivateGroups));
digitalWrite(13,HIGH);
delay(50);
digitalWrite(13,LOW);
privateGroups[numActivePrivateGroups].setup(receivingPacket.groupID, &radio);
privateGroups[numActivePrivateGroups].updateFromPacket(receivingPacket);
Config::instance->setRFNetworkId(numActivePrivateGroups, receivingPacket.groupID);
sendCommand(GROUP_ADDED);
numActivePrivateGroups++;
}else
{
DBG("Max groups reached");
}
}
}else if(!syncing)
{
//DBG("Packet from unknown group received "+String(receivingPacket.groupID));
}
}
}
onRFData();
}
return true;
}
return false;
}
void syncRF(float timeout = 0)
{
syncTime = timeout*1000;
DBG("Start Sync with timeout :"+String(syncTime));
timeAtSync = millis();
syncing = true;
}
void stopSync()
{
syncing = false;
Config::instance->setNumPrivateGroups(numActivePrivateGroups);
DBG("Finish sync, got "+String(Config::instance->getNumPrivateGroups())+" groups");
}
void resetSync()
{
resetPrivateGroups();
}
void resetPrivateGroups()
{
DBG("Reset private groups !");
numActivePrivateGroups = 0;
}
// COMMAND FUNCTIONS
//DATA SYNC
typedef void(*RFEvent)();
void (*onRFData) ();
void setRFDataCallback (RFEvent func) {
onRFData = func;
}
static void onRFDataDefaultCallback() {}
};