Merge branch 'master' into flashnew

# Conflicts:
#	src/rp2040_arduino_platform.cpp
#	src/rp2040_arduino_platform.h
This commit is contained in:
SirSydom 2022-02-10 00:09:48 +01:00
commit 9098478614
63 changed files with 1631 additions and 523 deletions

View File

@ -0,0 +1,153 @@
<?xml version="1.0" encoding="utf-8"?>
<KNX xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" CreatedBy="KNX MT" ToolVersion="5.6.407.26745" xmlns="http://knx.org/xml/project/11">
<ManufacturerData>
<Manufacturer RefId="M-00FA">
<Catalog>
<CatalogSection Id="M-00FA_CS-1" Name="Geräte" Number="1" DefaultLanguage="en-US">
<CatalogItem Id="M-00FA_H-12288-1_HP-1074-0B-0000_CI-EC05-1" Name="KNX to 433mhz (DIO)" Number="1" ProductRefId="M-00FA_H-12288-1_P-EC05" Hardware2ProgramRefId="M-00FA_H-12288-1_HP-1074-0B-0000" DefaultLanguage="en-US" />
</CatalogSection>
</Catalog>
<ApplicationPrograms>
<ApplicationProgram Id="M-00FA_A-1074-0B-0000" ApplicationNumber="4212" ApplicationVersion="11" ProgramType="ApplicationProgram" MaskVersion="MV-07B0" Name="SAMD-DIO" LoadProcedureStyle="MergedProcedure" PeiType="0" DefaultLanguage="en-US" DynamicTableManagement="false" Linkable="false" MinEtsVersion="4.0">
<Static>
<Code>
<RelativeSegment Id="M-00FA_A-1074-0B-0000_RS-04-00000" Name="Parameters" Offset="0" Size="34" LoadStateMachine="4" />
</Code>
<ParameterTypes>
<ParameterType Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout" Name="StartupTimeout">
<TypeRestriction Base="Value" SizeInBit="8">
<Enumeration Text="Disabled" Value="0" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-0" />
<Enumeration Text="1 s" Value="1" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-1" />
<Enumeration Text="2 s" Value="2" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-2" />
<Enumeration Text="3 s" Value="3" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-3" />
<Enumeration Text="4 s" Value="4" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-4" />
<Enumeration Text="5 s" Value="5" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-5" />
<Enumeration Text="6 s" Value="6" Id="M-00FA_A-1074-0B-0000_PT-StartupTimeout_EN-6" />
</TypeRestriction>
</ParameterType>
<ParameterType Id="M-00FA_A-1074-0B-0000_PT-TimeCycle" Name="TimeCycle">
<TypeRestriction Base="Value" SizeInBit="8">
<Enumeration Text="Disabled" Value="0" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-0" />
<Enumeration Text="1 sec" Value="1" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-1" />
<Enumeration Text="5 sec" Value="2" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-2" />
<Enumeration Text="15 sec" Value="3" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-3" />
<Enumeration Text="1 min" Value="4" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-4" />
<Enumeration Text="5 min" Value="5" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-5" />
<Enumeration Text="15 min" Value="6" Id="M-00FA_A-1074-0B-0000_PT-TimeCycle_EN-6" />
</TypeRestriction>
</ParameterType>
<ParameterType Id="M-00FA_A-1074-0B-0000_PT-pulseValue" Name="pulseValue">
<TypeNumber SizeInBit="32" Type="signedInt" minInclusive="-2147483648" maxInclusive="2147483647" />
</ParameterType>
</ParameterTypes>
<Parameters>
<Parameter Id="M-00FA_A-1074-0B-0000_P-1" Name="startupTimeout" ParameterType="M-00FA_A-1074-0B-0000_PT-StartupTimeout" Text="Startup delaytime" Value="1">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="0" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-2" Name="timeCycleRefresh" ParameterType="M-00FA_A-1074-0B-0000_PT-TimeCycle" Text="refresh period" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="1" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-3" Name="value1" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Button 1 On" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="2" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-4" Name="value2" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Button 1 Off" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="6" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-5" Name="value3" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Button 2 On" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="10" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-6" Name="value4" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Button 2 Off" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="14" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-7" Name="value5" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Button 3 On" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="18" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-8" Name="value6" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Button 3 Off" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="22" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-9" Name="value7" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Shift On All" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="26" BitOffset="0" />
</Parameter>
<Parameter Id="M-00FA_A-1074-0B-0000_P-10" Name="value8" ParameterType="M-00FA_A-1074-0B-0000_PT-pulseValue" Text="Shift Off All" Value="0">
<Memory CodeSegment="M-00FA_A-1074-0B-0000_RS-04-00000" Offset="30" BitOffset="0" />
</Parameter>
</Parameters>
<ParameterRefs>
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-1_R-1" RefId="M-00FA_A-1074-0B-0000_P-1" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-2_R-2" RefId="M-00FA_A-1074-0B-0000_P-2" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-3_R-3" RefId="M-00FA_A-1074-0B-0000_P-3" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-4_R-4" RefId="M-00FA_A-1074-0B-0000_P-4" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-5_R-5" RefId="M-00FA_A-1074-0B-0000_P-5" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-6_R-6" RefId="M-00FA_A-1074-0B-0000_P-6" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-7_R-7" RefId="M-00FA_A-1074-0B-0000_P-7" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-8_R-8" RefId="M-00FA_A-1074-0B-0000_P-8" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-9_R-9" RefId="M-00FA_A-1074-0B-0000_P-9" />
<ParameterRef Id="M-00FA_A-1074-0B-0000_P-10_R-10" RefId="M-00FA_A-1074-0B-0000_P-10" />
</ParameterRefs>
<ComObjectTable>
<ComObject Id="M-00FA_A-1074-0B-0000_O-1" Name="trigger value 1" Text="trigger value 1" Number="1" FunctionText="get/set button 1" ObjectSize="1 Bit" ReadFlag="Enabled" WriteFlag="Enabled" CommunicationFlag="Enabled" TransmitFlag="Enabled" UpdateFlag="Disabled" ReadOnInitFlag="Disabled" />
<ComObject Id="M-00FA_A-1074-0B-0000_O-2" Name="trigger value 2" Text="trigger value 2" Number="2" FunctionText="get/set button 2" ObjectSize="1 Bit" ReadFlag="Enabled" WriteFlag="Enabled" CommunicationFlag="Enabled" TransmitFlag="Enabled" UpdateFlag="Disabled" ReadOnInitFlag="Disabled" />
<ComObject Id="M-00FA_A-1074-0B-0000_O-3" Name="trigger value 3" Text="trigger value 3" Number="3" FunctionText="get/set button 3" ObjectSize="1 Bit" ReadFlag="Enabled" WriteFlag="Enabled" CommunicationFlag="Enabled" TransmitFlag="Enabled" UpdateFlag="Disabled" ReadOnInitFlag="Disabled" />
<ComObject Id="M-00FA_A-1074-0B-0000_O-4" Name="trigger value 4" Text="trigger value 4" Number="4" FunctionText="get/set All buttons" ObjectSize="1 Bit" ReadFlag="Enabled" WriteFlag="Enabled" CommunicationFlag="Enabled" TransmitFlag="Enabled" UpdateFlag="Disabled" ReadOnInitFlag="Disabled" />
<ComObject Id="M-00FA_A-1074-0B-0000_O-5" Name="trigger progMode" Text="trigger progMode" Number="5" FunctionText="put device in ETS programmation" ObjectSize="1 Bit" ReadFlag="Disabled" WriteFlag="Enabled" CommunicationFlag="Enabled" TransmitFlag="Enabled" UpdateFlag="Disabled" ReadOnInitFlag="Disabled" />
</ComObjectTable>
<ComObjectRefs>
<ComObjectRef Id="M-00FA_A-1074-0B-0000_O-1_R-1" RefId="M-00FA_A-1074-0B-0000_O-1" />
<ComObjectRef Id="M-00FA_A-1074-0B-0000_O-2_R-2" RefId="M-00FA_A-1074-0B-0000_O-2" />
<ComObjectRef Id="M-00FA_A-1074-0B-0000_O-3_R-3" RefId="M-00FA_A-1074-0B-0000_O-3" />
<ComObjectRef Id="M-00FA_A-1074-0B-0000_O-4_R-4" RefId="M-00FA_A-1074-0B-0000_O-4" />
<ComObjectRef Id="M-00FA_A-1074-0B-0000_O-5_R-5" RefId="M-00FA_A-1074-0B-0000_O-5" />
</ComObjectRefs>
<AddressTable MaxEntries="65000" />
<AssociationTable MaxEntries="65000" />
<LoadProcedures>
<LoadProcedure MergeId="2">
<LdCtrlRelSegment LsmIdx="4" Size="34" Mode="0" Fill="0" AppliesTo="full" />
</LoadProcedure>
<LoadProcedure MergeId="4">
<LdCtrlWriteRelMem ObjIdx="4" Offset="0" Size="34" Verify="true" />
</LoadProcedure>
</LoadProcedures>
<Options />
</Static>
<Dynamic>
<ChannelIndependentBlock>
<ParameterBlock Id="M-00FA_A-1074-0B-0000_PB-1" Name="ParameterPage" Text="Common Parameters">
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-1_R-1" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-2_R-2" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-3_R-3" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-4_R-4" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-5_R-5" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-6_R-6" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-7_R-7" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-8_R-8" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-9_R-9" />
<ParameterRefRef RefId="M-00FA_A-1074-0B-0000_P-10_R-10" />
<ComObjectRefRef RefId="M-00FA_A-1074-0B-0000_O-1_R-1" />
<ComObjectRefRef RefId="M-00FA_A-1074-0B-0000_O-2_R-2" />
<ComObjectRefRef RefId="M-00FA_A-1074-0B-0000_O-3_R-3" />
<ComObjectRefRef RefId="M-00FA_A-1074-0B-0000_O-4_R-4" />
<ComObjectRefRef RefId="M-00FA_A-1074-0B-0000_O-5_R-5" />
</ParameterBlock>
</ChannelIndependentBlock>
</Dynamic>
</ApplicationProgram>
</ApplicationPrograms>
<Hardware>
<Hardware Id="M-00FA_H-12288-1" Name="SAMD21-KNXto433" SerialNumber="12288" VersionNumber="1" BusCurrent="10" HasIndividualAddress="true" HasApplicationProgram="true">
<Products>
<Product Id="M-00FA_H-12288-1_P-EC05" Text="KNX to 433mhz (DIO)" OrderNumber="EC05" IsRailMounted="false" DefaultLanguage="en-US">
<RegistrationInfo RegistrationStatus="Registered" />
</Product>
</Products>
<Hardware2Programs>
<Hardware2Program Id="M-00FA_H-12288-1_HP-1074-0B-0000" MediumTypes="MT-0">
<ApplicationProgramRef RefId="M-00FA_A-1074-0B-0000" />
<RegistrationInfo RegistrationStatus="Registered" RegistrationNumber="0001/111" />
</Hardware2Program>
</Hardware2Programs>
</Hardware>
</Hardware>
</Manufacturer>
</ManufacturerData>
</KNX>

View File

@ -0,0 +1,32 @@
Control Chacon/DIO 433Mhz plug like that: (not an affiliated link just for info)
https://www.amazon.fr/DiO-Connected-Home-t%C3%A9l%C3%A9command%C3%A9es-t%C3%A9l%C3%A9commande/dp/B005LKMAW0
Hardware:
- Samd21 (gy-samd21)
- FS 1000A (cheap 433 transmitter)
- TpUart KNX
- logic level converter
- Chacon/DIO 433Mhz plug (must work with every dumb 433mhz plug/remote that support the HomeEasy protocol)
Software
- change the rfPin variable, compile and tranfert into the samd21 (or any microcontroller)
- (maybe) adapt THIGH and TLOW in rfCode class for your case.
Before configuring ETS, you need to receive the 433mhz code for each button of your remote.
Take an arduino UNO, plug the FS1000a receiver, look on github/google to receive the code rc-switch or https://charleslabs.fr/fr/project-Contr%C3%B4le+de+prises+DiO+avec+Arduino (in french), or https://caron.ws/diy-cartes-microcontroleurs/piloter-vos-prises-chacon-rf433mhz-arduino/ ( in french too)
for me it's : 1806947472 and 1806947456 for the channel 1 on/off, etc...
Now in ETS put the received 433Mhz code into parameters.
-> Full Download in ETS and enjoy.
Feature:
This code is delay() free, blocking code free (ie: no long while or for loop), to call the knx.loop() as fast as possible.

Binary file not shown.

View File

@ -0,0 +1,368 @@
#include <knx.h>
//#include <DiOremote.h>
//#define DEBUGSERIAL 1
#ifdef DEBUGSERIAL
#define DPRINT(...) SerialUSB.print(__VA_ARGS__)
#define DPRINTLN(...) SerialUSB.println(__VA_ARGS__)
#include <MemoryFree.h>
#include <pgmStrToRAM.h>
#else
#define DPRINT(...) //now defines a blank line
#define DPRINTLN(...) //now defines a blank line
#endif
#define goButton1 knx.getGroupObject(1)
#define goButton2 knx.getGroupObject(2)
#define goButton3 knx.getGroupObject(3)
#define goButtonAll knx.getGroupObject(4)
#define goProgMode knx.getGroupObject(5)
//DiOremote myRemote = DiOremote(6);
//void function2();
//void function1(void (*)());
//void loop() {
// function1(function2);
//}
//Global Const
const uint8_t ets_startupTimeout[7] = {0, 1, 2, 3, 4, 5, 6};
const uint16_t ets_timePeriod[7] = {0, 1, 5, 15, 1 * 60, 5 * 60, 15 * 60};
const uint8_t ets_progMode[7] = {0, 1, 2 * 60, 3 * 60, 4 * 60, 5 * 60, 10 * 60}; //need knxprod update... ?
const uint8_t ledPin = LED_BUILTIN;
const uint8_t rfPin = 6;
// //Protocol timing (in us)
// #define DiOremote_START_FRAME_1 220
// #define DiOremote_START_FRAME_0 2675
// #define DiOremote_THIGH 220
// #define DiOremote_TLOW_0 350 short
// #define DiOremote_TLOW_1 1400 long
// #define DiOremote_END_FRAME_1 220
// #define DiOremote_END_FRAME_0 10600
// Global Variable
bool progMode = true;
// bool codeSendindBlock = false;
uint8_t percentCycle = 0; // better to define a global or read knx.paramByte each time... ?
uint32_t timePeriod = 0; // same here,
uint32_t timerProgMode = 0; // same here,
uint32_t ch1_on, ch1_off, ch2_on, ch2_off, ch3_on, ch3_off, chall_on, chall_off;
class RfCode {
private:
uint8_t _rfPin;
uint32_t _codeValueOn;
uint32_t _codeValueOff;
uint8_t _GOaddress;
const uint16_t THIGH = 220, TSTART = 2675, TSHORT = 220, TLONG = 1400, TEND = 10600;
uint8_t _loopCount = 0; // fixed ==5
bool lastState = false;
uint32_t _codePending = 0;
uint32_t _codePendingMemory = _codePending;
uint8_t _loopPending = 0; // fixed ==32
bool _sendMsgPending= false;
enum PulseStates {
PULSE_INIT,
PULSE_KEY1, //32 times loop
PULSE_KEY2, //32 times loop
PULSE_END
};
PulseStates pulseStates = PULSE_INIT;
bool pulseSend(const uint16_t delayHigh, const uint16_t delayLow){ //alike state machine?
static bool initPulse = false;
static bool highDone = false;
static uint32_t pulseLastTime = 0;
uint32_t currentTime = micros();
if (!initPulse){
initPulse = true;
digitalWrite(_rfPin, HIGH);
pulseLastTime = currentTime;
}
else if (currentTime - pulseLastTime >= delayHigh && !highDone)
{
digitalWrite(_rfPin, LOW);
pulseLastTime = currentTime;
highDone = true;
}
else if (currentTime - pulseLastTime >= delayLow && highDone)
{
initPulse = false;
highDone = false;
}
return !initPulse;
}
uint16_t TTime(bool invert){
uint16_t TTIME;
if (_codePending & 0x80000000L)// future bug if uint32_t _codePengin > 2^32 / 2 ?
{
TTIME = invert ? TSHORT : TLONG;
}
else
{
TTIME = invert ? TLONG : TSHORT;
}
return TTIME;
}
public:
RfCode(uint8_t rfPin){
_rfPin = rfPin;
pinMode(_rfPin, OUTPUT);
}
// void init(uint8_t addr, uint32_t codeValueOn, uint32_t codeValueOff){ //GroupObject &device, long timeOn){
// _codeValueOn = codeValueOn;
// _codeValueOff = codeValueOff;
// _GOaddress = addr;
// }
void setState(bool modeOnOff, uint32_t codeValueOn, uint32_t codeValueOff){
if (!_sendMsgPending)
{
_sendMsgPending = true;
_codeValueOn = codeValueOn;
_codeValueOff = codeValueOff;
// _GOaddress = addr;
if (modeOnOff){
_codePending = _codeValueOn;
// SerialUSB.println(_codePending);
}
else
{
_codePending = _codeValueOff;
// SerialUSB.println(_codePending);
}
_codePendingMemory = _codePending;
}
}
// bool getMsgPendingState(){
// return _sendMsgPending;
// }
void loop(){
if (_sendMsgPending)
{
// needed to block setState of another Class, yes FIFO is better...
// codeSendindBlock = true;
if (_loopCount < 5)
{
switch (pulseStates){
case PULSE_INIT:
if (pulseSend(THIGH, TSTART)){
pulseStates = PULSE_KEY1;
}
break;
case PULSE_KEY1:
if (pulseSend(THIGH, TTime(false)))
{
pulseStates = PULSE_KEY2;
}
break;
case PULSE_KEY2:
if (pulseSend(THIGH, TTime(true)))
{
if (_loopPending < 32){
_codePending <<= 1;
_loopPending++;
pulseStates = PULSE_KEY1; // next loop !
}
else{ // finish!
pulseStates = PULSE_END;
}
}
break;
case PULSE_END:
if (pulseSend(THIGH, TEND)){
_loopCount++;
_codePending = _codePendingMemory;
_loopPending = 0;
pulseStates = PULSE_INIT;
}
break;
default:
break;
}
}
else
{
_loopCount = 0;
_sendMsgPending = false;
// codeSendindBlock = false;
}
}
}
};
class Blinker
{
private:
uint8_t ledPin_; // the number of the LED pin
uint32_t OnTime = 1000; // milliseconds of on-time
uint32_t OffTime = 1000; // milliseconds of off-time
bool ledState = LOW; // ledState used to set the LED
uint32_t previousMillis; // will store last time LED was updated
void setOutput(bool state_, uint32_t currentMillis_){
ledState = state_;
previousMillis = currentMillis_;
digitalWrite(ledPin_, state_);
}
public:
Blinker(uint8_t pin)
{
ledPin_ = pin;
pinMode(ledPin_, OUTPUT);
previousMillis = 0;
}
void set(uint32_t on, uint32_t off){
OnTime = on;
OffTime = off;
}
void loop(){
uint32_t currentMillis = millis();
if((ledState == HIGH) && (currentMillis - previousMillis >= OnTime))
{
setOutput(LOW, currentMillis);
}
else if ((ledState == LOW) && (currentMillis - previousMillis >= OffTime))
{
setOutput(HIGH, currentMillis);
}
}
};
RfCode button = RfCode(5);
Blinker led = Blinker(ledPin);
void callBackButton1(GroupObject& go){
button.setState((bool)go.value(), ch1_on, ch1_off);
}
void callBackButton2(GroupObject& go){
button.setState((bool)go.value(), ch2_on, ch2_off);
}
void callBackButton3(GroupObject& go){
button.setState((bool)go.value(), ch3_on, ch3_off);
}
void callBackButtonAll(GroupObject& go){
button.setState((bool)go.value(), chall_on, ch3_off);
}
void callBackProgMode(GroupObject& go){
progMode = (bool)go.value();
}
void setup() {
// #ifdef DEBUGSERIAL
// SerialUSB.begin(9600);
// while (!SerialUSB) { //wait for DEBUGING
// ; // wait for serial port to connect. Needed for native USB port only
// }
// ArduinoPlatform::SerialDebug = &SerialUSB;
// #endif
randomSeed(millis());
// knx.bau().deviceObject().individualAddress(1);
knx.readMemory();
if (knx.configured())
{
DPRINT("Setup: KNX Configuration...");
progMode = false; // don't need to put device in progMode.
int confStartupTime = ets_startupTimeout[knx.paramByte(0)] * 1000;
delay(confStartupTime); // the only delay used, why make a withoutDelay function for that?
timePeriod = ets_timePeriod[knx.paramByte(1)] * 1000;
// timerProgMode = ets_progMode[knx.paramByte(34)] * 1000;
ch1_on = knx.paramInt(2);
ch1_off = knx.paramInt(6);
goButton1.callback(callBackButton1);
goButton1.dataPointType(DPT_Switch);
ch2_on = knx.paramInt(10);
ch2_off = knx.paramInt(14);
goButton2.callback(callBackButton2);
goButton2.dataPointType(DPT_Switch);
ch3_on = knx.paramInt(18);
ch3_off = knx.paramInt(22);
goButton3.callback(callBackButton3);
goButton3.dataPointType(DPT_Switch);
chall_on = knx.paramByte(26);
chall_off = knx.paramByte(30);
goButtonAll.callback(callBackButtonAll);
goButtonAll.dataPointType(DPT_Switch);
goProgMode.callback(callBackProgMode);
goProgMode.dataPointType(DPT_Trigger);
DPRINTLN("Finished");
}
knx.ledPin(5);
knx.ledPinActiveOn(HIGH);
knx.buttonPin(9);
knx.start();
led.set(2000, 2000);
}
void loop()
{
knx.loop();
led.loop();
if (knx.configured() && !progMode)
{
button.loop();
}
else if (progMode)
{
prodModeLoop();
}
}
void prodModeLoop(){ // run Only if progMode triggered ( at start or callback)
const uint32_t timerProgMode = ( 15 * 60 * 1000 ) ; // 15min
static uint32_t timerProgPrevMillis = 0;
if (!knx.progMode())
{
knx.progMode(true);
led.set(500, 500);
timerProgPrevMillis = millis();
DPRINTLN("progModeLoop Start");
}
else
{
if (millis() - timerProgPrevMillis > timerProgMode) {
knx.progMode(false);
goProgMode.value(false);
progMode = 0;
led.set(100, 100); // panic!
DPRINTLN("progModeLoop Stop");
}
}
}

View File

@ -25,7 +25,7 @@
void checkIaqSensorStatus(void);
void errLeds(void);
uint8_t* saveBme680State(uint8_t* buffer);
uint8_t* loadBme680State(uint8_t* buffer);
const uint8_t* loadBme680State(const uint8_t* buffer);
void triggerCallback(GroupObject& go);
void updateState();
@ -53,6 +53,10 @@ void setup(void)
wifiManager.autoConnect("knx-bme680");
#endif
// set save and restore callbacks
knx.setSaveCallback(saveBme680State);
knx.setRestoreCallback(loadBme680State);
// read adress table, association table, groupobject table and parameters from eeprom
knx.readMemory();
@ -60,7 +64,6 @@ void setup(void)
if(knx.configured())
goTriggerSample.callback(triggerCallback);
// Configure Wire pins before this call if needed.
Wire.begin();
// depends on sensor board. Try BME680_I2C_ADDR_PRIMARY if it doen't work.
@ -87,9 +90,6 @@ void setup(void)
BSEC_OUTPUT_GAS_PERCENTAGE
};
knx.setSaveCallback(saveBme680State);
knx.setRestoreCallback(loadBme680State);
if (knx.configured())
{
cyclSend = knx.paramInt(0);
@ -214,7 +214,7 @@ void errLeds(void)
delay(100);
}
uint8_t* loadBme680State(uint8_t* buffer)
const uint8_t* loadBme680State(const uint8_t* buffer)
{
// Existing state in EEPROM
Serial.println("Reading state from EEPROM");

View File

@ -0,0 +1,129 @@
#include <knx.h>
#ifdef ARDUINO_ARCH_ESP8266
#include <WiFiManager.h>
#endif
/*****************************************
* changes necessary for SMALL_GROUPOBJECT
* are commented with //**
* This project can be used with any
* of the knxprod files of the original
* knx-demo project.
*****************************************/
// create named references for easy access to group objects
#define goCurrent knx.getGroupObject(1)
#define goMax knx.getGroupObject(2)
#define goMin knx.getGroupObject(3)
#define goReset knx.getGroupObject(4)
float currentValue = 0;
float maxValue = 0;
float minValue = RAND_MAX;
long lastsend = 0;
void measureTemp()
{
long now = millis();
if ((now - lastsend) < 2000)
return;
lastsend = now;
int r = rand();
currentValue = (r * 1.0) / (RAND_MAX * 1.0);
currentValue *= 100 * 100;
// write new value to groupobject
goCurrent.value(currentValue, DPT_Value_Temp); //** each value access needs to done with according DPT parameter
if (currentValue > maxValue)
{
maxValue = currentValue;
goMax.value(maxValue, DPT_Value_Temp); //** each value access needs to done with according DPT parameter
}
if (currentValue < minValue)
{
minValue = currentValue;
goMin.value(minValue, DPT_Value_Temp); //** each value access needs to done with according DPT parameter
}
}
// callback from reset-GO
void resetCallback(GroupObject& go)
{
//** callbacks are now handled in the class, not per instance,
//** this means, we have to check, which GroupObject is calling back
if (go.asap() == goReset.asap())
{
if (go.value(DPT_Trigger)) //** each value access needs to done with according DPT parameter
{
maxValue = 0;
minValue = 10000;
}
}
}
void setup()
{
Serial.begin(115200);
ArduinoPlatform::SerialDebug = &Serial;
randomSeed(millis());
#ifdef ARDUINO_ARCH_ESP8266
WiFiManager wifiManager;
wifiManager.autoConnect("knx-demo");
#endif
// read adress table, association table, groupobject table and parameters from eeprom
knx.readMemory();
// print values of parameters if device is already configured
if (knx.configured())
{
// register callback for reset GO
GroupObject::classCallback(resetCallback); //** callbacks are now handled per class, not per instance
//** there is no global assignment of DPT for GroupObjects
// goReset.dataPointType(DPT_Trigger);
// goCurrent.dataPointType(DPT_Value_Temp);
// goMin.dataPointType(DPT_Value_Temp);
// goMax.dataPointType(DPT_Value_Temp);
Serial.print("Timeout: ");
Serial.println(knx.paramByte(0));
Serial.print("Zykl. senden: ");
Serial.println(knx.paramByte(1));
Serial.print("Min/Max senden: ");
Serial.println(knx.paramByte(2));
Serial.print("Aenderung senden: ");
Serial.println(knx.paramByte(3));
Serial.print("Abgleich: ");
Serial.println(knx.paramByte(4));
}
// pin or GPIO the programming led is connected to. Default is LED_BUILTIN
// knx.ledPin(LED_BUILTIN);
// is the led active on HIGH or low? Default is LOW
// knx.ledPinActiveOn(HIGH);
// pin or GPIO programming button is connected to. Default is 0
// knx.buttonPin(0);
// Is the interrup created in RISING or FALLING signal? Default is RISING
// knx.buttonPinInterruptOn(FALLING);
// start the framework.
knx.start();
}
void loop()
{
// don't delay here to much. Otherwise you might lose packages or mess up the timing with ETS
knx.loop();
// only run the application code if the device was configured with ETS
if (!knx.configured())
return;
measureTemp();
}

View File

@ -0,0 +1,120 @@
;PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[platformio]
; We have to keep libdeps dir out the project directory otherwise,
; library scanner seems to have issues so compilation fails
libdeps_dir = /tmp/libdeps
src_dir = .
;--- SAMD --------------------------------------------------
; SMALL_GROUPOBJECT just tested with TP on SAMD, but should work also in other environments
[env:zeroUSB]
platform = atmelsam
board = zeroUSB
framework = arduino
; We consider that the this projects is opened within its project directory
; while working with VS Code.
lib_extra_dirs = ../../../
lib_deps =
SPI
https://github.com/thelsing/FlashStorage.git
knx
build_flags =
-DMASK_VERSION=0x07B0
-DSMALL_GROUPOBJECT
-Wno-unknown-pragmas
; [env:adafruit_feather_m0_rf]
; platform = atmelsam
; board = adafruit_feather_m0
; framework = arduino
; ; We consider that the this projects is opened within its project directory
; ; while working with VS Code.
; lib_extra_dirs = ../../../
; lib_deps =
; SPI
; https://github.com/thelsing/FlashStorage.git
; knx
; build_flags =
; -DMASK_VERSION=0x27B0
; -Wno-unknown-pragmas
;-----------------------------------------------------------
;--- ESP8266 -----------------------------------------------
#[env:nodemcuv2_ip]
#platform = espressif8266
#board = nodemcuv2
#framework = arduino
; We consider that the this projects is opened within its project directory
; while working with VS Code.
#lib_extra_dirs = ../../../
#lib_deps =
# WifiManager
# knx
#build_flags =
# -DMASK_VERSION=0x57B0
# -Wno-unknown-pragmas
; [env:nodemcuv2_tp]
; platform = espressif8266
; board = nodemcuv2
; framework = arduino
; ; We consider that the this projects is opened within its project directory
; ; while working with VS Code.
; lib_extra_dirs = ../../../
; lib_deps =
; WifiManager
; knx
; build_flags =
; -DMASK_VERSION=0x07B0
; -Wno-unknown-pragmas
;---------------------------------------------------------
;--- ESP32 -----------------------------------------------
; [env:esp32dev_ip]
; platform = espressif32
; board = esp32dev
; framework = arduino
; ; We consider that the this projects is opened within its project directory
; ; while working with VS Code.
; lib_extra_dirs = ../../../
; lib_deps =
; knx
; build_flags =
; -DMASK_VERSION=0x57B0
; -Wno-unknown-pragmas
; [env:esp32dev_tp]
; platform = espressif32
; board = esp32dev
; framework = arduino
; ; We consider that the this projects is opened within its project directory
; ; while working with VS Code.
; lib_extra_dirs = ../../../
; lib_deps =
; knx
; build_flags =
; -DMASK_VERSION=0x07B0
; -Wno-unknown-pragmas

View File

@ -1,6 +1,7 @@
#include <Arduino.h>
#include <knx.h>
#ifdef ARDUINO_ARCH_ESP8266
#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32)
#include <WiFiManager.h>
#endif
@ -59,7 +60,7 @@ void setup()
randomSeed(millis());
#ifdef ARDUINO_ARCH_ESP8266
#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32)
WiFiManager wifiManager;
wifiManager.autoConnect("knx-demo");
#endif

View File

@ -40,7 +40,7 @@ build_flags =
-DUSE_DATASECURE
[env:nodemcuv2_tp]
platform = espressif8266
platform = espressif8266@^2
board = nodemcuv2
framework = arduino
lib_deps =
@ -61,6 +61,7 @@ platform = espressif32
board = esp32dev
framework = arduino
lib_deps =
https://github.com/tzapu/WiFiManager.git
knx
build_flags =

View File

@ -51,7 +51,7 @@ build_flags =
# -Wno-unknown-pragmas
[env:nodemcuv2_tp]
platform = espressif8266
platform = espressif8266@^2
board = nodemcuv2
framework = arduino
; We consider that the this projects is opened within its project directory
@ -59,7 +59,7 @@ framework = arduino
lib_extra_dirs = ../../../
lib_deps =
WifiManager
WifiManager@0.15.0
knx
build_flags =
@ -79,6 +79,7 @@ framework = arduino
lib_extra_dirs = ../../../
lib_deps =
https://github.com/tzapu/WiFiManager.git
knx
build_flags =

View File

@ -82,7 +82,7 @@ int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePa
int next = 1;
int bitsLeft = 8;
while (count < bufSize && (bitsLeft > 0 || next < length))
while (bitsLeft > 0 || next < length)
{
if (bitsLeft < 5)
{

View File

@ -82,7 +82,7 @@ int FdskCalculator::toBase32(uint8_t* in, long length, uint8_t*& out, bool usePa
int next = 1;
int bitsLeft = 8;
while (count < bufSize && (bitsLeft > 0 || next < length))
while (bitsLeft > 0 || next < length)
{
if (bitsLeft < 5)
{

View File

@ -38,7 +38,7 @@ const uint8_t physicalCount = 6; // voltage,current,power_factor,power,energy,fr
uint8_t percentCycle = 0; // better to define a global or read knx.paramByte each time... ?
uint32_t timePeriod = 0; // same here,
uint8_t resetPeriod = 0; //same here ...
uint8_t resetEnergy = 0; // and here... disabled/day/week/month
//uint8_t resetEnergy = 0; // and here... disabled/day/week/month
bool progMode = true;
@ -54,11 +54,10 @@ struct Physical {
void loop(){
// unsigned long currentMillis = millis();
// Delta Change update as defined in ETS
int32_t deltaPercent = ( 100 * ( _value - _lastValue ) / _value );
float deltaPercent = ( 100 * ( _value - _lastValue ) / _value );
if ( percentCycle != 0 && abs(deltaPercent) >= percentCycle )
{
_trigger = true;
_lastValue = _value;
}
// Refresh groupAddress value as defined in ETS since last update
@ -70,6 +69,7 @@ struct Physical {
// UpdateGO but send to bus only if triggered by time or value change percentage
if (_trigger){
knx.getGroupObject(_GOaddr).value(_value, _dpt);
_lastValue = _value;
_lastMillis = millis();
_trigger = false;
}else{
@ -143,7 +143,6 @@ class Blinker
Blinker led = Blinker(ledPin);
void callBackProgMode(GroupObject& go){
progMode = (bool)go.value();
}
@ -172,7 +171,7 @@ void resetCallback(GroupObject& go)
{
if (go.value())
{
resetEnergy = true;
pzem.resetEnergy();
goReset.value(false);
}
}
@ -181,7 +180,7 @@ void setup() {
pinPeripheral(PIN_SERIAL2_RX, PIO_SERCOM);
pinPeripheral(PIN_SERIAL2_TX, PIO_SERCOM);
SerialUSB.begin(9600);
// SerialUSB.begin(9600);
Serial2.begin(9600);
ArduinoPlatform::SerialDebug = &SerialUSB;
@ -238,12 +237,17 @@ void loop() {
if (knx.configured() && !progMode)
{
refreshValueLoop();
resetEnergyLoop();
for (uint8_t i=0; i< physicalCount; i++)
{
Physical[i].loop();
}
if (timeStatus() == timeSet && resetPeriod != 0)
{
resetEnergyLoop();
}
}
else if (progMode)
{
@ -257,7 +261,7 @@ void refreshValueLoop(){
if (millis() - lastPzemUpdate >= pzemInterval)
{
for (uint8_t i=0; i< physicalCount; i++)
for (uint8_t i=0; i < physicalCount; i++)
{
float isaValue;
switch (i) { //maybe a pointer or reference could be nicer...
@ -282,11 +286,18 @@ void refreshValueLoop(){
default:
break;
}
if(!isnan(isaValue))
{
Physical[i].setValue(isaValue);
}
else
{
Physical[i].setValue(-1);
}
}
lastPzemUpdate = millis();
led.set(500, 1000);
}
}
@ -339,14 +350,14 @@ void prodModeLoop(){ // run Only if progMode triggered ( at start or callback)
{
knx.progMode(true);
timerProgPrevMillis = millis();
led.set(500, 250);
led.set(50, 100);
}
else
{
if (millis() - timerProgPrevMillis > timerProgMode) {
knx.progMode(false);
goProgMode.value(false);
progMode = 0;
progMode = false;
}
}
}

View File

@ -8,7 +8,7 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:adafruit_feather_m0]
platform = atmelsam
platform = atmelsam@6.0.1
board = adafruit_feather_m0
framework = arduino

View File

@ -13,7 +13,7 @@
libdeps_dir = /tmp/libdeps
[env:adafruit_feather_m0]
platform = atmelsam
platform = atmelsam@6.0.1
board = adafruit_feather_m0
framework = arduino
; We consider that the this projects is opened within its project directory
@ -27,7 +27,7 @@ board_build.usb_product="KNX RF - USB Interface"
lib_deps =
SPI
Adafruit TinyUSB Library
Adafruit TinyUSB Library@0.7.1
https://github.com/thelsing/FlashStorage.git
knx

View File

@ -2,9 +2,17 @@
#include "knx/bits.h"
#include <Arduino.h>
#ifndef KNX_NO_SPI
#include <SPI.h>
#endif
#ifndef KNX_NO_PRINT
Stream* ArduinoPlatform::SerialDebug = &Serial;
#endif
ArduinoPlatform::ArduinoPlatform() : _knxSerial(nullptr)
{
}
ArduinoPlatform::ArduinoPlatform(HardwareSerial* knxSerial) : _knxSerial(knxSerial)
{
@ -27,7 +35,8 @@ void ArduinoPlatform::fatalError()
void ArduinoPlatform::knxUart( HardwareSerial* serial )
{
closeUart();
if (_knxSerial)
closeUart();
_knxSerial = serial;
setupUart();
}
@ -94,6 +103,7 @@ size_t ArduinoPlatform::readBytesUart(uint8_t *buffer, size_t length)
return length;
}
#ifndef KNX_NO_SPI
void ArduinoPlatform::setupSpi()
{
SPI.begin();
@ -111,7 +121,9 @@ int ArduinoPlatform::readWriteSpi(uint8_t *data, size_t len)
SPI.transfer(data, len);
return 0;
}
#endif
#ifndef KNX_NO_PRINT
void printUint64(uint64_t value, int base = DEC)
{
char buf[8 * sizeof(uint64_t) + 1];
@ -284,3 +296,4 @@ void println(void)
{
ArduinoPlatform::SerialDebug->println();
}
#endif // KNX_NO_PRINT

View File

@ -2,11 +2,10 @@
#include "Arduino.h"
extern Stream& _serialDBG;
class ArduinoPlatform : public Platform
{
public:
ArduinoPlatform();
ArduinoPlatform(HardwareSerial* knxSerial);
// basic stuff
@ -24,11 +23,14 @@ class ArduinoPlatform : public Platform
virtual size_t readBytesUart(uint8_t* buffer, size_t length);
//spi
#ifndef KNX_NO_SPI
void setupSpi() override;
void closeSpi() override;
int readWriteSpi (uint8_t *data, size_t len) override;
#endif
#ifndef KNX_NO_PRINT
static Stream* SerialDebug;
#endif
protected:
HardwareSerial* _knxSerial;

View File

@ -134,6 +134,7 @@ void delayMicroseconds (unsigned int howLong)
ClockP_usleep(howLong);
}
#ifndef KNX_NO_PRINT
size_t write(uint8_t c)
{
#if defined(PRINT_UART)
@ -402,6 +403,7 @@ void println(double num)
// default: print 10 digits
println(num, 10);
}
#endif // KNX_NO_PRINT
uint32_t digitalRead(uint32_t dwPin)
{

View File

@ -6,7 +6,10 @@
#include "knx/bits.h"
Esp32Platform::Esp32Platform() : ArduinoPlatform(&Serial1)
Esp32Platform::Esp32Platform()
#ifndef KNX_NO_DEFAULT_UART
: ArduinoPlatform(&Serial1)
#endif
{
}
@ -34,6 +37,14 @@ void Esp32Platform::macAddress(uint8_t * addr)
esp_wifi_get_mac(WIFI_IF_STA, addr);
}
uint32_t Esp32Platform::uniqueSerialNumber()
{
uint64_t chipid = ESP.getEfuseMac();
uint32_t upperId = (chipid >> 32) & 0xFFFFFFFF;
uint32_t lowerId = (chipid & 0xFFFFFFFF);
return (upperId ^ lowerId);
}
void Esp32Platform::restart()
{
println("restart");
@ -81,6 +92,18 @@ int Esp32Platform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen)
return len;
}
bool Esp32Platform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
{
IPAddress ucastaddr(htonl(addr));
println("sendBytesUniCast endPacket fail");
if(_udp.beginPacket(ucastaddr, port) == 1) {
_udp.write(buffer, len);
if(_udp.endPacket() == 0) println("sendBytesUniCast endPacket fail");
}
else println("sendBytesUniCast beginPacket fail");
return true;
}
uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
{
EEPROM.begin(size);
@ -89,6 +112,7 @@ uint8_t * Esp32Platform::getEepromBuffer(uint16_t size)
void Esp32Platform::commitToEeprom()
{
EEPROM.getDataPtr(); // trigger dirty flag in EEPROM lib to make sure data will be written to flash
EEPROM.commit();
}

View File

@ -16,6 +16,9 @@ public:
uint32_t currentDefaultGateway() override;
void macAddress(uint8_t* addr) override;
// unique serial number
uint32_t uniqueSerialNumber() override;
// basic stuff
void restart();
@ -25,6 +28,9 @@ public:
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override;
//unicast
bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
//memory
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();

View File

@ -7,7 +7,10 @@
#include "knx/bits.h"
EspPlatform::EspPlatform() : ArduinoPlatform(&Serial)
EspPlatform::EspPlatform()
#ifndef KNX_NO_DEFAULT_UART
: ArduinoPlatform(&Serial)
#endif
{
}
@ -35,6 +38,11 @@ void EspPlatform::macAddress(uint8_t * addr)
wifi_get_macaddr(STATION_IF, addr);
}
uint32_t EspPlatform::uniqueSerialNumber()
{
return ESP.getChipId();
}
void EspPlatform::restart()
{
println("restart");
@ -43,9 +51,9 @@ void EspPlatform::restart()
void EspPlatform::setupMultiCast(uint32_t addr, uint16_t port)
{
_mulitcastAddr = htonl(addr);
_mulitcastPort = port;
IPAddress mcastaddr(_mulitcastAddr);
_multicastAddr = htonl(addr);
_multicastPort = port;
IPAddress mcastaddr(_multicastAddr);
Serial.printf("setup multicast addr: %s port: %d ip: %s\n", mcastaddr.toString().c_str(), port,
WiFi.localIP().toString().c_str());
@ -61,7 +69,7 @@ void EspPlatform::closeMultiCast()
bool EspPlatform::sendBytesMultiCast(uint8_t * buffer, uint16_t len)
{
//printHex("<- ",buffer, len);
_udp.beginPacketMulticast(_mulitcastAddr, _mulitcastPort, WiFi.localIP());
_udp.beginPacketMulticast(_multicastAddr, _multicastPort, WiFi.localIP());
_udp.write(buffer, len);
_udp.endPacket();
return true;
@ -84,6 +92,18 @@ int EspPlatform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen)
return len;
}
bool EspPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
{
IPAddress ucastaddr(htonl(addr));
println("sendBytesUniCast endPacket fail");
if(_udp.beginPacket(ucastaddr, port) == 1) {
_udp.write(buffer, len);
if(_udp.endPacket() == 0) println("sendBytesUniCast endPacket fail");
}
else println("sendBytesUniCast beginPacket fail");
return true;
}
uint8_t * EspPlatform::getEepromBuffer(uint16_t size)
{
EEPROM.begin(size);

View File

@ -16,6 +16,9 @@ class EspPlatform : public ArduinoPlatform
uint32_t currentDefaultGateway() override;
void macAddress(uint8_t* addr) override;
// unique serial number
uint32_t uniqueSerialNumber() override;
// basic stuff
void restart();
@ -25,13 +28,16 @@ class EspPlatform : public ArduinoPlatform
bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override;
int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override;
//unicast
bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override;
//memory
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();
private:
WiFiUDP _udp;
uint32_t _mulitcastAddr;
uint16_t _mulitcastPort;
uint32_t _multicastAddr;
uint16_t _multicastPort;
};
#endif

View File

@ -2,9 +2,9 @@
#include "table_object.h"
/**
* This class represents the group address table. It provides a mapping between tranport layer
* This class represents the group address table. It provides a mapping between transport layer
* service access points (TSAP) and group addresses. The TSAP can be imagined as an index to the array
* of group adresses.
* of group addresses.
*
* See section 4.10 of @cite knx:3/5/1 for further details.
* It implements realisation type 7 (see section 4.10.7 of @cite knx:3/5/1).
@ -13,9 +13,9 @@ class AddressTableObject : public TableObject
{
public:
/**
* The contructor.
* The constructor.
*
* @param memory This parameter is only passed to the custructor of TableObject an not used by this class.
* @param memory This parameter is only passed to the constructor of TableObject and is not used by this class.
*/
AddressTableObject(Memory& memory);
const uint8_t* restore(const uint8_t* buffer) override;
@ -35,7 +35,7 @@ class AddressTableObject : public TableObject
/**
* Get the TSAP mapped to a group address.
*
* @param groupAddress the group address of whicht to get the TSAP for.
* @param groupAddress the group address of which to get the TSAP for.
*
* @return the TSAP if found or zero if no tsap was found.
*/

View File

@ -66,7 +66,7 @@ void ApplicationLayer::dataGroupIndication(HopCountType hopType, Priority priori
case GroupValueWrite:
_bau.groupValueWriteIndication(asap, priority, hopType, secCtrl, data, len);
default:
/* other apdutypes ar not valid here. If the appear do nothing */
/* other apdutypes are not valid here. If they appear do nothing */
break;
}
}
@ -908,7 +908,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap,
uint8_t* apdudata = apdu.data();
if (dataLength == 0)
{
// data size is six bit or less. So store int first byte
// data size is six bit or less. So store in first byte
*apdudata &= ~0x3f;
*apdudata |= (*data & 0x3f);
}
@ -916,7 +916,7 @@ void ApplicationLayer::groupValueSend(ApduType type, AckType ack, uint16_t asap,
{
memcpy(apdudata + 1, data, dataLength);
}
// no need to check if there is a tsap. This is a response, so the read got trough
// no need to check if there is a tsap. This is a response, so the read got through
uint16_t tsap = (uint16_t)_assocTable->translateAsap(asap);
dataGroupRequest(ack, hopType, priority, tsap, apdu, secCtrl);
dataGroupIndication(hopType, priority, tsap, apdu, secCtrl);
@ -1129,7 +1129,7 @@ void ApplicationLayer::individualIndication(HopCountType hopType, Priority prior
_bau.keyWriteAppLayerConfirm(priority, hopType, tsap, secCtrl, data[1]);
break;
default:
print("Indiviual-indication: unhandled APDU-Type: ");
print("Individual-indication: unhandled APDU-Type: ");
println(apdu.type());
}
}
@ -1240,7 +1240,7 @@ void ApplicationLayer::individualConfirm(AckType ack, HopCountType hopType, Prio
_bau.keyWriteResponseConfirm(ack, priority, hopType, tsap, secCtrl, data[1], status);
break;
default:
print("Indiviual-confirm: unhandled APDU-Type: ");
print("Individual-confirm: unhandled APDU-Type: ");
println(apdu.type());
}
}

View File

@ -11,7 +11,7 @@ class TransportLayer;
* This is an implementation of the application layer as specified in @cite knx:3/5/1.
* It provides methods for the BusAccessUnit to do different things and translates this
* call to an APDU and calls the correct method of the TransportLayer.
* It also takes calls from TransportLayer, decodes the submitted APDU and calls the coresponding
* It also takes calls from TransportLayer, decodes the submitted APDU and calls the corresponding
* methods of the BusAccessUnit class.
*/
class ApplicationLayer
@ -31,12 +31,12 @@ class ApplicationLayer
void associationTableObject(AssociationTableObject& assocTable);
// from transport layer
// Note: without data secure feature, the application layer is just used with SecurtyControl.dataSecurity = None
// Note: without data secure feature, the application layer is just used with SecurityControl.dataSecurity = None
// hooks that can be implemented by derived class (e.g. SecureApplicationLayer)
#pragma region Transport - Layer - Callbacks
/**
* Somebody send us an APDU via multicast communiation. See 3.2 of @cite knx:3/3/4.
* Somebody send us an APDU via multicast communication. See 3.2 of @cite knx:3/3/4.
* See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest.
* This method is called by the TransportLayer.
*
@ -51,7 +51,7 @@ class ApplicationLayer
*/
virtual void dataGroupIndication(HopCountType hopType, Priority priority, uint16_t tsap, APDU& apdu);
/**
* Report the status of an APDU that we sent via multicast communiation back to us. See 3.2 of @cite knx:3/3/4.
* Report the status of an APDU that we sent via multicast communication back to us. See 3.2 of @cite knx:3/3/4.
* See also ApplicationLayer::dataGroupConfirm and TransportLayer::dataGroupRequest. This method is called by
* the TransportLayer.
*

View File

@ -29,6 +29,29 @@ ApplicationProgramObject::ApplicationProgramObject(Memory& memory)
TableObject::initializeProperties(sizeof(properties), properties);
}
uint8_t* ApplicationProgramObject::save(uint8_t* buffer)
{
uint8_t programVersion[5];
property(PID_PROG_VERSION)->read(programVersion);
buffer = pushByteArray(programVersion, 5, buffer);
return TableObject::save(buffer);
}
const uint8_t* ApplicationProgramObject::restore(const uint8_t* buffer)
{
uint8_t programVersion[5];
buffer = popByteArray(programVersion, 5, buffer);
property(PID_PROG_VERSION)->write(programVersion);
return TableObject::restore(buffer);
}
uint16_t ApplicationProgramObject::saveSize()
{
return TableObject::saveSize() + 5; // sizeof(programVersion)
}
uint8_t * ApplicationProgramObject::data(uint32_t addr)
{
return TableObject::data() + addr;

View File

@ -7,6 +7,9 @@ class ApplicationProgramObject : public TableObject
{
public:
ApplicationProgramObject(Memory& memory);
uint8_t* save(uint8_t* buffer) override;
const uint8_t* restore(const uint8_t* buffer) override;
uint16_t saveSize() override;
uint8_t* data(uint32_t addr);
uint8_t getByte(uint32_t addr);
uint16_t getWord(uint32_t addr);

View File

@ -25,7 +25,7 @@ uint16_t AssociationTableObject::entryCount()
uint16_t AssociationTableObject::getTSAP(uint16_t idx)
{
if (idx < 0 || idx >= entryCount())
if (idx >= entryCount())
return 0;
return ntohs(_tableData[2 * idx + 1]);
@ -33,7 +33,7 @@ uint16_t AssociationTableObject::getTSAP(uint16_t idx)
uint16_t AssociationTableObject::getASAP(uint16_t idx)
{
if (idx < 0 || idx >= entryCount())
if (idx >= entryCount())
return 0;
return ntohs(_tableData[2 * idx + 2]);

View File

@ -62,7 +62,7 @@ uint8_t BauSystemB::checkmasterResetValidity(EraseCode eraseCode, uint8_t channe
case EraseCode::ResetIA:
{
// TODO: increase download counter except for confirmed restart (PID_DOWNLOAD_COUNTER)
println("ResetAP requested. Not implemented yet.");
println("ResetIA requested. Not implemented yet.");
return successCode;
}
case EraseCode::ResetLinks:
@ -500,7 +500,7 @@ bool BauSystemB::restartRequest(uint16_t asap, const SecurityControl secCtrl)
void BauSystemB::connectConfirm(uint16_t tsap)
{
if (_restartState == Connecting && tsap >= 0)
if (_restartState == Connecting)
{
/* restart connection is confirmed, go to the next state */
_restartState = Connected;
@ -532,7 +532,7 @@ void BauSystemB::nextRestartState()
}
break;
case Restarted:
/* restart is finished, we send a discommect */
/* restart is finished, we send a disconnect */
if (millis() - _restartDelay > 30)
{
applicationLayer().disconnectRequest(SystemPriority);

View File

@ -114,9 +114,13 @@ void BauSystemBDevice::updateGroupObject(GroupObject & go, uint8_t * data, uint8
memcpy(goData, data, length);
go.commFlag(Updated);
#ifdef SMALL_GROUPOBJECT
GroupObject::processClassCallback(go);
#else
GroupObjectUpdatedHandler handler = go.callback();
if (handler)
handler(go);
#endif
}
bool BauSystemBDevice::configured()

View File

@ -8,6 +8,7 @@ const uint8_t* popByte(uint8_t& b, const uint8_t* data)
return data;
}
#ifndef KNX_NO_PRINT
void printHex(const char* suffix, const uint8_t *data, size_t length, bool newline)
{
print(suffix);
@ -21,6 +22,7 @@ void printHex(const char* suffix, const uint8_t *data, size_t length, bool newli
println();
}
}
#endif
const uint8_t* popWord(uint16_t& w, const uint8_t* data)
{

View File

@ -63,6 +63,7 @@ typedef void (*voidFuncPtr)(void);
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode);
#endif
#ifndef KNX_NO_PRINT
void print(const char[]);
void print(char);
void print(unsigned char, int = DEC);
@ -87,6 +88,11 @@ void println(double);
void println(void);
void printHex(const char* suffix, const uint8_t *data, size_t length, bool newline = true);
#else
#define print(...) do {} while(0)
#define println(...) do {} while(0)
#define printHex(...) do {} while(0)
#endif
const uint8_t* popByte(uint8_t& b, const uint8_t* data);
const uint8_t* popWord(uint16_t& w, const uint8_t* data);

View File

@ -60,6 +60,22 @@
// Define via a compiler -D flag if required
// #define USE_DATASECURE
// option to have GroupObjects (KO in German) use 8 bytes mangement information RAM instead of 19 bytes
// see knx-demo-small-go for example
// this option might be also set via compiler flag -DSMALL_GROUPOBJECT if required
//#define SMALL_GROUPOBJECT
// Some defines to reduce footprint
// Do not perform conversion from KNXValue(const char*) to other types, it mainly avoids the expensive strtod
//#define KNX_NO_STRTOx_CONVERSION
// Do not print messages
//#define KNX_NO_PRINT
// Do not use SPI (Arduino variants)
//#define KNX_NO_SPI
// Do not use the default UART (Arduino variants), it must be defined by ArduinoPlatform::knxUart
// (combined with other flags (HWSERIAL_NONE for stm32) - avoid allocation of RX/TX buffers for all serial lines)
//#define KNX_NO_DEFAULT_UART
#endif
#if !defined(MASK_VERSION)

View File

@ -49,7 +49,7 @@ uint8_t DataProperty::write(uint16_t start, uint8_t count, const uint8_t* data)
start -= 1;
if (start + count > _currentElements)
{
//reallocate memory for _data
// reallocate memory for _data
uint8_t* oldData = _data;
size_t oldDataSize = _currentElements * ElementSize();

View File

@ -39,5 +39,5 @@ public:
uint8_t defaultHopCount();
private:
uint8_t _prgMode = 0;
uint16_t _ownAddress = 0;
uint16_t _ownAddress = 65535; // 15.15.255;
};

View File

@ -357,6 +357,7 @@
#define DPT_FlaggedScaling Dpt(239, 1)
#define DPT_CombinedPosition Dpt(240, 800)
#define DPT_StatusSAB Dpt(241, 800)
#define DPT_Colour_RGBW Dpt(251, 600)
class Dpt
{

View File

@ -22,12 +22,6 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return busValueToBinaryControl(payload, payload_length, datatype, value);
// DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return busValueToStepControl(payload, payload_length, datatype, value);
// DPT 4.* - Character// DPT 2.* - Binary Control
if (datatype.mainGroup == 2 && datatype.subGroup >= 1 && datatype.subGroup <= 12 && datatype.index <= 1)
return busValueToBinaryControl(payload, payload_length, datatype, value);
// DPT 3.* - Step Control
if (datatype.mainGroup == 3 && datatype.subGroup >= 7 && datatype.subGroup <= 8 && datatype.index <= 1)
return busValueToStepControl(payload, payload_length, datatype, value);
// DPT 4.* - Character
@ -42,8 +36,8 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return busValueToStatusAndMode(payload, payload_length, datatype, value);
// DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index)
// DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || (datatype.subGroup == 600)) && !datatype.index)
return busValueToUnsigned16(payload, payload_length, datatype, value);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
@ -55,108 +49,7 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return busValueToTimeDelta(payload, payload_length, datatype, value);
// DPT 9.* - 16 Bit Float
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 && datatype.subGroup != 9) || (datatype.subGroup >= 20 && datatype.subGroup <= 28)) && !datatype.index)
return busValueToFloat16(payload, payload_length, datatype, value);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToTime(payload, payload_length, datatype, value);
// DPT 11.* - Date
if (datatype.mainGroup == 11 && datatype.subGroup == 1 && !datatype.index)
return busValueToDate(payload, payload_length, datatype, value);
// DPT 12.* - Unsigned 32 Bit Integer
if (datatype.mainGroup == 12 && datatype.subGroup == 1 && !datatype.index)
return busValueToUnsigned32(payload, payload_length, datatype, value);
// DPT 13.001/13.002/13.010-13.015 - Signed 32 Bit Integer
if (datatype.mainGroup == 13 && (datatype.subGroup == 1 || datatype.subGroup == 2 || (datatype.subGroup >= 10 && datatype.subGroup <= 15)) && !datatype.index)
return busValueToSigned32(payload, payload_length, datatype, value);
// DPT 13.100 - Long Time Period
if (datatype.mainGroup == 13 && datatype.subGroup == 100 && !datatype.index)
return busValueToLongTimePeriod(payload, payload_length, datatype, value);
// DPT 14.* - 32 Bit Float
if (datatype.mainGroup == 14 && datatype.subGroup <= 79 && !datatype.index)
return busValueToFloat32(payload, payload_length, datatype, value);
// DPT 15.* - Access Data
if (datatype.mainGroup == 15 && !datatype.subGroup && datatype.index <= 5)
return busValueToAccess(payload, payload_length, datatype, value);
// DPT 16.* - String
if (datatype.mainGroup == 16 && datatype.subGroup <= 1 && !datatype.index)
return busValueToString(payload, payload_length, datatype, value);
// DPT 17.* - Scene Number
if (datatype.mainGroup == 17 && datatype.subGroup == 1 && !datatype.index)
return busValueToScene(payload, payload_length, datatype, value);
// DPT 18.* - Scene Control
if (datatype.mainGroup == 18 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToSceneControl(payload, payload_length, datatype, value);
// DPT 19.* - Date and Time
if (datatype.mainGroup == 19 && datatype.subGroup == 1 && (datatype.index <= 3 || datatype.index == 9 || datatype.index == 10))
return busValueToDateTime(payload, payload_length, datatype, value);
// DPT 26.* - Scene Info
if (datatype.mainGroup == 26 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToSceneInfo(payload, payload_length, datatype, value);
// DPT 28.* - Unicode String
if (datatype.mainGroup == 28 && datatype.subGroup == 1 && !datatype.index)
return busValueToUnicode(payload, payload_length, datatype, value);
// DPT 29.* - Signed 64 Bit Integer
if (datatype.mainGroup == 29 && datatype.subGroup >= 10 && datatype.subGroup <= 12 && !datatype.index)
return busValueToSigned64(payload, payload_length, datatype, value);
// DPT 219.* - Alarm Info
if (datatype.mainGroup == 219 && datatype.subGroup == 1 && datatype.index <= 10)
return busValueToAlarmInfo(payload, payload_length, datatype, value);
// DPT 221.* - Serial Number
if (datatype.mainGroup == 221 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToSerialNumber(payload, payload_length, datatype, value);
// DPT 217.* - Version
if (datatype.mainGroup == 217 && datatype.subGroup == 1 && datatype.index <= 2)
return busValueToVersion(payload, payload_length, datatype, value);
// DPT 225.001/225.002 - Scaling Speed and Scaling Step Time
if (datatype.mainGroup == 225 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && datatype.index <= 1)
return busValueToScaling(payload, payload_length, datatype, value);
// DPT 225.003 - Next Tariff
if (datatype.mainGroup == 225 && datatype.subGroup == 3 && datatype.index <= 1)
return busValueToTariff(payload, payload_length, datatype, value);
// DPT 231.* - Locale
if (datatype.mainGroup == 231 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToLocale(payload, payload_length, datatype, value);
// DPT 232.600 - RGB
if (datatype.mainGroup == 232 && datatype.subGroup == 600 && !datatype.index)
return busValueToRGB(payload, payload_length, datatype, value);
// DPT 234.* - Language and Region
if (datatype.mainGroup == 234 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
return busValueToLocale(payload, payload_length, datatype, value);
// DPT 235.* - Active Energy
if (datatype.mainGroup == 235 && datatype.subGroup == 1 && datatype.index <= 3)
return busValueToActiveEnergy(payload, payload_length, datatype, value);
// DPT 238.* - Scene Config
if (datatype.mainGroup == 238 && datatype.subGroup == 1 && datatype.index <= 2)
return busValueToSceneConfig(payload, payload_length, datatype, value);
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToFlaggedScaling(payload, payload_length, datatype, value);
if (datatype.mainGroup == 4 && datatype.subGroup >= 1 && datatype.subGroup <= 2 && !datatype.index)
return busValueToCharacter(payload, payload_length, datatype, value);
// DPT 5.* - Unsigned 8 Bit Integer
if (datatype.mainGroup == 5 && ((datatype.subGroup >= 1 && datatype.subGroup <= 6 && datatype.subGroup != 2) || datatype.subGroup == 10) && !datatype.index)
return busValueToUnsigned8(payload, payload_length, datatype, value);
// DPT 6.001/6.010 - Signed 8 Bit Integer
if (datatype.mainGroup == 6 && (datatype.subGroup == 1 || datatype.subGroup == 10) && !datatype.index)
return busValueToSigned8(payload, payload_length, datatype, value);
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return busValueToStatusAndMode(payload, payload_length, datatype, value);
// DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index)
return busValueToUnsigned16(payload, payload_length, datatype, value);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return busValueToTimePeriod(payload, payload_length, datatype, value);
// DPT 8.001/8.010/8.011 - Signed 16 Bit Integer
if (datatype.mainGroup == 8 && (datatype.subGroup == 1 || datatype.subGroup == 10 || datatype.subGroup == 11) && !datatype.index)
return busValueToSigned16(payload, payload_length, datatype, value);
// DPT 8.002-DPT 8.007 - Time Delta
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return busValueToTimeDelta(payload, payload_length, datatype, value);
// DPT 9.* - 16 Bit Float
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 && datatype.subGroup != 9) || (datatype.subGroup >= 20 && datatype.subGroup <= 28)) && !datatype.index)
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index)
return busValueToFloat16(payload, payload_length, datatype, value);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
@ -233,6 +126,9 @@ int KNX_Decode_Value(uint8_t* payload, size_t payload_length, const Dpt& datatyp
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return busValueToFlaggedScaling(payload, payload_length, datatype, value);
// DPT 251.600 - RGBW
if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
return busValueToRGBW(payload, payload_length, datatype, value);
}
return false;
}
@ -260,8 +156,8 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
// DPT 6.020 - Status with Mode
if (datatype.mainGroup == 6 && datatype.subGroup == 20 && datatype.index <= 5)
return valueToBusValueStatusAndMode(value, payload, payload_length, datatype);
// DPT 7.001/7.010/7.011/7.012/7.013 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13)) && !datatype.index)
// DPT 7.001/7.010/7.011/7.012/7.013/7.600 - Unsigned 16 Bit Integer
if (datatype.mainGroup == 7 && (datatype.subGroup == 1 || (datatype.subGroup >= 10 && datatype.subGroup <= 13) || datatype.subGroup == 600) && !datatype.index)
return valueToBusValueUnsigned16(value, payload, payload_length, datatype);
// DPT 7.002-DPT 7.007 - Time Period
if (datatype.mainGroup == 7 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
@ -273,7 +169,7 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
if (datatype.mainGroup == 8 && datatype.subGroup >= 2 && datatype.subGroup <= 7 && !datatype.index)
return valueToBusValueTimeDelta(value, payload, payload_length, datatype);
// DPT 9.* - 16 Bit Float
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 && datatype.subGroup != 9) || (datatype.subGroup >= 20 && datatype.subGroup <= 28)) && !datatype.index)
if (datatype.mainGroup == 9 && ((datatype.subGroup >= 1 && datatype.subGroup <= 11 ) || (datatype.subGroup >= 20 && datatype.subGroup <= 29)) && !datatype.index)
return valueToBusValueFloat16(value, payload, payload_length, datatype);
// DPT 10.* - Time and Weekday
if (datatype.mainGroup == 10 && datatype.subGroup == 1 && datatype.index <= 1)
@ -350,6 +246,9 @@ int KNX_Encode_Value(const KNXValue& value, uint8_t* payload, size_t payload_len
// DPT 239.* - Flagged Scaling
if (datatype.mainGroup == 239 && datatype.subGroup == 1 && datatype.index <= 1)
return valueToBusValueFlaggedScaling(value, payload, payload_length, datatype);
// DPT 251.600 - RGBW
if (datatype.mainGroup == 251 && datatype.subGroup == 600 && datatype.index <= 1)
return valueToBusValueRGBW(value, payload, payload_length, datatype);
return false;
}
@ -904,12 +803,27 @@ int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& data
{
ASSERT_PAYLOAD(3);
uint32_t rgb = unsigned16FromPayload(payload, 0) * 256 + unsigned8FromPayload(payload, 2);
if (rgb > 16777215)
return false;
value = rgb;
return true;
}
int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(6);
switch (datatype.index) {
case 0: // The RGBW value
{
uint32_t rgbw = unsigned32FromPayload(payload, 0);
value = rgbw;
}
return true;
case 1: // The mask bits only
value = unsigned8FromPayload(payload,5);
return true;
}
return false;
}
int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value)
{
ASSERT_PAYLOAD(2);
@ -993,7 +907,7 @@ int valueToBusValueStepControl(const KNXValue& value, uint8_t* payload, size_t p
int valueToBusValueCharacter(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
if ((uint64_t)value < INT64_C(0) || (uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127)))
if ((uint64_t)value > INT64_C(255) || (datatype.subGroup == 1 && (uint64_t)value > INT64_C(127)))
return false;
unsigned8ToPayload(payload, payload_length, 0, (uint64_t)value, 0xFF);
return true;
@ -1260,7 +1174,7 @@ int valueToBusValueAccess(const KNXValue& value, uint8_t* payload, size_t payloa
break;
case 5:
{
if ((uint64_t)value < INT64_C(0) || (uint64_t)value > INT64_C(15))
if ((uint64_t)value > INT64_C(15))
return false;
bcdToPayload(payload, payload_length, 7, (uint64_t)value);
break;
@ -1551,7 +1465,7 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo
{
uint32_t duration = value;
if (duration < INT64_C(0) || duration > INT64_C(65535))
if (duration > INT64_C(65535))
return false;
ENSURE_PAYLOAD(3);
@ -1578,7 +1492,7 @@ int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payloa
{
uint32_t duration = value;
if (duration < INT64_C(0) || duration > INT64_C(65535))
if (duration > INT64_C(65535))
return false;
ENSURE_PAYLOAD(3);
@ -1626,6 +1540,24 @@ int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_l
return true;
}
int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch(datatype.index)
{
case 0: // RGBW
{
uint32_t rgbw = (uint32_t)value;
unsigned32ToPayload(payload, payload_length, 0, rgbw, 0xffffffff); // RGBW
}
break;
case 1: // Mask bits
unsigned8ToPayload(payload, payload_length, 5, (uint8_t)value, 0x0f);
break;
}
return true;
}
int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype)
{
switch (datatype.index)
@ -1654,7 +1586,6 @@ int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t
{
case 0:
{
if ((int64_t)value < INT64_C(-2147483648) || (int64_t)value > INT64_C(2147483647))
return false;
ENSURE_PAYLOAD(6);

View File

@ -78,6 +78,7 @@ int busValueToScaling(const uint8_t* payload, size_t payload_length, const Dpt&
int busValueToTariff(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToLocale(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToRGB(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToRGBW(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToFlaggedScaling(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
int busValueToActiveEnergy(const uint8_t* payload, size_t payload_length, const Dpt& datatype, KNXValue& value);
@ -116,6 +117,7 @@ int valueToBusValueScaling(const KNXValue& value, uint8_t* payload, size_t paylo
int valueToBusValueTariff(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueLocale(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueRGB(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueRGBW(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueFlaggedScaling(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);
int valueToBusValueActiveEnergy(const KNXValue& value, uint8_t* payload, size_t payload_length, const Dpt& datatype);

View File

@ -4,23 +4,30 @@
#include "datapoint_types.h"
#include "group_object_table_object.h"
#ifdef SMALL_GROUPOBJECT
GroupObjectUpdatedHandler GroupObject::_updateHandlerStatic = 0;
#endif
GroupObjectTableObject* GroupObject::_table = 0;
GroupObject::GroupObject()
{
_data = 0;
_commFlag = Ok;
_table = 0;
_dataLength = 0;
#ifndef SMALL_GROUPOBJECT
_updateHandler = 0;
#endif
}
GroupObject::GroupObject(const GroupObject& other)
{
_data = new uint8_t[other._dataLength];
_commFlag = other._commFlag;
_table = other._table;
_dataLength = other._dataLength;
_asap = other._asap;
#ifndef SMALL_GROUPOBJECT
_updateHandler = other._updateHandler;
#endif
memcpy(_data, other._data, _dataLength);
}
@ -175,6 +182,24 @@ size_t GroupObject::sizeInTelegram()
return asapValueSize(code);
}
#ifdef SMALL_GROUPOBJECT
GroupObjectUpdatedHandler GroupObject::classCallback()
{
return _updateHandlerStatic;
}
void GroupObject::classCallback(GroupObjectUpdatedHandler handler)
{
_updateHandlerStatic = handler;
}
void GroupObject::processClassCallback(GroupObject& ko)
{
if (_updateHandlerStatic != 0)
_updateHandlerStatic(ko);
}
#else
void GroupObject::callback(GroupObjectUpdatedHandler handler)
{
_updateHandler = handler;
@ -185,6 +210,7 @@ GroupObjectUpdatedHandler GroupObject::callback()
{
return _updateHandler;
}
#endif
void GroupObject::value(const KNXValue& value, const Dpt& type)
{
@ -205,7 +231,7 @@ bool GroupObject::tryValue(KNXValue& value, const Dpt& type)
return KNX_Decode_Value(_data, _dataLength, type, value);
}
#ifndef SMALL_GROUPOBJECT
void GroupObject::dataPointType(Dpt value)
{
_datapointType = value;
@ -240,7 +266,7 @@ void GroupObject::valueNoSend(const KNXValue& value)
{
valueNoSend(value, _datapointType);
}
#endif
void GroupObject::valueNoSend(const KNXValue& value, const Dpt& type)
{

View File

@ -133,6 +133,8 @@ class GroupObject
* (in german "KO-Nr")
*/
uint16_t asap();
#ifndef SMALL_GROUPOBJECT
/**
* register a callback for this group object. The registered callback will be called if the group object was changed from the bus.
*/
@ -141,16 +143,12 @@ class GroupObject
* returns the registered callback
*/
GroupObjectUpdatedHandler callback();
#endif
/**
* return the current value of the group object.
* @param type the datapoint type used for the conversion. If this doesn't fit to the group object the returned value is invalid.
*/
KNXValue value(const Dpt& type);
/**
* return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned
* value is invalid.
*/
KNXValue value();
/**
* set the current value of the group object and changes the state of the group object to ::WriteRequest.
* @param value the value the group object is set to
@ -159,13 +157,6 @@ class GroupObject
* The parameters must fit the group object. Otherwise it will stay unchanged.
*/
void value(const KNXValue& value, const Dpt& type);
/**
* set the current value of the group object and changes the state of the group object to ::WriteRequest.
* @param value the value the group object is set to
*
* The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
*/
void value(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
@ -174,13 +165,6 @@ class GroupObject
* The parameters must fit the group object. Otherwise it will stay unchanged.
*/
void valueNoSend(const KNXValue& value, const Dpt& type);
/**
* set the current value of the group object.
* @param value the value the group object is set to
*
* The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
*/
void valueNoSend(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
@ -191,6 +175,27 @@ class GroupObject
* @returns true if the value of the group object was changed successfully.
*/
bool tryValue(KNXValue& value, const Dpt& type);
#ifndef SMALL_GROUPOBJECT
/**
* return the current value of the group object. The datapoint type must be set with dataPointType(). Otherwise the returned
* value is invalid.
*/
KNXValue value();
/**
* set the current value of the group object and changes the state of the group object to ::WriteRequest.
* @param value the value the group object is set to
*
* The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
*/
void value(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
*
* The parameters must fit the group object and dhe datapoint type must be set with dataPointType(). Otherwise it will stay unchanged.
*/
void valueNoSend(const KNXValue& value);
/**
* set the current value of the group object.
* @param value the value the group object is set to
@ -209,15 +214,32 @@ class GroupObject
* sets the datapoint type of the group object.
*/
void dataPointType(Dpt value);
#else
/**
* Alternative callback processing: register one global callback for all group object.
* The registered callback will be called if any group object was changed from the bus.
* The callback method has to dispatch to the correct handler for this group object.
*/
static GroupObjectUpdatedHandler classCallback();
static void classCallback(GroupObjectUpdatedHandler handler);
static void processClassCallback(GroupObject& ko);
#endif
private:
// class members
static GroupObjectTableObject* _table;
#ifdef SMALL_GROUPOBJECT
static GroupObjectUpdatedHandler _updateHandlerStatic;
#endif
size_t asapValueSize(uint8_t code);
GroupObjectUpdatedHandler _updateHandler;
size_t goSize();
uint16_t _asap = 0;
ComFlag _commFlag = Ok;
uint8_t* _data = 0;
uint8_t _dataLength = 0;
GroupObjectTableObject* _table = 0;
#ifndef SMALL_GROUPOBJECT
GroupObjectUpdatedHandler _updateHandler;
Dpt _datapointType;
#endif
};

View File

@ -6,7 +6,7 @@
#include "data_property.h"
#include "callback_property.h"
//224.0.23.12
// 224.0.23.12
#define DEFAULT_MULTICAST_ADDR ((uint32_t)0xE000170C)
IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platform): _deviceObject(deviceObject),
@ -46,7 +46,7 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf
return 1;
}
pushInt(io->_platform.currentIpAddress(), data);
pushInt(htonl(io->_platform.currentIpAddress()), data);
return 1;
}),
new CallbackProperty<IpParameterObject>(this, PID_CURRENT_SUBNET_MASK, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
@ -59,7 +59,7 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf
return 1;
}
pushInt(io->_platform.currentSubnetMask(), data);
pushInt(htonl(io->_platform.currentSubnetMask()), data);
return 1;
}),
new CallbackProperty<IpParameterObject>(this, PID_CURRENT_DEFAULT_GATEWAY, false, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv0,
@ -72,7 +72,7 @@ IpParameterObject::IpParameterObject(DeviceObject& deviceObject, Platform& platf
return 1;
}
pushInt(io->_platform.currentDefaultGateway(), data);
pushInt(htonl(io->_platform.currentDefaultGateway()), data);
return 1;
}),
new DataProperty(PID_IP_ADDRESS, true, PDT_UNSIGNED_LONG, 1, ReadLv3 | WriteLv3),

View File

@ -35,7 +35,7 @@ uint16_t KnxIpDeviceInformationDIB::individualAddress() const
}
void KnxIpDeviceInformationDIB::indiviudalAddress(uint16_t value)
void KnxIpDeviceInformationDIB::individualAddress(uint16_t value)
{
pushWord(value, _data + 4);
}
@ -65,7 +65,7 @@ void KnxIpDeviceInformationDIB::serialNumber(const uint8_t* value)
}
uint32_t KnxIpDeviceInformationDIB::routingMulicastAddress() const
uint32_t KnxIpDeviceInformationDIB::routingMulticastAddress() const
{
return getInt(_data + 14);
}

View File

@ -16,12 +16,12 @@ class KnxIpDeviceInformationDIB : public KnxIpDIB
uint8_t status() const;
void status(uint8_t value);
uint16_t individualAddress() const;
void indiviudalAddress(uint16_t value);
void individualAddress(uint16_t value);
uint16_t projectInstallationIdentifier() const;
void projectInstallationIdentifier(uint16_t value);
const uint8_t* serialNumber() const;
void serialNumber(const uint8_t* value);
uint32_t routingMulicastAddress() const;
uint32_t routingMulticastAddress() const;
void routingMulticastAddress(uint32_t value);
const uint8_t* macAddress() const;
void macAddress(const uint8_t* value);

View File

@ -19,7 +19,7 @@ KnxIpSearchResponse::KnxIpSearchResponse(IpParameterObject& parameters, DeviceOb
_deviceInfo.code(DEVICE_INFO);
_deviceInfo.medium(0x20); //KNX-IP FIXME get this value from somewhere else
_deviceInfo.status(deviceObject.progMode());
_deviceInfo.indiviudalAddress(parameters.propertyValue<uint16_t>(PID_KNX_INDIVIDUAL_ADDRESS));
_deviceInfo.individualAddress(parameters.propertyValue<uint16_t>(PID_KNX_INDIVIDUAL_ADDRESS));
_deviceInfo.projectInstallationIdentifier(parameters.propertyValue<uint16_t>(PID_PROJECT_INSTALLATION_ID));
_deviceInfo.serialNumber(deviceObject.propertyData(PID_SERIAL_NUMBER));
_deviceInfo.routingMulticastAddress(parameters.propertyValue<uint32_t>(PID_ROUTING_MULTICAST_ADDRESS));

View File

@ -187,7 +187,7 @@ KNXValue& KNXValue::operator=(const int16_t value)
KNXValue& KNXValue::operator=(const int32_t value)
{
_value.boolValue = value;
_value.intValue = value;
_type = IntType;
return *this;
}
@ -318,7 +318,7 @@ uint64_t KNXValue::ulongValue() const
switch (_type)
{
case ULongType:
return _value.uintValue;
return _value.ulongValue;
case BoolType:
return _value.boolValue ? 1 : 0;
case UCharType:
@ -343,7 +343,11 @@ uint64_t KNXValue::ulongValue() const
case DoubleType:
return (uint64_t)_value.doubleValue;
case StringType:
#ifndef KNX_NO_STRTOx_CONVERSION
return (uint64_t)strtoul(_value.stringValue, NULL, 0);
#else
return 0;
#endif
}
return 0;
}
@ -444,7 +448,11 @@ int64_t KNXValue::longValue() const
case DoubleType:
return (int64_t)_value.doubleValue;
case StringType:
#ifndef KNX_NO_STRTOx_CONVERSION
return strtol(_value.stringValue, NULL, 0);
#else
return 0;
#endif
}
return 0;
}
@ -476,7 +484,11 @@ double KNXValue::doubleValue() const
case LongType:
return _value.longValue;
case StringType:
#ifndef KNX_NO_STRTOx_CONVERSION
return strtod(_value.stringValue, NULL);
#else
return 0;
#endif
}
return 0;
}

View File

@ -10,7 +10,7 @@
#define MAXTABLEOBJ 4
#ifndef KNX_FLASH_SIZE
# define KNX_FLASH_SIZE 1024
#define KNX_FLASH_SIZE 1024
#endif
class MemoryBlock

View File

@ -74,6 +74,11 @@ uint32_t Platform::currentDefaultGateway()
void Platform::macAddress(uint8_t *data)
{}
uint32_t Platform::uniqueSerialNumber()
{
return 0x01020304;
}
void Platform::setupMultiCast(uint32_t addr, uint16_t port)
{}

View File

@ -20,6 +20,9 @@ class Platform
virtual uint32_t currentDefaultGateway();
virtual void macAddress(uint8_t* data);
// unique serial number
virtual uint32_t uniqueSerialNumber();
// basic stuff
virtual void restart() = 0;
virtual void fatalError() = 0;

View File

@ -31,7 +31,7 @@ RfMediumObject::RfMediumObject()
resultData[2] = 0xFF; // permanent bidirectional device
resultLength = 3;
}),
/* This properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication.
/* These properties are used in NMP_LinkBudget_Measure to diagnose the Link Budget of the communication.
This in not implemented yet.
new DataProperty(PID_RF_DIAG_SA_FILTER_TABLE, true, PDT_GENERIC_03, 8, ReadLv3 | WriteLv3),
new DataProperty(PID_RF_DIAG_BUDGET_TABLE, false, PDT_GENERIC_03, 8, ReadLv3 | WriteLv0),

View File

@ -21,19 +21,19 @@ extern void delayMicroseconds (unsigned int howLong);
/*----------------------[CC1101 - misc]---------------------------------------*/
#define CRYSTAL_FREQUENCY 26000000
#define CFG_REGISTER 0x2F //47 registers
#define FIFOBUFFER 0x42 //size of Fifo Buffer +2 for rssi and lqi
#define RSSI_OFFSET_868MHZ 0x4E //dec = 74
#define TX_RETRIES_MAX 0x05 //tx_retries_max
#define ACK_TIMEOUT 250 //ACK timeout in ms
#define CC1101_COMPARE_REGISTER 0x00 //register compare 0=no compare 1=compare
#define BROADCAST_ADDRESS 0x00 //broadcast address
#define CFG_REGISTER 0x2F // 47 registers
#define FIFOBUFFER 0x42 // size of Fifo Buffer +2 for rssi and lqi
#define RSSI_OFFSET_868MHZ 0x4E // dec = 74
#define TX_RETRIES_MAX 0x05 // tx_retries_max
#define ACK_TIMEOUT 250 // ACK timeout in ms
#define CC1101_COMPARE_REGISTER 0x00 // register compare 0=no compare 1=compare
#define BROADCAST_ADDRESS 0x00 // broadcast address
#define CC1101_FREQ_315MHZ 0x01
#define CC1101_FREQ_434MHZ 0x02
#define CC1101_FREQ_868MHZ 0x03
#define CC1101_FREQ_915MHZ 0x04
#define CC1101_TEMP_ADC_MV 3.225 //3.3V/1023 . mV pro digit
#define CC1101_TEMP_CELS_CO 2.47 //Temperature coefficient 2.47mV per Grad Celsius
#define CC1101_TEMP_ADC_MV 3.225 // 3.3V/1023 . mV pro digit
#define CC1101_TEMP_CELS_CO 2.47 // Temperature coefficient 2.47mV per Grad Celsius
/*---------------------------[CC1101 - R/W offsets]---------------------------*/
#define WRITE_SINGLE_BYTE 0x00
@ -43,12 +43,12 @@ extern void delayMicroseconds (unsigned int howLong);
/*---------------------------[END R/W offsets]--------------------------------*/
/*------------------------[CC1101 - FIFO commands]----------------------------*/
#define TXFIFO_BURST 0x7F //write burst only
#define TXFIFO_SINGLE_BYTE 0x3F //write single only
#define RXFIFO_BURST 0xFF //read burst only
#define RXFIFO_SINGLE_BYTE 0xBF //read single only
#define PATABLE_BURST 0x7E //power control read/write
#define PATABLE_SINGLE_BYTE 0xFE //power control read/write
#define TXFIFO_BURST 0x7F // write burst only
#define TXFIFO_SINGLE_BYTE 0x3F // write single only
#define RXFIFO_BURST 0xFF // read burst only
#define RXFIFO_SINGLE_BYTE 0xBF // read single only
#define PATABLE_BURST 0x7E // power control read/write
#define PATABLE_SINGLE_BYTE 0xFE // power control read/write
/*---------------------------[END FIFO commands]------------------------------*/
/*----------------------[CC1101 - config register]----------------------------*/

View File

@ -132,8 +132,8 @@ void RfPhysicalLayerCC1310::setOutputPowerLevel(int8_t dBm)
rfPowerTableSize = PROP_RF_txPowerTableSize;
}
//if max power is requested then the CCFG_FORCE_VDDR_HH must be set in
//the ccfg
// if max power is requested then the CCFG_FORCE_VDDR_HH must be set in
// the ccfg
#if (CCFG_FORCE_VDDR_HH != 0x1)
if((newValue.paType == RF_TxPowerTable_DefaultPA) &&
(dBm == rfPowerTable[rfPowerTableSize-2].power))

View File

@ -84,7 +84,6 @@ void RouterObject::initialize(CouplerModel model, uint8_t objIndex, DptMedium me
Property* tableProperties[] =
{
new DataProperty( PID_COUPLER_SERVICES_CONTROL, true, PDT_GENERIC_01, 1, ReadLv3 | WriteLv0, (uint8_t) 0), // written by ETS TODO: implement
new DataProperty( PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0), // TODO: improve: move to TableObject once segment size handling is clear
new DataProperty( PID_FILTER_TABLE_USE, true, PDT_BINARY_INFORMATION, 1, ReadLv3 | WriteLv0, (uint16_t) 0 ), // default: invalid filter table, do not use, written by ETS
new FunctionProperty<RouterObject>(this, PID_ROUTETABLE_CONTROL,
// Command Callback of PID_ROUTETABLE_CONTROL
@ -452,27 +451,9 @@ void RouterObject::beforeStateChange(LoadState& newState)
if (newState != LS_LOADED)
return;
// calculate crc16-ccitt for PID_MCB_TABLE
updateMcb();
_filterTableGroupAddresses = (uint16_t*)data();
}
void RouterObject::updateMcb()
{
uint8_t mcb[propertySize(PID_MCB_TABLE)];
static constexpr uint32_t segmentSize = kFilterTableSize;
uint16_t crc16 = crc16Ccitt(data(), segmentSize);
pushInt(segmentSize, &mcb[0]); // Segment size
pushByte(0x00, &mcb[4]); // CRC control byte -> 0: always valid -> according to coupler spec. it shall always be a valid CRC
pushByte(0xFF, &mcb[5]); // Read access 4 bits + Write access 4 bits (unknown: value taken from real coupler device)
pushWord(crc16, &mcb[6]); // CRC-16 CCITT of filter table
property(PID_MCB_TABLE)->write(mcb);
}
void RouterObject::masterReset(EraseCode eraseCode, uint8_t channel)
{
if (eraseCode == FactoryReset)

View File

@ -52,8 +52,6 @@ private:
void commandClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
bool statusClearSetGroupAddress(uint16_t startAddress, uint16_t endAddress, bool bitIsSet);
void updateMcb();
bool _rfSbcRoutingEnabled = false;
bool _ipSbcRoutingEnabled = false;
uint16_t* _filterTableGroupAddresses = 0;

View File

@ -31,6 +31,8 @@ uint8_t* TableObject::save(uint8_t* buffer)
{
buffer = pushByte(_state, buffer);
buffer = pushInt(_size, buffer);
if (_data)
buffer = pushInt(_memory.toRelative(_data), buffer);
else
@ -46,6 +48,8 @@ const uint8_t* TableObject::restore(const uint8_t* buffer)
buffer = popByte(state, buffer);
_state = (LoadState)state;
buffer = popInt(_size, buffer);
uint32_t relativeAddress = 0;
buffer = popInt(relativeAddress, buffer);
@ -80,6 +84,8 @@ bool TableObject::allocTable(uint32_t size, bool doFill, uint8_t fillByte)
if (doFill)
memset(_data, fillByte, size);
_size = size;
return true;
}
@ -229,7 +235,7 @@ void TableObject::errorCode(ErrorCode errorCode)
uint16_t TableObject::saveSize()
{
return 5 + InterfaceObject::saveSize();
return 5 + InterfaceObject::saveSize() + sizeof(_size);
}
void TableObject::initializeProperties(size_t propertiesSize, Property** properties)
@ -267,6 +273,21 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
pushInt(obj->tableReference(), data);
return 1;
}),
new CallbackProperty<TableObject>(this, PID_MCB_TABLE, false, PDT_GENERIC_08, 1, ReadLv3 | WriteLv0,
[](TableObject* obj, uint16_t start, uint8_t count, uint8_t* data) -> uint8_t {
if (obj->_state != LS_LOADED)
return 0; // need to check return code for invalid
uint32_t segmentSize = obj->_size;
uint16_t crc16 = crc16Ccitt(obj->data(), segmentSize);
pushInt(segmentSize, data); // Segment size
pushByte(0x00, data + 4); // CRC control byte -> 0: always valid
pushByte(0xFF, data + 5); // Read access 4 bits + Write access 4 bits
pushWord(crc16, data + 6); // CRC-16 CCITT of data
return 1;
}),
new DataProperty(PID_ERROR_CODE, false, PDT_ENUM8, 1, ReadLv3 | WriteLv0, (uint8_t)E_NO_FAULT)
};
//TODO: missing
@ -284,4 +305,4 @@ void TableObject::initializeProperties(size_t propertiesSize, Property** propert
memcpy(allProperties + propertyCount, ownProperties, sizeof(ownProperties));
InterfaceObject::initializeProperties(sizeof(allProperties), allProperties);
}
}

View File

@ -28,7 +28,7 @@ class TableObject: public InterfaceObject
uint8_t* save(uint8_t* buffer) override;
const uint8_t* restore(const uint8_t* buffer) override;
uint16_t saveSize() override;
protected:
protected:
/**
* This method is called before the interface object enters a new ::LoadState.
* If there is a error changing the state newState should be set to ::LS_ERROR and errorCode()
@ -47,7 +47,7 @@ protected:
void errorCode(ErrorCode errorCode);
void initializeProperties(size_t propertiesSize, Property** properties) override;
private:
uint32_t tableReference();
bool allocTable(uint32_t size, bool doFill, uint8_t fillByte);
@ -68,4 +68,11 @@ protected:
LoadState _state = LS_UNLOADED;
Memory& _memory;
uint8_t *_data = 0;
/**
* used to store size of data() in allocTable(), needed for calculation of crc in PID_MCB_TABLE.
* This value is also saved and restored.
* The size of the memory block cannot be used because it is changed during alignment to page size.
*/
uint32_t _size = 0;
};

View File

@ -11,6 +11,9 @@
#include <stdio.h>
#include <string.h>
// Activate trace output
//#define DBG_TRACE
// NCN5120
//#define NCN5120
@ -75,25 +78,28 @@
#define U_STOP_MODE_IND 0x2B
#define U_SYSTEM_STAT_IND 0x4B
//loop states
#define IDLE 0
#define RX_FIRST_BYTE 1
#define RX_L_DATA 2
#define RX_WAIT_DATA_CON 3
#define TX_FRAME 4
//tx states
enum {
TX_IDLE,
TX_FRAME,
TX_WAIT_ECHO,
TX_WAIT_CONN
};
#define BYTE_TIMEOUT 10 //milli seconds
//rx states
enum {
RX_WAIT_START,
RX_L_DATA,
RX_WAIT_EOP
};
#define EOP_TIMEOUT 2 //milli seconds; end of layer-2 packet gap
#define CONFIRM_TIMEOUT 500 //milli seconds
#define RESET_TIMEOUT 100 //milli seconds
void TpUartDataLinkLayer::loop()
{
_receiveBuffer[0] = 0x29;
_receiveBuffer[1] = 0;
uint8_t* buffer = _receiveBuffer + 2;
uint8_t rxByte;
if (!_enabled)
{
if (millis() - _lastResetChipTime > 1000)
@ -107,265 +113,317 @@ void TpUartDataLinkLayer::loop()
if (!_enabled)
return;
switch (_loopState)
{
case IDLE:
if (_platform.uartAvailable())
{
_loopState = RX_FIRST_BYTE;
}
else
{
if (!_waitConfirm && !isTxQueueEmpty())
// Signals to communicate from rx part with the tx part
bool isEchoComplete = false; // Flag that a complete echo is received
uint8_t dataConnMsg = 0; // The DATA_CONN message just seen or 0
do {
_receiveBuffer[0] = 0x29;
_receiveBuffer[1] = 0;
uint8_t* buffer = _receiveBuffer + 2;
uint8_t rxByte;
bool isEOP = (millis() - _lastByteRxTime > EOP_TIMEOUT); // Flag that an EOP gap is seen
switch (_rxState)
{
case RX_WAIT_START:
if (_platform.uartAvailable())
{
loadNextTxFrame();
_loopState = TX_FRAME;
rxByte = _platform.readUart();
#ifdef DBG_TRACE
print(rxByte, HEX);
#endif
_lastByteRxTime = millis();
// Check for layer-2 packets
_RxByteCnt = 0;
_xorSum = 0;
if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND)
{
buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte;
_RxByteCnt++; //convert to L_DATA_EXTENDED
_convert = true;
_rxState = RX_L_DATA;
#ifdef DBG_TRACE
println("RLS");
#endif
break;
}
else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND)
{
buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte;
_convert = false;
_rxState = RX_L_DATA;
#ifdef DBG_TRACE
println("RLX");
#endif
break;
}
// Handle all single byte packets here
else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
{
dataConnMsg = rxByte;
}
else if (rxByte == L_POLL_DATA_IND)
{
// not sure if this can happen
println("got L_POLL_DATA_IND");
}
else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND)
{
// this can only happen in bus monitor mode
println("got L_ACKN_IND");
}
else if (rxByte == U_RESET_IND)
{
println("got U_RESET_IND");
}
else if ((rxByte & U_STATE_IND) == U_STATE_IND)
{
print("got U_STATE_IND:");
if (rxByte & 0x80) print (" SC");
if (rxByte & 0x40) print (" RE");
if (rxByte & 0x20) print (" TE");
if (rxByte & 0x10) print (" PE");
if (rxByte & 0x08) print (" TW");
println();
}
else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND)
{
print("got U_FRAME_STATE_IND: 0x");
print(rxByte, HEX);
println();
}
else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND)
{
print("got U_CONFIGURE_IND: 0x");
print(rxByte, HEX);
println();
}
else if (rxByte == U_FRAME_END_IND)
{
println("got U_FRAME_END_IND");
}
else if (rxByte == U_STOP_MODE_IND)
{
println("got U_STOP_MODE_IND");
}
else if (rxByte == U_SYSTEM_STAT_IND)
{
print("got U_SYSTEM_STAT_IND: 0x");
while (true)
{
int tmp = _platform.readUart();
if (tmp < 0)
continue;
print(tmp, HEX);
break;
}
println();
}
else
{
print("got UNEXPECTED: 0x");
print(rxByte, HEX);
println();
}
}
break;
case RX_L_DATA:
if (isEOP)
{
_rxState = RX_WAIT_START;
print("EOP inside RX_L_DATA");
printHex(" => ", buffer, _RxByteCnt);
break;
}
if (!_platform.uartAvailable())
break;
_lastByteRxTime = millis();
rxByte = _platform.readUart();
#ifdef DBG_TRACE
print(rxByte, HEX);
#endif
if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
{
_rxState = RX_WAIT_EOP;
println("invalid telegram size");
}
else
{
buffer[_RxByteCnt++] = rxByte;
}
if (_RxByteCnt == 7)
{
//Destination Address + payload available
_xorSum ^= rxByte;
//check if echo
if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)))
{ //ignore repeated bit of control byte
_isEcho = true;
}
else
{
_isEcho = false;
}
//convert into Extended.ind
if (_convert)
{
uint8_t payloadLength = buffer[6] & 0x0F;
buffer[1] = buffer[6] & 0xF0;
buffer[6] = payloadLength;
}
if (!_isEcho)
{
uint8_t c = 0x10;
// The bau knows everything and could either check the address table object (normal device)
// or any filter tables (coupler) to see if we are addressed.
//check if individual or group address
bool isGroupAddress = (buffer[1] & 0x80) != 0;
uint16_t addr = getWord(buffer + 4);
if (_cb.isAckRequired(addr, isGroupAddress))
{
c |= 0x01;
}
// Hint: We can send directly here, this doesn't disturb other transmissions
_platform.writeUart(c);
}
}
else if (_RxByteCnt == buffer[6] + 7 + 2)
{
//complete Frame received, payloadLength+1 for TCPI +1 for CRC
if (rxByte == (uint8_t)(~_xorSum))
{
//check if crc is correct
if (_isEcho && _sendBuffer != NULL)
{
//check if it is realy an echo, rx_crc = tx_crc
if (rxByte == _sendBuffer[_sendBufferLength - 1])
_isEcho = true;
else
_isEcho = false;
}
if (_isEcho)
{
isEchoComplete = true;
}
else
{
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
}
_rxState = RX_WAIT_START;
#ifdef DBG_TRACE
println("RX_WAIT_START");
#endif
}
else
{
println("frame with invalid crc ignored");
_rxState = RX_WAIT_EOP;
}
}
else
{
_xorSum ^= rxByte;
}
break;
case RX_WAIT_EOP:
if (isEOP)
{
_RxByteCnt = 0;
_rxState = RX_WAIT_START;
#ifdef DBG_TRACE
println("RX_WAIT_START");
#endif
break;
}
if (!_platform.uartAvailable())
break;
_lastByteRxTime = millis();
rxByte = _platform.readUart();
#ifdef DBG_TRACE
print(rxByte, HEX);
#endif
break;
default:
break;
}
} while (_rxState == RX_L_DATA);
// Check for spurios DATA_CONN message
if (dataConnMsg && _txState != TX_WAIT_CONN && _txState != TX_WAIT_ECHO) {
println("got unexpected L_DATA_CON");
}
switch (_txState)
{
case TX_IDLE:
if (!isTxQueueEmpty())
{
loadNextTxFrame();
_txState = TX_FRAME;
#ifdef DBG_TRACE
println("TX_FRAME");
#endif
}
break;
case TX_FRAME:
if (sendSingleFrameByte() == false)
{
_waitConfirm = true;
_waitConfirmStartTime = millis();
_loopState = IDLE;
_txState = TX_WAIT_ECHO;
#ifdef DBG_TRACE
println("TX_WAIT_ECHO");
#endif
}
break;
case RX_FIRST_BYTE:
rxByte = _platform.readUart();
_lastByteRxTime = millis();
_RxByteCnt = 0;
_xorSum = 0;
if ((rxByte & L_DATA_MASK) == L_DATA_STANDARD_IND)
case TX_WAIT_ECHO:
case TX_WAIT_CONN:
if (isEchoComplete)
{
buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte;
_RxByteCnt++; //convert to L_DATA_EXTENDED
_convert = true;
_loopState = RX_L_DATA;
break;
_txState = TX_WAIT_CONN;
#ifdef DBG_TRACE
println("TX_WAIT_CONN");
#endif
}
else if ((rxByte & L_DATA_MASK) == L_DATA_EXTENDED_IND)
else if (dataConnMsg)
{
buffer[_RxByteCnt++] = rxByte;
_xorSum ^= rxByte;
_convert = false;
_loopState = RX_L_DATA;
break;
}
else if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
{
println("got unexpected L_DATA_CON");
}
else if (rxByte == L_POLL_DATA_IND)
{
// not sure if this can happen
println("got L_POLL_DATA_IND");
}
else if ((rxByte & L_ACKN_MASK) == L_ACKN_IND)
{
// this can only happen in bus monitor mode
println("got L_ACKN_IND");
}
else if (rxByte == U_RESET_IND)
{
println("got U_RESET_IND");
}
else if ((rxByte & U_STATE_IND) == U_STATE_IND)
{
print("got U_STATE_IND: 0x");
print(rxByte, HEX);
println();
}
else if ((rxByte & U_FRAME_STATE_MASK) == U_FRAME_STATE_IND)
{
print("got U_FRAME_STATE_IND: 0x");
print(rxByte, HEX);
println();
}
else if ((rxByte & U_CONFIGURE_MASK) == U_CONFIGURE_IND)
{
print("got U_CONFIGURE_IND: 0x");
print(rxByte, HEX);
println();
}
else if (rxByte == U_FRAME_END_IND)
{
println("got U_FRAME_END_IND");
}
else if (rxByte == U_STOP_MODE_IND)
{
println("got U_STOP_MODE_IND");
}
else if (rxByte == U_SYSTEM_STAT_IND)
{
print("got U_SYSTEM_STAT_IND: 0x");
while (true)
{
int tmp = _platform.readUart();
if (tmp < 0)
continue;
print(tmp, HEX);
break;
bool waitEcho = (_txState == TX_WAIT_ECHO);
if (waitEcho) {
println("L_DATA_CON without echo");
}
println();
}
else
{
print("got UNEXPECTED: 0x");
print(rxByte, HEX);
println();
}
_loopState = IDLE;
break;
case RX_L_DATA:
if (millis() - _lastByteRxTime > BYTE_TIMEOUT)
{
_RxByteCnt = 0;
_loopState = IDLE;
println("Timeout during RX_L_DATA");
break;
}
if (!_platform.uartAvailable())
break;
_lastByteRxTime = millis();
rxByte = _platform.readUart();
if (_RxByteCnt == MAX_KNX_TELEGRAM_SIZE)
{
_loopState = IDLE;
println("invalid telegram size");
}
else
{
buffer[_RxByteCnt++] = rxByte;
}
if (_RxByteCnt == 7)
{
//Destination Address + payload available
_xorSum ^= rxByte;
//check if echo
if (_sendBuffer != nullptr && (!((buffer[0] ^ _sendBuffer[0]) & ~0x20) && !memcmp(buffer + _convert + 1, _sendBuffer + 1, 5)))
{ //ignore repeated bit of control byte
_isEcho = true;
}
else
{
_isEcho = false;
}
//convert into Extended.ind
if (_convert)
{
uint8_t payloadLength = buffer[6] & 0x0F;
buffer[1] = buffer[6] & 0xF0;
buffer[6] = payloadLength;
}
if (!_isEcho)
{
uint8_t c = 0x10;
// The bau knows everything and could either check the address table object (normal device)
// or any filter tables (coupler) to see if we are addressed.
//check if individual or group address
bool isGroupAddress = (buffer[1] & 0x80) != 0;
uint16_t addr = getWord(buffer + 4);
if (_cb.isAckRequired(addr, isGroupAddress))
{
c |= 0x01;
}
_platform.writeUart(c);
}
}
else if (_RxByteCnt == buffer[6] + 7 + 2)
{
//complete Frame received, payloadLength+1 for TCPI +1 for CRC
if (rxByte == (uint8_t)(~_xorSum))
{
//check if crc is correct
if (_isEcho && _sendBuffer != NULL)
{
//check if it is realy an echo, rx_crc = tx_crc
if (rxByte == _sendBuffer[_sendBufferLength - 1])
_isEcho = true;
else
_isEcho = false;
}
if (_isEcho)
{
_loopState = RX_WAIT_DATA_CON;
}
else
{
frameBytesReceived(_receiveBuffer, _RxByteCnt + 2);
_loopState = IDLE;
}
}
else
{
println("frame with invalid crc ignored");
_loopState = IDLE;
}
}
else
{
_xorSum ^= rxByte;
}
break;
case RX_WAIT_DATA_CON:
if (!_platform.uartAvailable())
break;
rxByte = _platform.readUart();
_lastByteRxTime = millis();
if ((rxByte & L_DATA_CON_MASK) == L_DATA_CON)
{
//println("L_DATA_CON received");
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, ((rxByte & SUCCESS) > 0));
_waitConfirm = false;
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, !waitEcho && ((dataConnMsg & SUCCESS) > 0));
delete[] _sendBuffer;
_sendBuffer = 0;
_sendBufferLength = 0;
_loopState = IDLE;
_txState = TX_IDLE;
}
else
else if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT)
{
//should not happen
println("expected L_DATA_CON not received");
dataConBytesReceived(_receiveBuffer, _RxByteCnt + 2, false);
_waitConfirm = false;
println("L_DATA_CON not received within expected time");
uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE];
cemiBuffer[0] = 0x29;
cemiBuffer[1] = 0;
memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength);
dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false);
delete[] _sendBuffer;
_sendBuffer = 0;
_sendBufferLength = 0;
_loopState = IDLE;
_txState = TX_IDLE;
#ifdef DBG_TRACE
println("TX_IDLE");
#endif
}
break;
default:
break;
}
if (_waitConfirm)
{
if (millis() - _waitConfirmStartTime > CONFIRM_TIMEOUT)
{
println("L_DATA_CON not received within expected time");
uint8_t cemiBuffer[MAX_KNX_TELEGRAM_SIZE];
cemiBuffer[0] = 0x29;
cemiBuffer[1] = 0;
memcpy((cemiBuffer + 2), _sendBuffer, _sendBufferLength);
dataConBytesReceived(cemiBuffer, _sendBufferLength + 2, false);
_waitConfirm = false;
delete[] _sendBuffer;
_sendBuffer = 0;
_sendBufferLength = 0;
if (_loopState == RX_WAIT_DATA_CON)
_loopState = IDLE;
}
}
}
@ -496,16 +554,21 @@ bool TpUartDataLinkLayer::sendSingleFrameByte()
cmd[0] = U_L_DATA_END_REQ | _TxByteCnt;
cmd[1] = _sendBuffer[_TxByteCnt];
#ifdef DBG_TRACE
print(cmd[1], HEX);
#endif
_platform.writeUart(cmd, 2);
_TxByteCnt++;
return true;
}
else
// Check for last byte send
if (_TxByteCnt >= _sendBufferLength)
{
_TxByteCnt = 0;
return false;
}
return true;
}
void TpUartDataLinkLayer::addFrameTxQueue(CemiFrame& frame)

View File

@ -31,16 +31,15 @@ class TpUartDataLinkLayer : public DataLinkLayer
private:
bool _enabled = false;
bool _waitConfirm = false;
uint8_t* _sendBuffer = 0;
uint16_t _sendBufferLength = 0;
uint8_t _receiveBuffer[MAX_KNX_TELEGRAM_SIZE];
uint8_t _loopState = 0;
uint8_t _txState = 0;
uint8_t _rxState = 0;
uint16_t _RxByteCnt = 0;
uint16_t _TxByteCnt = 0;
uint8_t _oldIdx = 0;
bool _isEcho = false;
bool _isAddressed = false;
bool _convert = false;
uint8_t _xorSum = 0;
uint32_t _lastByteRxTime;

View File

@ -8,6 +8,10 @@
#include "knx/bau2920.h"
#include "knx/bau57B0.h"
#ifndef USERDATA_SAVE_SIZE
#define USERDATA_SAVE_SIZE 0
#endif
#ifdef ARDUINO_ARCH_SAMD
#include "samd_platform.h"
#ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE
@ -45,7 +49,8 @@
#endif
#endif
typedef uint8_t* (*SaveRestoreCallback)(uint8_t* buffer);
typedef const uint8_t* (*RestoreCallback)(const uint8_t* buffer);
typedef uint8_t* (*SaveCallback)(uint8_t* buffer);
typedef void (*IsrFunctionPtr)();
template <class P, class B> class KnxFacade : private SaveRestore
@ -54,18 +59,21 @@ template <class P, class B> class KnxFacade : private SaveRestore
KnxFacade() : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr)
{
manufacturerId(0xfa);
bauNumber(platform().uniqueSerialNumber());
_bau.addSaveRestore(this);
}
KnxFacade(B& bau) : _bau(bau)
{
manufacturerId(0xfa);
bauNumber(platform().uniqueSerialNumber());
_bau.addSaveRestore(this);
}
KnxFacade(IsrFunctionPtr buttonISRFunction) : _platformPtr(new P()), _bauPtr(new B(*_platformPtr)), _bau(*_bauPtr)
{
manufacturerId(0xfa);
bauNumber(platform().uniqueSerialNumber());
_bau.addSaveRestore(this);
setButtonISRFunction(buttonISRFunction);
}
@ -226,7 +234,7 @@ template <class P, class B> class KnxFacade : private SaveRestore
{
_bau.deviceObject().bauNumber(value);
}
void orderNumber(const uint8_t* value)
{
_bau.deviceObject().orderNumber(value);
@ -236,7 +244,7 @@ template <class P, class B> class KnxFacade : private SaveRestore
{
_bau.deviceObject().hardwareType(value);
}
void version(uint16_t value)
{
_bau.deviceObject().version(value);
@ -268,12 +276,12 @@ template <class P, class B> class KnxFacade : private SaveRestore
_progButtonISRFuncPtr = progButtonISRFuncPtr;
}
void setSaveCallback(SaveRestoreCallback func)
void setSaveCallback(SaveCallback func)
{
_saveCallback = func;
}
void setRestoreCallback(SaveRestoreCallback func)
void setRestoreCallback(RestoreCallback func)
{
_restoreCallback = func;
}
@ -286,6 +294,40 @@ template <class P, class B> class KnxFacade : private SaveRestore
return _bau.parameters().data(addr);
}
// paramBit(address, shift)
// get state of a parameter as a boolean like "enable/disable", ...
// Declaration in XML file:
// ...
// <ParameterType Id="M-00FA_A-0066-EA-0001_PT-toggle" Name="toggle">
// <TypeRestriction Base="Value" SizeInBit="1">
// <Enumeration Text="Désactivé" Value="0" Id="M-00FA_A-0066-EA-0001_PT-toggle_EN-0"/>
// <Enumeration Text="Activé" Value="1" Id="M-00FA_A-0066-EA-0001_PT-toggle_EN-1"/>
// </TypeRestriction>
// </ParameterType>
// ...
// <Parameter Id="M-00FA_A-0066-EA-0001_P-2" Name="Input 1" ParameterType="M-00FA_A-0066-EA-0001_PT-toggle" Text="Input 1" Value="1">
// <Memory CodeSegment="M-00FA_A-0066-EA-0001_RS-04-00000" Offset="1" BitOffset="0"/>
// </Parameter>
// <Parameter Id="M-00FA_A-0066-EA-0001_P-3" Name="Input 2" ParameterType="M-00FA_A-0066-EA-0001_PT-toggle" Text="Input 2" Value="1">
// <Memory CodeSegment="M-00FA_A-0066-EA-0001_RS-04-00000" Offset="1" BitOffset="1"/>
// </Parameter>
// <Parameter Id="M-00FA_A-0066-EA-0001_P-4" Name="Inout 3" ParameterType="M-00FA_A-0066-EA-0001_PT-toggle" Text="Input 3" Value="1">
// <Memory CodeSegment="M-00FA_A-0066-EA-0001_RS-04-00000" Offset="1" BitOffset="2"/>
// </Parameter>
// ...
// Usage in code :
// if ( knx.paramBit(1,1))
// {
// //do somthings ....
// }
bool paramBit(uint32_t addr, uint8_t shift)
{
if (!_bau.configured())
return 0;
return (bool) ((_bau.parameters().getByte(addr) >> (7-shift)) & 0x01);
}
uint8_t paramByte(uint32_t addr)
{
if (!_bau.configured())
@ -293,7 +335,20 @@ template <class P, class B> class KnxFacade : private SaveRestore
return _bau.parameters().getByte(addr);
}
// Same usage than paramByte(addresse) for signed parameters
// Declaration in XML file
// <ParameterType Id="M-00FA_A-0066-EA-0001_PT-delta" Name="delta">
// <TypeNumber SizeInBit="8" Type="signedInt" minInclusive="-10" maxInclusive="10"/>
// </ParameterType>
int8_t paramSignedByte(uint32_t addr)
{
if (!_bau.configured())
return 0;
return (int8_t) _bau.parameters().getByte(addr);
}
uint16_t paramWord(uint32_t addr)
{
if (!_bau.configured())
@ -338,11 +393,11 @@ template <class P, class B> class KnxFacade : private SaveRestore
uint32_t _ledPin = LED_BUILTIN;
uint32_t _buttonPinInterruptOn = RISING;
uint32_t _buttonPin = 0;
SaveRestoreCallback _saveCallback = 0;
SaveRestoreCallback _restoreCallback = 0;
SaveCallback _saveCallback = 0;
RestoreCallback _restoreCallback = 0;
volatile bool _toggleProgMode = false;
bool _progLedState = false;
uint16_t _saveSize = 0;
uint16_t _saveSize = USERDATA_SAVE_SIZE;
IsrFunctionPtr _progButtonISRFuncPtr = 0;
uint8_t* save(uint8_t* buffer)
@ -353,7 +408,7 @@ template <class P, class B> class KnxFacade : private SaveRestore
return buffer;
}
uint8_t* restore(uint8_t* buffer)
const uint8_t* restore(const uint8_t* buffer)
{
if (_restoreCallback != 0)
return _restoreCallback(buffer);

View File

@ -501,6 +501,7 @@ void LinuxPlatform::setupUart()
}
}
#ifndef KNX_NO_PRINT
void printUint64(uint64_t value, int base = DEC)
{
char buf[8 * sizeof(uint64_t) + 1];
@ -707,6 +708,7 @@ void println(void)
{
printf("\n");
}
#endif // KNX_NO_PRINT
void pinMode(uint32_t dwPin, uint32_t dwMode)
{

View File

@ -6,7 +6,10 @@
#include <Arduino.h>
#include <FlashAsEEPROM.h>
SamdPlatform::SamdPlatform() : ArduinoPlatform(&Serial1)
SamdPlatform::SamdPlatform()
#ifndef KNX_NO_DEFAULT_UART
: ArduinoPlatform(&Serial1)
#endif
{
}
@ -14,6 +17,26 @@ SamdPlatform::SamdPlatform( HardwareSerial* s) : ArduinoPlatform(s)
{
}
uint32_t SamdPlatform::uniqueSerialNumber()
{
#if defined (__SAMD51__)
// SAMD51 from section 9.6 of the datasheet
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x008061FC)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x00806010)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x00806014)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x00806018)
#else
//#elif defined (__SAMD21E17A__) || defined(__SAMD21G18A__) || defined(__SAMD21E18A__) || defined(__SAMD21J18A__)
// SAMD21 from section 9.3.3 of the datasheet
#define SERIAL_NUMBER_WORD_0 *(volatile uint32_t*)(0x0080A00C)
#define SERIAL_NUMBER_WORD_1 *(volatile uint32_t*)(0x0080A040)
#define SERIAL_NUMBER_WORD_2 *(volatile uint32_t*)(0x0080A044)
#define SERIAL_NUMBER_WORD_3 *(volatile uint32_t*)(0x0080A048)
#endif
return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3;
}
void SamdPlatform::restart()
{
println("restart");

View File

@ -10,6 +10,9 @@ public:
SamdPlatform();
SamdPlatform( HardwareSerial* s);
// unique serial number
uint32_t uniqueSerialNumber() override;
void restart();
uint8_t* getEepromBuffer(uint16_t size);
void commitToEeprom();

View File

@ -1,10 +1,13 @@
#include "stm32_platform.h"
#ifdef ARDUINO_ARCH_STM32
#include <stm32_eeprom.h>
#include <EEPROM.h>
#include "knx/bits.h"
Stm32Platform::Stm32Platform() : ArduinoPlatform(&Serial2)
Stm32Platform::Stm32Platform()
#ifndef KNX_NO_DEFAULT_UART
: ArduinoPlatform(&Serial2)
#endif
{
}
@ -17,6 +20,11 @@ Stm32Platform::~Stm32Platform()
delete [] _eepromPtr;
}
uint32_t Stm32Platform::uniqueSerialNumber()
{
return HAL_GetUIDw0() ^ HAL_GetUIDw1() ^ HAL_GetUIDw2();
}
void Stm32Platform::restart()
{
NVIC_SystemReset();

View File

@ -8,6 +8,9 @@ public:
Stm32Platform( HardwareSerial* s);
~Stm32Platform();
// unique serial number
uint32_t uniqueSerialNumber() override;
// basic stuff
void restart();