mirror of
https://github.com/thelsing/knx.git
synced 2025-08-08 13:47:01 +02:00
Merge branch 'master' into flashnew
# Conflicts: # src/rp2040_arduino_platform.cpp # src/rp2040_arduino_platform.h
This commit is contained in:
commit
9098478614
153
examples/knx-433Dio/KNXto433.xml
Normal file
153
examples/knx-433Dio/KNXto433.xml
Normal 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>
|
32
examples/knx-433Dio/README.md
Normal file
32
examples/knx-433Dio/README.md
Normal 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.
|
||||
|
||||
|
||||
|
||||
|
BIN
examples/knx-433Dio/knx-433.knxprod
Normal file
BIN
examples/knx-433Dio/knx-433.knxprod
Normal file
Binary file not shown.
368
examples/knx-433Dio/knx-433Dio.ino
Normal file
368
examples/knx-433Dio/knx-433Dio.ino
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
129
examples/knx-demo-smal-go/knx-demo.ino
Normal file
129
examples/knx-demo-smal-go/knx-demo.ino
Normal 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();
|
||||
}
|
120
examples/knx-demo-smal-go/platformio.ini
Normal file
120
examples/knx-demo-smal-go/platformio.ini
Normal 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
|
@ -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
|
||||
|
@ -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 =
|
||||
|
@ -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 =
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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]);
|
||||
|
@ -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);
|
||||
|
@ -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()
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -39,5 +39,5 @@ public:
|
||||
uint8_t defaultHopCount();
|
||||
private:
|
||||
uint8_t _prgMode = 0;
|
||||
uint16_t _ownAddress = 0;
|
||||
uint16_t _ownAddress = 65535; // 15.15.255;
|
||||
};
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
};
|
||||
|
@ -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),
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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));
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
#define MAXTABLEOBJ 4
|
||||
|
||||
#ifndef KNX_FLASH_SIZE
|
||||
# define KNX_FLASH_SIZE 1024
|
||||
#define KNX_FLASH_SIZE 1024
|
||||
#endif
|
||||
|
||||
class MemoryBlock
|
||||
|
@ -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)
|
||||
{}
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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),
|
||||
|
@ -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]----------------------------*/
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
};
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
|
@ -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();
|
||||
|
@ -8,6 +8,9 @@ public:
|
||||
Stm32Platform( HardwareSerial* s);
|
||||
~Stm32Platform();
|
||||
|
||||
// unique serial number
|
||||
uint32_t uniqueSerialNumber() override;
|
||||
|
||||
// basic stuff
|
||||
void restart();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user