CAN: config retrieving from master

This commit is contained in:
2024-03-02 15:48:21 +03:00
parent 3c9e30b28a
commit 535e1be274
5 changed files with 533 additions and 44 deletions

View File

@@ -1,3 +1,4 @@
#
-DWIFI_ENABLE
-DDMX_DISABLE
# - exeption in DMX.update/begin
@@ -12,7 +13,7 @@
-DARDUINO_OTA_MDNS_DISABLE
-DMDNS_ENABLE
#- ArduinoMDNS didnt working
-D CANDRV
-DMCP23017
-DMODBUS_TX_PIN=13
#-DARTNET_ENABLE - udp rx errors ((

View File

@@ -4,6 +4,7 @@
#include <candriver.h>
#include <Arduino.h>
#include <main.h>
#include <utils.h>
#if defined(ARDUINO_ARCH_STM32)
#include <STM32_CAN.h>
@@ -20,6 +21,9 @@ STM32_CAN STMCan( CAN1, ALT, RX_SIZE_64, TX_SIZE_16 );
#include <config.h>
//#include <systemconfigdata.h>
extern systemConfig sysConf;
extern canStream CANConfStream;
extern aJsonObject * root;
extern volatile int8_t configLocked;
void printFrame(datagram_t * frame, uint8_t len ) {
@@ -91,22 +95,47 @@ bool canDriver::lookupMAC()
return res;
}
bool canDriver::requestFrame(uint8_t devId, payloadType _payloadType )
{
canid_t id;
datagram_t packet;
bool res;
id.reserve=0;
id.status=0;
id.payloadType=_payloadType;
id.deviceId=devId;
id.itemId=0; //CRC?
packet.metric1 =0;
//memcpy(packet.mac,sysConf.mac,6);
debugSerial<<("Request frame ")<<_payloadType<<F(" for id ")<<devId<<endl;
res=write (id.id,&packet,1);
if (res) state=canState::FrameRequested;
else state=canState::Error;
responseTimer=millisNZ();
return res;
}
bool canDriver::sendRemoteID(macAddress mac)
{
canid_t id;
//datagram_t packet;
bool res=false;
id.deviceId=getIdByMac(mac); //Retrieved controllerID
if (!id.deviceId) return false;
id.reserve=0;
id.status=1; //response
id.payloadType=payloadType::lookupMAC;
id.deviceId=100; //Retrieved controllerID
id.itemId=200; //CRC of remote config
id.itemId=200; //CRC16 of remote config
//packet.data[0]=1;
debugSerial<<("Send remote ID")<<endl;
res = write (id.id);//,&packet,8);
if (res) state=canState::HaveId;
if (res) state=canState::Idle;
else state=canState::Error;
// responseTimer=millisNZ(); ????????
return res;
@@ -137,21 +166,24 @@ bool canDriver::begin()
#endif
debugSerial<<"CAN initialized"<<endl;
controllerId = getMyId();
ready=true;
return true;
}
void canDriver::Poll()
int canDriver::readFrame()
{
// return ;
if (!ready) return;
if (!ready) return -1;
//STM32
#if defined(ARDUINO_ARCH_STM32)
if (STMCan.read(CAN_RX_msg))
{
processPacket( CAN_RX_msg.id, (datagram_t*) CAN_RX_msg.buf,CAN_RX_msg.len);
if (CAN_RX_msg.len>8) CAN_RX_msg.len=8;
memcpy(RXpacket.data, CAN_RX_msg.buf,CAN_RX_msg.len);
RXlen = CAN_RX_msg.len;
RXid.id = CAN_RX_msg.id;
return RXlen;
}
#endif
#if defined(ARDUINO_ARCH_ESP32)
@@ -182,21 +214,22 @@ void canDriver::Poll()
//debugSerialPort.println(packetSize);
debugSerialPort.println(CAN.packetDlc());
datagram_t packet;
// only print packet data for non-RTR packets
int i=0;
while (CAN.available()) {
packet.data[i++]=CAN.read();
//debugSerialPort.print((char)CAN.read());
if (i>=8) break;
}
debugSerialPort.println();
processPacket( CAN.packetId(), &packet,i);
// only print packet data for non-RTR packets
RXlen=0;
while (CAN.available()) {
RXpacket.data[RXlen++]=CAN.read();
if (RXlen>=8) break;
}
RXid.id = CAN.packetId();
debugSerialPort.println();
return RXlen;
}
}
#endif
//DUE
#if defined(__SAM3X8E__)
CAN_FRAME incoming;
@@ -207,12 +240,20 @@ void canDriver::Poll()
#endif
return -1;
}
void canDriver::Poll()
{
if (readFrame()>=0) processPacket( RXid, &RXpacket, RXlen);
//State machine
switch (state)
{
case canState::MACLookup:
// case canState::FrameRequested:
if (isTimeOver(responseTimer,millis(),1000UL))
{
responseTimer=millisNZ();
@@ -226,55 +267,189 @@ switch (state)
lookupMAC();
break;
// case canState::HaveId:
}
}
bool canDriver::processPacket(uint32_t rawid, datagram_t *packet, uint8_t len, bool rtr)
case canState::ReadConfig:
{
canid_t id;
id.id = rawid;
//Blocking read config
if (configLocked) return; // only in safe moments
configLocked++;
infoSerial<<F("Requesting Config from CAN")<<endl;
CANConfStream.open(controllerId,payloadType::configFrame,'r');
if (CANConfStream.peek() == '{') {
debugSerial<<F("JSON detected")<<endl;
aJsonStream as = aJsonStream(&CANConfStream);
cleanConf(false);
root = aJson.parse(&as);
CANConfStream.close();
if (!root) {
errorSerial<<F("load failed")<<endl;
sysConf.setETAG("");
// sysConfStream.close();
configLocked--;
state = canState::Error;
return;
}
infoSerial<<F("Loaded from CAN")<<endl;
configLocked--;
applyConfig();
sysConf.loadETAG();
state = canState::Idle;
return ;
}
CANConfStream.close();
infoSerial<<F("Config not loaded")<<endl;
state = canState::Error;
configLocked--;
}
break;
// case canState::Idle:
}
}
bool canDriver::processPacket(canid_t id, datagram_t *packet, uint8_t len, bool rtr)
{
debugSerial.print("CAN Received ");
debugSerialPort.print(len);
debugSerialPort.print(" bytes id 0x");
debugSerialPort.println(id.id,HEX);
printFrame(packet,len);
if (len) printFrame(packet,len);
if (id.status)
//Responces
switch (state)
{
case canState::MACLookup:
if ((id.payloadType == payloadType::lookupMAC) && (len>=6))
if ((id.payloadType == payloadType::lookupMAC))
{
debugSerial<<"Got Controller CAN addr: "<<id.deviceId<<endl;
controllerId=id.deviceId;
state = canState::ReadConfig;
}
return true;
case canState::HaveId:
case canState::FrameRequested:
if ((id.payloadType == payloadType::configFrame) && (id.deviceId == controllerId))
{
errorSerial<<F("Config received when not expected")<<endl;
}
break;
case canState::Idle:
break;
case canState::Error:
return false;
}
else //Requests
{
if (id.payloadType == payloadType::lookupMAC)
if ((id.payloadType == payloadType::lookupMAC) && (len>=6))
{
return sendRemoteID(packet->mac);
//debugSerial<<"ID requested"<<endl;
}
else if (id.payloadType == payloadType::configFrame)
{
debugSerial<<F("Requested conf for dev#")<<id.deviceId<<endl;
aJsonObject * remoteConfObj = findConfbyID(id.deviceId);
if (remoteConfObj)
{
infoSerial<<F("Sending conf for dev#")<<id.deviceId<<endl;
CANConfStream.open(id.deviceId,payloadType::configFrame,'w');
aJsonStream outStream = aJsonStream(&CANConfStream);
aJson.print(remoteConfObj, &outStream);
CANConfStream.close();
}
return 1;
//debugSerial<<"ID requested"<<endl;
}
}
return false;
}
uint8_t canDriver::getMyId()
{
if (!root) return 0;
aJsonObject * canObj = aJson.getObjectItem(root, "can");
if (!canObj) return 0;
aJsonObject * addrObj = aJson.getObjectItem(canObj, "addr");
if (addrObj && (addrObj->type == aJson_Int)) return addrObj->valueint;
return 0;
}
aJsonObject * canDriver::findConfbyID(uint8_t devId)
{
if (!root) return NULL;
aJsonObject * canObj = aJson.getObjectItem(root, "can");
if (!canObj) return NULL;
aJsonObject * remoteConfObj = aJson.getObjectItem(canObj, "conf");
if (!remoteConfObj) return NULL;
remoteConfObj=remoteConfObj->child;
while (remoteConfObj)
{
aJsonObject * remoteCanObj = aJson.getObjectItem(remoteConfObj, "can");
if (remoteCanObj)
{
aJsonObject * addrObj = aJson.getObjectItem(remoteCanObj, "addr");
if (addrObj && (addrObj->type == aJson_Int) && (addrObj->valueint == devId)) return remoteConfObj;
}
remoteConfObj=remoteConfObj->next;
}
return NULL;
}
uint8_t canDriver::getIdByMac(macAddress mac)
{
char macStr[19];
uint8_t strptr = 0;
if (!root) return 0;
aJsonObject * canObj = aJson.getObjectItem(root, "can");
if (!canObj) return 0;
aJsonObject * confObj = aJson.getObjectItem(canObj, "conf");
if (!confObj) return 0;
memset(macStr,0,sizeof(macStr));
for (byte i = 0; i < 6; i++)
{
if (mac[i]<16) macStr[strptr++]='0';
SetBytes(&mac[i],1,&macStr[strptr]);
strptr+=2;
if (i < 5) macStr[strptr++]=':';
}
debugSerial<<F("Searching devId for ")<<macStr<<endl;
aJsonObject * remoteConfObj = aJson.getObjectItem(confObj, macStr);
if (!remoteConfObj) return 0;
aJsonObject * remoteCanObj = aJson.getObjectItem(remoteConfObj, "can");
if (!remoteCanObj) return 0;
aJsonObject * addrObj = aJson.getObjectItem(remoteCanObj, "addr");
if (!addrObj) return 0;
if (addrObj && (addrObj->type == aJson_Int))
{
debugSerial<<F("find dev#")<< addrObj->valueint << endl;
return addrObj->valueint;
}
return 0;
}
bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
{ //return 0;
@@ -289,7 +464,7 @@ bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
CAN_TX_msg.id = msg_id;
CAN_TX_msg.flags.extended = 1; // To enable extended ID
CAN_TX_msg.len=size;
if (res=STMCan.write(CAN_TX_msg)) debugSerial<<("CAN Wrote ")<<size<<" bytes"<<endl;
if (res=STMCan.write(CAN_TX_msg)) debugSerial<<("CAN Wrote ")<<size<<" bytes, id "<<_HEX(msg_id)<<endl;
else debugSerial.println("CAN Write error");
return res;
#endif
@@ -299,7 +474,7 @@ bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
CAN.beginExtendedPacket(msg_id,size);
CAN.write(buf->data,size);
//for(uint8_t i=0;i<size; i++) CAN.write(buf[i]);
if (res=CAN.endPacket()) debugSerial.println("CAN Wrote");
if (res=CAN.endPacket()) debugSerial<< ("CAN Wrote ")<<size << " bytes, id "<<_HEX(msg_id)<<endl;
else debugSerial.println("CAN Write error");
return res;
#endif
@@ -319,4 +494,192 @@ bool canDriver::write(uint32_t msg_id, datagram_t * buf, uint8_t size)
}
bool canDriver::sendStatus(char * itemName, itemCmd cmd)
{
}
bool canDriver::sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd)
{
}
////////////////////////////// Steream //////////////////////////
int canStream::send(uint8_t len)
{
canid_t id;
datagram_t packet;
bool res;
if (!driver) return 0;
id.reserve=0;
id.status=1;
id.payloadType=pType;
id.deviceId=devId;
id.itemId=0; // chunk?
res=driver->write (id.id, &writeBuffer, len);
writePos=0;
if (res)
{
//Await check?
return 1;
}
else return 0;
}
int canStream::checkState()
{
bool res = false;
if (!driver) return -1;
switch (state)
{
case canState::StreamOpenedRead:
readPos = 0;
res= driver->requestFrame(devId,pType); //Requesting frame;
if (res)
state = canState::FrameRequested;
else
{
state = canState::Error;
return -1;
}
//continue
case canState::FrameRequested:
{
uint32_t timer = millis();
int c;
do {
debugSerial.print(".");
yield();
if (c=driver->readFrame()>0 && (driver->RXid.deviceId == devId) && (driver ->RXid.payloadType == pType))
{
state = canState::FrameReceived;
debugSerial<<F("Payload received ")<< c << "|" <<driver->RXlen<< " "<<driver->RXpacket.payload<<endl;;
return driver->RXlen;
}
} while((!isTimeOver(timer,millis(),1000UL)) );
debugSerial<<F("RX data awaiting timeout")<<endl;
return -1;
}
break;
case canState::FrameReceived:
return driver->RXlen;
break;
case canState::waitingConfirm:
if (driver->readFrame()>=0)
{
if (
(driver->RXid.deviceId == devId) &&
(driver->RXid.payloadType == pType) &&
(driver->RXid.status == 0)
)
state = canState::StreamOpenedWrite;
return 0;
}
return driver->RXlen;
break;
case canState::Idle:
return -1;
break;
}
return -1;
};
// Stream methods
int canStream::available()
{
if (!driver) return -1;
int avail = checkState();
return avail;
};
int canStream::read()
{
if (!driver) return -1;
int avail = checkState();
int ch;
if (avail>=0)
{
ch = driver->RXpacket.data[readPos++];
if (readPos>=8) state = canState::StreamOpenedRead;
return ch;
}
else return -1;
};
int canStream::peek()
{
if (!driver) return -1;
int avail = checkState();
int ch;
if (avail>=0)
{
ch = driver->RXpacket.data[readPos];
return ch;
}
else return -1;
};
size_t canStream::write(uint8_t c)
{
//if ((state != canState::StreamOpenedWrite) || (state != canState::waitingConfirm)) return -1;
uint32_t timer = millis();
do
{
checkState();
yield();
//debugSerial.print("*");
if (isTimeOver(timer,millis(),1000UL))
{
state = canState::Error;
errorSerial<<F("CAN write timeout")<<endl;
return -1;
}
}
while (!availableForWrite() );
writeBuffer.data[writePos++]=c;
if (writePos>=8)
{
bool res = send(8);
if (res) state = canState::waitingConfirm;
else state = canState::Error;
return res;
}
return 1; };
void canStream::flush()
{
send(writePos);
};
int canStream::availableForWrite()
{
switch (state)
{
case canState::waitingConfirm: return 0;
}
return 1;
}
#endif

View File

@@ -9,6 +9,10 @@
#endif
#include <itemCmd.h>
#include <Stream.h>
#include <aJSON.h>
#include <streamlog.h>
//#include <config.h> NO!
typedef uint8_t macAddress[6];
@@ -28,7 +32,7 @@ typedef union
} canid_t;
enum payloadType
{
{ unknown=0,
itemCommand=1,
lookupMAC=2,
configFrame=3,
@@ -66,6 +70,7 @@ enum commandType
typedef union {
uint8_t data[8];
char payload[8];
struct {
itemCmdStore cmd;
itemArgStore param;
@@ -87,13 +92,17 @@ typedef union {
enum canState
{
Unknown=0,
MACLookup=2,
HaveId=3,
ConfigFrameRequested=4,
ConfigFrameReceived=5,
ConfigLoaded=6,
Error=7
Unknown,
MACLookup,
Idle,
StreamOpenedWrite,
StreamOpenedRead,
FrameRequested,
FrameReceived,
ReadConfig,
ConfigLoaded,
waitingConfirm,
Error
};
#pragma pack(pop)
@@ -101,25 +110,101 @@ class canDriver
{
public:
canDriver(){ready=false; controllerId=0; responseTimer=0; state=canState::Unknown;};
uint8_t getMyId();
bool sendStatus(char * itemName, itemCmd cmd);
bool sendCommand(uint8_t devID, uint16_t itemID, itemCmd cmd);
bool upTime(uint32_t ut);
bool salt(uint32_t salt);
bool lookupMAC();
bool requestFrame(uint8_t devId, payloadType _payloadType );
int readFrame();
bool sendRemoteID(macAddress mac);
bool begin();
void Poll();
bool processPacket(uint32_t rawid, datagram_t *packet, uint8_t len, bool rtr=false);
bool processPacket(canid_t id, datagram_t *packet, uint8_t len, bool rtr=false);
bool write(uint32_t msg_id, datagram_t * buf = NULL, uint8_t size=0);
private:
uint8_t getControllerID(){return controllerId;};
uint8_t getIdByMac(macAddress mac);
datagram_t RXpacket;
canid_t RXid;
uint8_t RXlen;
private:
aJsonObject * findConfbyID(uint8_t devId);
#if defined(ARDUINO_ARCH_STM32)
CAN_message_t CAN_RX_msg;
CAN_message_t CAN_TX_msg;
#endif
bool ready;
uint8_t controllerId;
canState state;
uint32_t responseTimer;
};
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; }
int open(uint8_t controllerID, payloadType _pType, char _mode)
{
if (mode) close();
devId=controllerID;
pType = _pType;
mode = _mode;
if (mode == 'w') state=canState::StreamOpenedWrite;
else state=canState::StreamOpenedRead;
return 1;
};
int close ()
{
if ((mode == 'w') && writePos) flush();
mode = '\0';
state=canState::Unknown;
return 1;
}
// Stream methods
virtual int available();
virtual int read();
virtual int peek();
virtual void flush();
// Print methods
virtual size_t write(uint8_t c) ;
virtual int availableForWrite();
private:
int send(uint8_t len);
int checkState();
canDriver * driver;
unsigned int readPos;
unsigned int writePos;
datagram_t writeBuffer;
uint8_t devId;
char mode;
payloadType pType;
canState state;
//bool writeBlocked;
};
#endif //

View File

@@ -70,6 +70,7 @@ systemConfig sysConf(&sysConfStream);
#ifdef CANDRV
canDriver LHCAN;
canStream CANConfStream(&LHCAN);
#endif
extern long timer0_overflow_count;
@@ -1572,6 +1573,44 @@ int loadConfigFromEEPROM()
return 0;
}
int loadConfigFromCAN()
{
if (configLocked) return 0;
configLocked++;
infoSerial<<F("Loading Config from CAN")<<endl;
CANConfStream.open(LHCAN.getControllerID(),payloadType::configFrame,'r');
if (CANConfStream.peek() == '{') {
debugSerial<<F("JSON detected")<<endl;
aJsonStream as = aJsonStream(&CANConfStream);
cleanConf(false);
root = aJson.parse(&as);
CANConfStream.close();
if (!root) {
errorSerial<<F("load failed")<<endl;
sysConf.setETAG("");
// sysConfStream.close();
configLocked--;
return 0;
}
infoSerial<<F("Loaded from CAN")<<endl;
configLocked--;
applyConfig();
sysConf.loadETAG();
return 1;
}
CANConfStream.close();
infoSerial<<F("No stored config")<<endl;
configLocked--;
return 0;
}
int cmdFunctionSave(int arg_cnt, char **args)
{
if (arg_cnt>1)

View File

@@ -332,6 +332,7 @@ bool disabledDisconnected(const aJsonObject *thermoExtensionArray, int thermoLat
void resetHard();
bool cleanConf(bool wait);
void printCurentLanConfig();