mirror of
https://github.com/anklimov/lighthub
synced 2025-12-06 03:39:49 +03:00
CAN DUE, relative items, CAN-MQTT brige
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
|
||||
#if defined(ARDUINO_ARCH_STM32)
|
||||
#include <STM32_CAN.h>
|
||||
STM32_CAN STMCan( CAN1, ALT, RX_SIZE_64, TX_SIZE_16 );
|
||||
STM32_CAN STMCan( CAN1, CAN_PINS::DEF, RX_SIZE_64, TX_SIZE_16 );
|
||||
#endif
|
||||
|
||||
#if defined(ARDUINO_ARCH_ESP32)
|
||||
@@ -24,6 +24,7 @@ extern systemConfig sysConf;
|
||||
extern canStream CANConfStream;
|
||||
extern aJsonObject * root;
|
||||
extern volatile int8_t configLocked;
|
||||
extern bool configLoaded;
|
||||
|
||||
|
||||
void printFrame(datagram_t * frame, uint8_t len ) {
|
||||
@@ -163,6 +164,13 @@ bool canDriver::begin()
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
Can0.begin(CAN_BPS_125K);
|
||||
|
||||
int filter;
|
||||
//extended
|
||||
for (filter = 0; filter < 3; filter++) {
|
||||
Can0.setRXFilter(filter, 0, 0, true);
|
||||
//Can1.setRXFilter(filter, 0, 0, true);
|
||||
}
|
||||
#endif
|
||||
|
||||
debugSerial<<"CAN initialized"<<endl;
|
||||
@@ -232,10 +240,15 @@ int canDriver::readFrame()
|
||||
|
||||
//DUE
|
||||
#if defined(__SAM3X8E__)
|
||||
CAN_FRAME incoming;
|
||||
CAN_FRAME CAN_RX_msg;
|
||||
if (Can0.available() > 0) {
|
||||
Can0.read(incoming);
|
||||
printFrame(incoming);
|
||||
|
||||
Can0.read(CAN_RX_msg);
|
||||
if (CAN_RX_msg.length>8) CAN_RX_msg.length=8;
|
||||
memcpy(RXpacket.data, CAN_RX_msg.data.bytes,CAN_RX_msg.length);
|
||||
RXlen = CAN_RX_msg.length;
|
||||
RXid.id = CAN_RX_msg.id;
|
||||
return RXlen;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -263,6 +276,8 @@ switch (state)
|
||||
break;
|
||||
|
||||
case canState::Error:
|
||||
if (configLoaded) state=canState::ConfigLoaded;
|
||||
else
|
||||
if (isTimeOver(responseTimer,millis(),10000UL))
|
||||
lookupMAC();
|
||||
break;
|
||||
@@ -314,13 +329,51 @@ bool canDriver::processPacket(canid_t id, datagram_t *packet, uint8_t len, bool
|
||||
{
|
||||
|
||||
debugSerial.print("CAN Received ");
|
||||
debugSerialPort.print(len);
|
||||
debugSerialPort.print(" bytes id 0x");
|
||||
debugSerialPort.println(id.id,HEX);
|
||||
debugSerial.print(len);
|
||||
debugSerial.print(" bytes id 0x");
|
||||
debugSerial.print(id.id,HEX);
|
||||
|
||||
if (len) printFrame(packet,len);
|
||||
if (id.status)
|
||||
if (id.status){
|
||||
//Responces
|
||||
//@ any state
|
||||
switch (id.payloadType)
|
||||
{
|
||||
case payloadType::itemCommand:
|
||||
{
|
||||
if (len!=8) return false;
|
||||
aJsonObject *confObj = findConfbyID(id.deviceId);
|
||||
if (confObj)
|
||||
{
|
||||
debugSerial<<F("CAN: status received for dev ")<<id.deviceId<<endl;
|
||||
//char * itemNName = findItemName(id.itemId);
|
||||
aJsonObject *itemsObj = aJson.getObjectItem(confObj,"items");
|
||||
if (!itemsObj) return false;;
|
||||
Item it(id.itemId, itemsObj);
|
||||
if (it.isValid())
|
||||
{
|
||||
itemCmd ic;
|
||||
uint16_t flags = 0;
|
||||
ic.cmd = packet->cmd;
|
||||
ic.param = packet->param;
|
||||
|
||||
debugSerial<<F("CAN: item ")<<it.itemArr->name;
|
||||
ic.debugOut();
|
||||
|
||||
if (ic.isCommand()) flags |= FLAG_COMMAND;
|
||||
if (ic.isValue()) flags |= FLAG_PARAMETERS;
|
||||
ic.saveItem(&it,flags);
|
||||
it.SendStatusImmediate(ic,flags | FLAG_NOT_SEND_CAN);
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case canState::MACLookup:
|
||||
@@ -346,8 +399,19 @@ if (id.status)
|
||||
case canState::Error:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else //Requests
|
||||
{
|
||||
/*
|
||||
switch (id.payloadType)
|
||||
{
|
||||
case payloadType::itemCommand:
|
||||
break;
|
||||
|
||||
case payloadType::sysCmd:
|
||||
break;
|
||||
|
||||
}*/
|
||||
if ((id.payloadType == payloadType::itemCommand) && (len ==8))
|
||||
{
|
||||
Item it(id.itemId);
|
||||
@@ -439,7 +503,7 @@ uint8_t canDriver::getIdByMac(macAddress mac)
|
||||
memset(macStr,0,sizeof(macStr));
|
||||
for (byte i = 0; i < 6; i++)
|
||||
{
|
||||
if (mac[i]<16) macStr[strptr++]='0';
|
||||
// if (mac[i]<16) macStr[strptr++]='0';
|
||||
|
||||
SetBytes(&mac[i],1,&macStr[strptr]);
|
||||
strptr+=2;
|
||||
@@ -494,16 +558,16 @@ bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
CAN_FRAME outGoting;
|
||||
outgoing.id = 0x400;
|
||||
outgoing.extended = true;
|
||||
outgoing.priority = 4; //0-15 lower is higher priority
|
||||
|
||||
outgoing.data.s0 = 0xFEED;
|
||||
outgoing.data.byte[2] = 0xDD;
|
||||
outgoing.data.byte[3] = 0x55;
|
||||
outgoing.data.high = 0xDEADBEEF;
|
||||
Can0.sendFrame(outgoing);
|
||||
CAN_FRAME CAN_TX_msg;
|
||||
CAN_TX_msg.id = msg_id;
|
||||
CAN_TX_msg.extended = true;
|
||||
CAN_TX_msg.length=size;
|
||||
//outgoing.priority = 4; //0-15 lower is higher priority
|
||||
if (buf) for(uint8_t i=0;i<size; i++) CAN_TX_msg.data.bytes[i]=buf->data[i];
|
||||
res=Can0.sendFrame(CAN_TX_msg);
|
||||
if (res) debugSerial<<("CAN Wrote ")<<size<<" bytes, id "<<_HEX(msg_id)<<endl;
|
||||
else debugSerial.println("CAN Write error");
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -519,8 +583,10 @@ bool canDriver::sendStatus(uint8_t itemNum, itemCmd cmd)
|
||||
|
||||
bool canDriver::sendCommand(aJsonObject * can,itemCmd cmd, bool status)
|
||||
{
|
||||
debugSerial<<"CAN: sendCommand ";
|
||||
cmd.debugOut();
|
||||
// debugSerial<<"CAN: ";
|
||||
// if (status) debugSerial<<F("sendStatus ");
|
||||
// else debugSerial<<F("sendCommand ");
|
||||
// cmd.debugOut();
|
||||
|
||||
if (can && (can->type == aJson_Array))
|
||||
{
|
||||
@@ -549,7 +615,7 @@ bool canDriver::sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool st
|
||||
packet.cmd = cmd.cmd;
|
||||
packet.param = cmd.param;
|
||||
|
||||
debugSerial << ((status)?"CAN: Status":"CAN: Command");
|
||||
debugSerial << ((status)?"CAN: send Status":"CAN: send Command");
|
||||
debugSerial<<F(" for dev:item ")<<devID<<":"<<itemID<<" ";
|
||||
cmd.debugOut();
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ typedef union {
|
||||
|
||||
enum canState
|
||||
{
|
||||
Unknown,
|
||||
stateUnknown,
|
||||
MACLookup,
|
||||
Idle,
|
||||
StreamOpenedWrite,
|
||||
@@ -110,7 +110,7 @@ Error
|
||||
class canDriver
|
||||
{
|
||||
public:
|
||||
canDriver(){ready=false; controllerId=0; responseTimer=0; state=canState::Unknown;};
|
||||
canDriver(){ready=false; controllerId=0; responseTimer=0; state=canState::stateUnknown;};
|
||||
uint8_t getMyId();
|
||||
bool sendStatus(uint8_t itemNum, itemCmd cmd);
|
||||
bool sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd, bool status=false);
|
||||
@@ -139,6 +139,11 @@ private:
|
||||
CAN_message_t CAN_RX_msg;
|
||||
CAN_message_t CAN_TX_msg;
|
||||
#endif
|
||||
|
||||
#if defined(__SAM3X8E__)
|
||||
//CAN_FRAME CAN_RX_msg;
|
||||
#endif
|
||||
|
||||
bool ready;
|
||||
|
||||
|
||||
@@ -156,7 +161,7 @@ extern aJsonObject * topics;
|
||||
class canStream : public Stream
|
||||
{
|
||||
public:
|
||||
canStream(canDriver * _driver) : readPos(0),writePos(0),devId(0), pType(payloadType::unknown),state(canState::Unknown){driver=_driver; }
|
||||
canStream(canDriver * _driver) : readPos(0),writePos(0),devId(0), pType(payloadType::unknown),state(canState::stateUnknown){driver=_driver; }
|
||||
int open(uint8_t controllerID, payloadType _pType, char _mode)
|
||||
{
|
||||
if (mode) close();
|
||||
@@ -171,7 +176,7 @@ public:
|
||||
{
|
||||
if ((mode == 'w') && writePos) flush();
|
||||
mode = '\0';
|
||||
state=canState::Unknown;
|
||||
state=canState::stateUnknown;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -141,8 +141,9 @@ int txt2subItem(char *payload) {
|
||||
|
||||
//const short defval[4] = {0, 0, 0, 0}; //Type,Arg,Val,Cmd
|
||||
|
||||
Item::Item(aJsonObject *obj)//Constructor
|
||||
Item::Item(aJsonObject *obj, aJsonObject *_items)//Constructor
|
||||
{
|
||||
rootItems=_items;
|
||||
itemArr = obj;
|
||||
driver = NULL;
|
||||
*defaultSubItem = 0;
|
||||
@@ -291,13 +292,14 @@ Item::~Item()
|
||||
}
|
||||
}
|
||||
|
||||
Item::Item(char *name) //Constructor
|
||||
Item::Item(char *name, aJsonObject *_items) //Constructor
|
||||
{
|
||||
char * pDefaultSubItem = defaultSubItem;
|
||||
rootItems=_items;
|
||||
driver = NULL;
|
||||
defaultSubItem[0] =0;
|
||||
defaultSuffixCode = 0;
|
||||
if (name && items)
|
||||
if (name && rootItems)
|
||||
{ char* sub;
|
||||
if (sub=strchr(name,'/'))
|
||||
{
|
||||
@@ -306,7 +308,7 @@ Item::Item(char *name) //Constructor
|
||||
for(i=0;(name[i] && (name[i]!='/') && (i<MQTT_SUBJECT_LENGTH));i++)
|
||||
buf[i]=name[i];
|
||||
buf[i]=0;
|
||||
itemArr = aJson.getObjectItem(items, buf);
|
||||
itemArr = aJson.getObjectItem(rootItems, buf);
|
||||
sub++;
|
||||
strncpy(defaultSubItem,sub,sizeof(defaultSubItem)-1);
|
||||
defaultSuffixCode = retrieveCode (&pDefaultSubItem);
|
||||
@@ -314,7 +316,7 @@ Item::Item(char *name) //Constructor
|
||||
//debugSerial<<F("defaultSubItem: ")<<defaultSubItem<<F(" defaultSuffixCode:")<<defaultSuffixCode<<endl;
|
||||
}
|
||||
else
|
||||
itemArr = aJson.getObjectItem(items, name);
|
||||
itemArr = aJson.getObjectItem(rootItems, name);
|
||||
}
|
||||
else itemArr = NULL;
|
||||
Parse();
|
||||
@@ -341,20 +343,21 @@ uint8_t getCanNum(aJsonObject* verb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
Item::Item(uint16_t num)
|
||||
Item::Item(uint16_t num, aJsonObject *_items)
|
||||
{
|
||||
|
||||
itemArr = NULL;
|
||||
itemArg = NULL;
|
||||
itemVal = NULL;
|
||||
itemExt = NULL;
|
||||
rootItems=_items;
|
||||
|
||||
driver = NULL;
|
||||
defaultSubItem[0] =0;
|
||||
defaultSuffixCode = 0;
|
||||
|
||||
if (!items) return;
|
||||
itemArr = items->child;
|
||||
if (!rootItems) return;
|
||||
itemArr = rootItems->child;
|
||||
while (itemArr)
|
||||
{
|
||||
if (getCanNum(itemArr->child) == num)
|
||||
@@ -778,7 +781,7 @@ return 0;
|
||||
// Recursive function with small stack consumption
|
||||
// if cmd defined - execute Ctrl for any group members recursively
|
||||
// else performs Activity check for group members and return true if any member is active
|
||||
bool digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem, bool authorized)
|
||||
bool Item::digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem, bool authorized)
|
||||
{ if (!itemArr || itemArr->type!=aJson_Array) return false;
|
||||
// Iterate across array of names
|
||||
aJsonObject *i = itemArr->child;
|
||||
@@ -786,7 +789,7 @@ bool digGroup (aJsonObject *itemArr, itemCmd *cmd, char* subItem, bool authorize
|
||||
while (i) {
|
||||
if (i->type == aJson_String)
|
||||
{ //debugSerial<< i->valuestring<<endl;
|
||||
aJsonObject *nextItem = aJson.getObjectItem(items, i->valuestring);
|
||||
aJsonObject *nextItem = aJson.getObjectItem(rootItems, i->valuestring);
|
||||
if (nextItem && nextItem->type == aJson_Array) //nextItem is correct item
|
||||
{
|
||||
Item it(nextItem);
|
||||
@@ -1789,7 +1792,7 @@ int Item::SendStatus(int sendFlags) {
|
||||
st.debugOut();
|
||||
|
||||
#ifdef CANDRV
|
||||
LHCAN.sendStatus(getCanNum(itemArr->child),st);
|
||||
if (!(sendFlags & FLAG_NOT_SEND_CAN)) LHCAN.sendStatus(getCanNum(itemArr->child),st);
|
||||
#endif
|
||||
|
||||
if (sendFlags & FLAG_COMMAND)
|
||||
@@ -2501,7 +2504,7 @@ int Item::checkModbusDimmer() {
|
||||
nextItem.checkModbusDimmer(data);
|
||||
pollingItem = pollingItem->next;
|
||||
if (!pollingItem)
|
||||
pollingItem = items->child;
|
||||
pollingItem = rootItems->child;
|
||||
}
|
||||
} else
|
||||
debugSerial << F("MB: polling ") << itemArr->name<< F(" error=") << _HEX(result) << endl;
|
||||
|
||||
@@ -98,17 +98,17 @@ extern aJsonObject *items;
|
||||
extern short thermoSetCurTemp(char *name, float t);
|
||||
|
||||
int txt2cmd (char * payload);
|
||||
bool digGroup (aJsonObject *itemArr, itemCmd *cmd = NULL, char* subItem = NULL, bool authorized = false);
|
||||
|
||||
class Item
|
||||
{
|
||||
public:
|
||||
aJsonObject *itemArr, *itemArg,*itemVal,*itemExt;
|
||||
aJsonObject *rootItems, *itemArr, *itemArg,*itemVal,*itemExt;
|
||||
uint8_t itemType;
|
||||
abstractOut * driver;
|
||||
|
||||
Item(char * name);
|
||||
Item(aJsonObject * obj);
|
||||
Item(uint16_t num);
|
||||
Item(char * name, aJsonObject *_items = items);
|
||||
Item(aJsonObject * obj, aJsonObject *_items = items);
|
||||
Item(uint16_t num, aJsonObject *_items = items);
|
||||
~Item();
|
||||
|
||||
boolean isValid ();
|
||||
@@ -148,7 +148,9 @@ class Item
|
||||
int scheduleOppositeCommand(itemCmd cmd,bool isActiveNow,bool authorized);
|
||||
int isScheduled();
|
||||
|
||||
|
||||
protected:
|
||||
bool digGroup (aJsonObject *itemArr, itemCmd *cmd = NULL, char* subItem = NULL, bool authorized = false);
|
||||
long int limitSetValue();
|
||||
int VacomSetFan (itemCmd st);
|
||||
int VacomSetHeat(itemCmd st);
|
||||
|
||||
@@ -119,7 +119,7 @@ const ch_type ch_type_P[] PROGMEM =
|
||||
#define FLAG_HALTED 0x40000UL
|
||||
#define FLAG_XON 0x80000UL
|
||||
|
||||
|
||||
#define FLAG_NOT_SEND_CAN 0x2UL
|
||||
|
||||
int txt2cmd (char * payload);
|
||||
|
||||
|
||||
@@ -766,7 +766,9 @@ switch (cmdType)
|
||||
|
||||
if (mqttClient.connected() && !ethernetIdleCount)
|
||||
{
|
||||
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring);
|
||||
if (!strchr(addrstr,'/')) setTopic(addrstr,sizeof(addrstr),T_OUT,emit->valuestring); ///ChangeMe - if no '/' in addr - template not working
|
||||
|
||||
debugSerial << F("MQTT: ")<<addrstr<< F(" -> ")<<emitCommand<<endl;
|
||||
mqttClient.publish(addrstr, emitCommand , true);
|
||||
}
|
||||
} // emit
|
||||
|
||||
@@ -733,6 +733,8 @@ lib_deps =
|
||||
https://github.com/khoih-prog/TimerInterrupt_Generic.git
|
||||
https://github.com/rlogiacco/CircularBuffer
|
||||
rweather/Crypto
|
||||
https://github.com/collin80/due_can.git
|
||||
https://github.com/collin80/can_common.git
|
||||
monitor_speed = 115200
|
||||
|
||||
[env:controllino]
|
||||
|
||||
Reference in New Issue
Block a user