From cdbf3e70cca72fbcd377eb458ee73e199e8f0af4 Mon Sep 17 00:00:00 2001 From: Thomas Kunze Date: Wed, 7 Nov 2018 00:32:36 +0100 Subject: [PATCH] include linux and samd versions here --- .../bme680.knxprod | Bin .../{knx-esp-bme680 => knx-bme680}/bme680.xml | 0 .../knx-bme680.ino | 3 +- .../knx-demo-ip.knxprod} | Bin .../knx-demo-ip.xml} | 0 examples/knx-demo/knx-demo-tp.knxprod | Bin 0 -> 41318 bytes examples/knx-demo/knx-demo-tp.xml | 133 +++++++++ .../knx-demo.ino} | 12 +- src/arch_config.h | 7 + src/button.cpp | 27 +- src/button.h | 4 + src/esp_platform.cpp | 3 + src/esp_platform.h | 4 + src/knx | 2 +- src/knx_facade.cpp | 25 +- src/knx_facade.h | 19 +- src/knx_facade_samd.cpp | 174 +++++++++++ src/led.cpp | 4 +- src/led.h | 6 +- src/linux_platform.cpp | 279 ++++++++++++++++++ src/linux_platform.h | 51 ++++ src/main.cpp | 116 ++++++++ src/nowifistate.cpp | 10 +- src/nowifistate.h | 6 +- src/programmingmodestate.cpp | 2 + src/programmingmodestate.h | 6 +- src/runningstate.cpp | 3 + src/runningstate.h | 5 +- src/samd_platform.cpp | 157 ++++++++++ src/samd_platform.h | 50 ++++ src/state.cpp | 4 + src/state.h | 7 +- src/wpsstate.cpp | 5 + src/wpsstate.h | 3 + visualstudio/ClassDiagram.cd | 95 ++++++ visualstudio/knx-bme680.vgdbproj | 59 +++- .../{knx-esp.vgdbproj => knx-demo.vgdbproj} | 67 ++++- visualstudio/knx-linux-Debug.vgdbsettings | 148 ++++++++++ visualstudio/knx-linux-Release.vgdbsettings | 148 ++++++++++ visualstudio/knx-linux.vcxproj | 131 ++++++++ visualstudio/knx-linux.vcxproj.filters | 217 ++++++++++++++ visualstudio/knx.sln | 57 ++++ 42 files changed, 2014 insertions(+), 35 deletions(-) rename examples/{knx-esp-bme680 => knx-bme680}/bme680.knxprod (100%) rename examples/{knx-esp-bme680 => knx-bme680}/bme680.xml (100%) rename examples/{knx-esp-bme680 => knx-bme680}/knx-bme680.ino (99%) rename examples/{knx-esp-demo/knx-esp-demo.knxprod => knx-demo/knx-demo-ip.knxprod} (100%) rename examples/{knx-esp-demo/knx-esp-demo.xml => knx-demo/knx-demo-ip.xml} (100%) create mode 100644 examples/knx-demo/knx-demo-tp.knxprod create mode 100644 examples/knx-demo/knx-demo-tp.xml rename examples/{knx-esp-demo/knx-esp-demo.ino => knx-demo/knx-demo.ino} (83%) create mode 100644 src/arch_config.h create mode 100644 src/knx_facade_samd.cpp create mode 100644 src/linux_platform.cpp create mode 100644 src/linux_platform.h create mode 100644 src/main.cpp create mode 100644 src/samd_platform.cpp create mode 100644 src/samd_platform.h create mode 100644 visualstudio/ClassDiagram.cd rename visualstudio/{knx-esp.vgdbproj => knx-demo.vgdbproj} (74%) create mode 100644 visualstudio/knx-linux-Debug.vgdbsettings create mode 100644 visualstudio/knx-linux-Release.vgdbsettings create mode 100644 visualstudio/knx-linux.vcxproj create mode 100644 visualstudio/knx-linux.vcxproj.filters create mode 100644 visualstudio/knx.sln diff --git a/examples/knx-esp-bme680/bme680.knxprod b/examples/knx-bme680/bme680.knxprod similarity index 100% rename from examples/knx-esp-bme680/bme680.knxprod rename to examples/knx-bme680/bme680.knxprod diff --git a/examples/knx-esp-bme680/bme680.xml b/examples/knx-bme680/bme680.xml similarity index 100% rename from examples/knx-esp-bme680/bme680.xml rename to examples/knx-bme680/bme680.xml diff --git a/examples/knx-esp-bme680/knx-bme680.ino b/examples/knx-bme680/knx-bme680.ino similarity index 99% rename from examples/knx-esp-bme680/knx-bme680.ino rename to examples/knx-bme680/knx-bme680.ino index 1eee699..96de618 100644 --- a/examples/knx-esp-bme680/knx-bme680.ino +++ b/examples/knx-bme680/knx-bme680.ino @@ -90,7 +90,8 @@ void setup(void) if (knx.configured()) { cyclSend = knx.paramInt(0); - Serial.printf("Zykl. send: %d\n", cyclSend); + Serial.print("Zykl. send:"); + Serial.println(cyclSend); } // start the framework. Will get wifi first. diff --git a/examples/knx-esp-demo/knx-esp-demo.knxprod b/examples/knx-demo/knx-demo-ip.knxprod similarity index 100% rename from examples/knx-esp-demo/knx-esp-demo.knxprod rename to examples/knx-demo/knx-demo-ip.knxprod diff --git a/examples/knx-esp-demo/knx-esp-demo.xml b/examples/knx-demo/knx-demo-ip.xml similarity index 100% rename from examples/knx-esp-demo/knx-esp-demo.xml rename to examples/knx-demo/knx-demo-ip.xml diff --git a/examples/knx-demo/knx-demo-tp.knxprod b/examples/knx-demo/knx-demo-tp.knxprod new file mode 100644 index 0000000000000000000000000000000000000000..ccb136353a00735032916bfe4dcfd1f3a3969ad1 GIT binary patch literal 41318 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 z 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 literal 0 HcmV?d00001 diff --git a/examples/knx-demo/knx-demo-tp.xml b/examples/knx-demo/knx-demo-tp.xml new file mode 100644 index 0000000..b7ae008 --- /dev/null +++ b/examples/knx-demo/knx-demo-tp.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/knx-esp-demo/knx-esp-demo.ino b/examples/knx-demo/knx-demo.ino similarity index 83% rename from examples/knx-esp-demo/knx-esp-demo.ino rename to examples/knx-demo/knx-demo.ino index b7ae38c..80e5473 100644 --- a/examples/knx-esp-demo/knx-esp-demo.ino +++ b/examples/knx-demo/knx-demo.ino @@ -1,4 +1,3 @@ -#include #include // declare array of all groupobjects with their sizes in byte @@ -62,7 +61,6 @@ void resetCallback(GroupObject& go) void setup() { Serial.begin(115200); - Serial.setDebugOutput(true); randomSeed(millis()); @@ -77,11 +75,11 @@ void setup() // print values of parameters if device is already configured if (knx.configured()) { - Serial.printf("Timeout: %d\n", knx.paramByte(0)); - Serial.printf("Zykl. senden: %d\n", knx.paramByte(1)); - Serial.printf("Min/Max senden: %d\n", knx.paramByte(2)); - Serial.printf("Aenderung senden: %d\n", knx.paramByte(3)); - Serial.printf("Abgleich %d\n", knx.paramByte(4)); + SerialDBG.print("Timeout: "); SerialDBG.println(knx.paramByte(0)); + SerialDBG.print("Zykl. senden: "); SerialDBG.println(knx.paramByte(1)); + SerialDBG.print("Min/Max senden: "); SerialDBG.println(knx.paramByte(2)); + SerialDBG.print("Aenderung senden: "); SerialDBG.println(knx.paramByte(3)); + SerialDBG.print("Abgleich: "); SerialDBG.println(knx.paramByte(4)); } // start the framework. Will get wifi first. diff --git a/src/arch_config.h b/src/arch_config.h new file mode 100644 index 0000000..044a407 --- /dev/null +++ b/src/arch_config.h @@ -0,0 +1,7 @@ +#pragma once + +#ifdef ARDUINO_ARCH_ESP8266 +#ifndef USE_STATES +#define USE_STATES +#endif +#endif \ No newline at end of file diff --git a/src/button.cpp b/src/button.cpp index e5a719b..5b014a1 100644 --- a/src/button.cpp +++ b/src/button.cpp @@ -2,9 +2,19 @@ #include "state.h" #include "knx_facade.h" +#ifdef USE_STATES unsigned long buttonTimestamp = 0; + +void buttonDown() +{ + buttonTimestamp = millis(); + attachInterrupt(knx.buttonPin(), buttonUp, RISING); +} +#endif + void buttonUp() { +#ifdef USE_STATES if (millis() - buttonTimestamp > 1000) { Serial.println("long button press"); @@ -16,10 +26,15 @@ void buttonUp() currentState->shortButtonPress(); } attachInterrupt(knx.buttonPin(), buttonDown, FALLING); -} - -void buttonDown() -{ - buttonTimestamp = millis(); - attachInterrupt(knx.buttonPin(), buttonUp, RISING); +#else if (knx.progMode()) + { + digitalWrite(knx.ledPin(), LOW); + knx.progMode(false); + } + else + { + digitalWrite(knx.ledPin(), HIGH); + knx.progMode(true); + } +#endif } \ No newline at end of file diff --git a/src/button.h b/src/button.h index 1c32762..4f921c1 100644 --- a/src/button.h +++ b/src/button.h @@ -1,4 +1,8 @@ #pragma once +#include "arch_config.h" + +#ifdef USE_STATES void buttonDown(); +#endif void buttonUp(); \ No newline at end of file diff --git a/src/esp_platform.cpp b/src/esp_platform.cpp index 017ff11..f68b4c0 100644 --- a/src/esp_platform.cpp +++ b/src/esp_platform.cpp @@ -1,4 +1,6 @@ #include "esp_platform.h" + +#ifdef ARDUINO_ARCH_ESP8266 #include #include #include @@ -169,3 +171,4 @@ size_t EspPlatform::readBytesUart(uint8_t *buffer, size_t length) printHex("p>", buffer, length); return length; } +#endif \ No newline at end of file diff --git a/src/esp_platform.h b/src/esp_platform.h index 4d5bd08..a07361d 100644 --- a/src/esp_platform.h +++ b/src/esp_platform.h @@ -1,7 +1,10 @@ +#ifdef ARDUINO_ARCH_ESP8266 #include "knx/platform.h" #include #include +#define SerialDBG Serial + class EspPlatform : public Platform { public: @@ -43,3 +46,4 @@ private: WiFiUDP _udp; }; +#endif \ No newline at end of file diff --git a/src/knx b/src/knx index 0762e75..aaf6c27 160000 --- a/src/knx +++ b/src/knx @@ -1 +1 @@ -Subproject commit 0762e753f73a44ca77a266753d8981203e579a32 +Subproject commit aaf6c275843ddcb541e8fdae4c8870ede1242370 diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index 0c4956a..efe1e20 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -4,9 +4,17 @@ #include "led.h" #include "nowifistate.h" -KnxFacade knx; +#ifdef ARDUINO_ARCH_SAMD +SamdPlatform platform; +Bau07B0 bau(platform); +#else +EspPlatform platform; +Bau57B0 bau(platform); +#endif +KnxFacade knx(bau); -KnxFacade::KnxFacade() : _bau(_platform) + +KnxFacade::KnxFacade(BauSystemB& bau) : _bau(bau) { manufacturerId(0xfa); _bau.addSaveRestore(this); @@ -69,8 +77,12 @@ void KnxFacade::writeMemory() void KnxFacade::loop() { +#ifdef USE_STATES if (currentState) currentState->loop(); +#else + knxLoop(); +#endif } void KnxFacade::knxLoop() @@ -112,12 +124,17 @@ void KnxFacade::start() { pinMode(_ledPin, OUTPUT); - pinMode(_buttonPin, INPUT); - attachInterrupt(_buttonPin, buttonDown, FALLING); + pinMode(_buttonPin, INPUT_PULLUP); +#ifdef USE_STATES + attachInterrupt(_buttonPin, buttonDown, FALLING); switchToSate(noWifiState); checkStates(); _ticker.attach_ms(100, doLed); +#else + attachInterrupt(knx.buttonPin(), buttonUp, RISING); + enabled(true); +#endif } uint8_t* KnxFacade::paramData(uint32_t addr) diff --git a/src/knx_facade.h b/src/knx_facade.h index 19fb3bc..6cd9fd1 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -1,16 +1,28 @@ #pragma once + +#include "arch_config.h" + +#ifdef ARDUINO_ARCH_SAMD +#include "samd_platform.h" +#include "knx/bau07B0.h" +#endif + +#ifdef ARDUINO_ARCH_ESP8266 #include #include "esp_platform.h" #include "knx/bau57B0.h" +#endif +#ifdef USE_STATES class RunningState; +#endif typedef uint8_t* (*saveRestoreCallback)(uint8_t* buffer); class KnxFacade : private SaveRestore { public: - KnxFacade(); + KnxFacade(BauSystemB& bau); bool enabled(); void enabled(bool value); bool progMode(); @@ -38,11 +50,12 @@ public: uint16_t paramWord(uint32_t addr); uint32_t paramInt(uint32_t addr); private: - EspPlatform _platform; - Bau57B0 _bau; + BauSystemB& _bau; uint32_t _ledPin = 16; uint32_t _buttonPin = 0; +#ifdef USE_STATES Ticker _ticker; +#endif saveRestoreCallback _saveCallback = 0; saveRestoreCallback _restoreCallback = 0; diff --git a/src/knx_facade_samd.cpp b/src/knx_facade_samd.cpp new file mode 100644 index 0000000..db2e2f4 --- /dev/null +++ b/src/knx_facade_samd.cpp @@ -0,0 +1,174 @@ +#include "knx_facade.h" +#if 0 +KnxFacade knx; + + +#define SerialDBG SerialUSB + +void buttonUp(); +long buttonTimestamp = 0; +void buttonDown() +{ + buttonTimestamp = millis(); + attachInterrupt(knx.buttonPin(), buttonUp, RISING); +} + +void buttonUp() +{ + // keep short/long for now + if (millis() - buttonTimestamp > 1000) + { + SerialDBG.println("long button press"); + } + else + { + SerialDBG.println("short button press"); + } + + if (knx.progMode()) + { + digitalWrite(knx.ledPin(), LOW); + knx.progMode(false); + } + else + { + digitalWrite(knx.ledPin(), HIGH); + knx.progMode(true); + } + + attachInterrupt(knx.buttonPin(), buttonDown, FALLING); +} + +KnxFacade::KnxFacade() : _bau(_platform) +{ + manufacturerId(0xfa); +} + +bool KnxFacade::enabled() +{ + return _bau.enabled(); +} + +void KnxFacade::enabled(bool value) +{ + _bau.enabled(true); +} + +bool KnxFacade::progMode() +{ + return _bau.deviceObject().progMode(); +} + +void KnxFacade::progMode(bool value) +{ + _bau.deviceObject().progMode(value); +} + +bool KnxFacade::configured() +{ + return _bau.configured(); +} + +uint32_t KnxFacade::ledPin() +{ + return _ledPin; +} + +void KnxFacade::ledPin(uint32_t value) +{ + _ledPin = value; +} + +uint32_t KnxFacade::buttonPin() +{ + return _buttonPin; +} + +void KnxFacade::buttonPin(uint32_t value) +{ + _buttonPin = value; +} + +void KnxFacade::readMemory() +{ + _bau.readMemory(); +} + +void KnxFacade::loop() +{ + _bau.loop(); +} + +void KnxFacade::registerGroupObjects(GroupObject* groupObjects, uint16_t count) +{ + _bau.groupObjectTable().groupObjects(groupObjects, count); +} + +void KnxFacade::manufacturerId(uint16_t value) +{ + _bau.deviceObject().manufacturerId(value); +} + +void KnxFacade::bauNumber(uint32_t value) +{ + _bau.deviceObject().bauNumber(value); +} + +void KnxFacade::orderNumber(const char* value) +{ + _bau.deviceObject().orderNumber(value); +} + +void KnxFacade::hardwareType(uint8_t* value) +{ + _bau.deviceObject().hardwareType(value); +} + +void KnxFacade::version(uint16_t value) +{ + _bau.deviceObject().version(value); +} + +void KnxFacade::start() +{ + pinMode(_ledPin, OUTPUT); + + pinMode(_buttonPin, INPUT_PULLUP); + attachInterrupt(_buttonPin, buttonDown, FALLING); + enabled(true); +} + +uint8_t* KnxFacade::paramData(uint32_t addr) +{ + if (!_bau.configured()) + return nullptr; + + return _bau.parameters().data(addr); +} + +uint8_t KnxFacade::paramByte(uint32_t addr) +{ + if (!_bau.configured()) + return 0; + + return _bau.parameters().getByte(addr); +} + +uint16_t KnxFacade::paramWord(uint32_t addr) +{ + if (!_bau.configured()) + return 0; + + return _bau.parameters().getWord(addr); +} + +uint32_t KnxFacade::paramInt(uint32_t addr) +{ + if (!_bau.configured()) + return 0; + + return _bau.parameters().getInt(addr); +} + + +#endif \ No newline at end of file diff --git a/src/led.cpp b/src/led.cpp index e1a66a6..41030f2 100644 --- a/src/led.cpp +++ b/src/led.cpp @@ -2,6 +2,7 @@ #include "knx_facade.h" #include "state.h" +#ifdef USE_STATES void doLed() { if (!currentState) @@ -25,4 +26,5 @@ void doLed() digitalWrite(knx.ledPin(), HIGH); else digitalWrite(knx.ledPin(), LOW); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/src/led.h b/src/led.h index 985759a..fadcac6 100644 --- a/src/led.h +++ b/src/led.h @@ -1,3 +1,7 @@ #pragma once -void doLed(); \ No newline at end of file +#include "arch_config.h" + +#ifdef USE_STATES +void doLed(); +#endif \ No newline at end of file diff --git a/src/linux_platform.cpp b/src/linux_platform.cpp new file mode 100644 index 0000000..229f4c0 --- /dev/null +++ b/src/linux_platform.cpp @@ -0,0 +1,279 @@ +#include "linux_platform.h" +#ifdef __linux__ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "knx/device_object.h" +#include "knx/address_table_object.h" +#include "knx/association_table_object.h" +#include "knx/group_object_table_object.h" +#include "knx/application_program_object.h" +#include "knx/ip_parameter_object.h" + +LinuxPlatform::LinuxPlatform() +{ + doMemoryMapping(); +} + +uint32_t LinuxPlatform::currentIpAddress() +{ + return 0; +} + +uint32_t LinuxPlatform::currentSubnetMask() +{ + return 0; +} + +uint32_t LinuxPlatform::currentDefaultGateway() +{ + return 0; +} + +uint32_t LinuxPlatform::millis() +{ + struct timespec spec; + + clock_gettime(CLOCK_MONOTONIC, &spec); + return spec.tv_sec * 1000 + round(spec.tv_nsec / 1.0e6); +} + +void LinuxPlatform::mdelay(uint32_t millis) +{ + struct timespec ts; + ts.tv_sec = millis / 1000; + ts.tv_nsec = (millis % 1000) * 1000000; + nanosleep(&ts, NULL); +} + +void LinuxPlatform::macAddress(uint8_t* data) +{ + // hardcode some address + data[0] = 0x08; + data[1] = 0x00; + data[2] = 0x27; + data[3] = 0x6c; + data[4] = 0xa8; + data[5] = 0x2a; +} + +void LinuxPlatform::restart() +{ + // do nothing +} + +void LinuxPlatform::fatalError() +{ + printf("A fatal error occured. Stopping.\n"); + while (true) + sleep(1); +} + +void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) +{ + _multicastAddr = addr; + _port = port; + + struct ip_mreq command; + uint32_t loop = 1; + + struct sockaddr_in sin; + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); + + _socketFd = socket(AF_INET, SOCK_DGRAM, 0); + if (_socketFd == -1) { + perror("socket()"); + fatalError(); + } + + /* Mehr Prozessen erlauben, denselben Port zu nutzen */ + loop = 1; + if (setsockopt(_socketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) + { + perror("setsockopt:SO_REUSEADDR"); + fatalError(); + } + + if (bind(_socketFd, (struct sockaddr *)&sin, sizeof(sin)) < 0) + { + perror("bind"); + fatalError(); + } + + /* Broadcast auf dieser Maschine zulassen */ + loop = 1; + if (setsockopt(_socketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) + { + perror("setsockopt:IP_MULTICAST_LOOP"); + fatalError(); + } + + /* Join the broadcast group: */ + command.imr_multiaddr.s_addr = htonl(addr); + command.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(_socketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0) + { + perror("setsockopt:IP_ADD_MEMBERSHIP"); + fatalError(); + } + + uint32_t flags = fcntl(_socketFd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(_socketFd, F_SETFL, flags); +} + +void LinuxPlatform::closeMultiCast() +{ + struct ip_mreq command; + command.imr_multiaddr.s_addr = htonl(_multicastAddr); + command.imr_interface.s_addr = htonl(INADDR_ANY); + + if (setsockopt(_socketFd, + IPPROTO_IP, + IP_DROP_MEMBERSHIP, + &command, sizeof(command)) < 0) { + perror("setsockopt:IP_DROP_MEMBERSHIP"); + } + close(_socketFd); +} + +bool LinuxPlatform::sendBytes(uint8_t* buffer, uint16_t len) +{ + struct sockaddr_in address = { 0 }; + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(_multicastAddr); + address.sin_port = htons(_port); + + ssize_t retVal = 0; + do + { + retVal = sendto(_socketFd, buffer, len, 0, (struct sockaddr *) &address, sizeof(address)); + if (retVal == -1) + { + if (errno != EAGAIN && errno != EWOULDBLOCK) + return false; + } + } while (retVal == -1); + return true; +} + +int LinuxPlatform::readBytes(uint8_t * buffer, uint16_t maxLen) +{ + uint32_t sin_len; + struct sockaddr_in sin; + + sin_len = sizeof(sin); + ssize_t len = recvfrom(_socketFd, buffer, maxLen, 0, (struct sockaddr *) &sin, &sin_len); + return len; +} + +uint8_t * LinuxPlatform::getEepromBuffer(uint16_t size) +{ + return _mappedFile + 2; +} + +void LinuxPlatform::commitToEeprom() +{ + fsync(_fd); +} + +#define FLASHSIZE 0x10000 +void LinuxPlatform::doMemoryMapping() +{ + _fd = open("flash.bin", O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IROTH); + if (_fd < 0) + { + perror("Error in file opening"); + //exit(-1); + } + + struct stat st; + uint32_t ret = fstat(_fd, &st); + if (ret < 0) + { + perror("Error in fstat"); + //exit(-1); + } + + size_t len_file = st.st_size; + if (len_file < FLASHSIZE) + { + if (ftruncate(_fd, FLASHSIZE) != 0) + { + perror("Error extending file"); + //exit(-1); + } + len_file = FLASHSIZE; + } + unsigned char* addr = (unsigned char*)mmap(NULL, len_file, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0); + if (addr[0] != 0xAF || addr[1] != 0xFE) + { + memset(addr, 0, FLASHSIZE); + addr[0] = 0xAF; + addr[1] = 0xFE; + } + + if (addr == MAP_FAILED) + { + perror("Error in mmap"); + //exit(-1); + } + _mappedFile = addr; +} + +size_t LinuxPlatform::readBytesUart(uint8_t *buffer, size_t length) +{ + return 0; +} + + +int LinuxPlatform::readUart() +{ + return -1; +} + + +size_t LinuxPlatform::writeUart(const uint8_t *buffer, size_t size) +{ + return 0; +} + + +size_t LinuxPlatform::writeUart(const uint8_t data) +{ + return 0; +} + + +int LinuxPlatform::uartAvailable() +{ + return 0; +} + + +void LinuxPlatform::closeUart() +{ +} + + +void LinuxPlatform::setupUart() +{ +} +#endif \ No newline at end of file diff --git a/src/linux_platform.h b/src/linux_platform.h new file mode 100644 index 0000000..710b9fa --- /dev/null +++ b/src/linux_platform.h @@ -0,0 +1,51 @@ +#pragma once + +#ifdef __linux__ + +#include "knx/platform.h" + +class LinuxPlatform: public Platform +{ +public: + LinuxPlatform(); + + // ip stuff + uint32_t currentIpAddress(); + uint32_t currentSubnetMask(); + uint32_t currentDefaultGateway(); + void macAddress(uint8_t* addr); + + // basic stuff + uint32_t millis(); + void mdelay(uint32_t millis); + void restart(); + void fatalError(); + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port); + void closeMultiCast(); + bool sendBytes(uint8_t* buffer, uint16_t len); + int readBytes(uint8_t* buffer, uint16_t maxLen); + + //uart + void setupUart(); + void closeUart(); + int uartAvailable(); + size_t writeUart(const uint8_t data); + size_t writeUart(const uint8_t *buffer, size_t size); + int readUart(); + size_t readBytesUart(uint8_t *buffer, size_t length); + + //memory + uint8_t* getEepromBuffer(uint16_t size); + void commitToEeprom(); +private: + uint32_t _multicastAddr; + uint16_t _port; + int _socketFd = -1; + void doMemoryMapping(); + uint8_t* _mappedFile; + int _fd; +}; + +#endif \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..d0094f0 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,116 @@ +#ifdef __linux__ + +#include "linux_platform.h" +#include "knx/bau57B0.h" +#include "knx/group_object_table_object.h" +#include +#include +#include + +LinuxPlatform platfrom; +Bau57B0 bau(platfrom); + +float currentValue = 0; +float maxValue = 0; +float minValue = RAND_MAX; +long lastsend = 0; + +GroupObject groupObjects[] +{ + GroupObject(2), + GroupObject(2), + GroupObject(2), + GroupObject(1) +}; +#define CURR groupObjects[0] +#define MAX groupObjects[1] +#define MIN groupObjects[2] +#define RESET groupObjects[3] + +void measureTemp() +{ + long now = platfrom.millis(); + if ((now - lastsend) < 2000) + return; + + lastsend = now; + int r = rand(); + currentValue = (r * 1.0) / (RAND_MAX * 1.0); + currentValue *= 100 * 100; + + CURR.objectWrite(currentValue); + + if (currentValue > maxValue) + { + maxValue = currentValue; + MAX.objectWrite(maxValue); + } + + if (currentValue < minValue) + { + minValue = currentValue; + MIN.objectWrite(minValue); + } +} + +void resetCallback(GroupObject& go) +{ + if (go.objectReadBool()) + { + maxValue = 0; + minValue = 10000; + } +} + +void appLoop() +{ + if (!bau.configured()) + return; + + measureTemp(); +} + +void setup() +{ + srand((unsigned int)time(NULL)); + bau.readMemory(); + + uint8_t hwType[] = { 0x0, 0x0, 0x8, 0x0, 0x0, 0x2 }; + GroupObjectTableObject& got(bau.groupObjectTable()); + got.groupObjects(groupObjects, 4); + + DeviceObject& devObj(bau.deviceObject()); + devObj.manufacturerId(0xfa); + devObj.bauNumber(0xdeadbeef); + devObj.orderNumber("Coolstuff"); + devObj.hardwareType(hwType); + devObj.version(0x0020); + + RESET.updateHandler = resetCallback; + + if (bau.deviceObject().induvidualAddress() == 0) + bau.deviceObject().progMode(true); + + if (bau.parameters().loadState() == LS_LOADED) + { + printf("Timeout: %d\n", bau.parameters().getWord(0)); + printf("Zykl. senden: %d\n", bau.parameters().getByte(2)); + printf("Min/Max senden: %d\n", bau.parameters().getByte(3)); + printf("Aenderung senden: %d\n", bau.parameters().getByte(4)); + printf("Abgleich %d\n", bau.parameters().getByte(5)); + } + bau.enabled(true); +} + +int main(int argc, char **argv) +{ + setup(); + + while (1) + { + bau.loop(); + appLoop(); + platfrom.mdelay(100); + } +} +#endif \ No newline at end of file diff --git a/src/nowifistate.cpp b/src/nowifistate.cpp index ddb6073..22feeb1 100644 --- a/src/nowifistate.cpp +++ b/src/nowifistate.cpp @@ -1,9 +1,11 @@ -#include - #include "nowifistate.h" #include "wpsstate.h" #include "runningstate.h" +#ifdef USE_STATES + +#include + NoWifiState noWifiState = NoWifiState(); void NoWifiState::shortButtonPress() @@ -32,4 +34,6 @@ void NoWifiState::enterState() Serial.printf("\nConnected successful to SSID '%s'\n", WiFi.SSID().c_str()); switchToSate(runningState); } -} \ No newline at end of file +} + +#endif \ No newline at end of file diff --git a/src/nowifistate.h b/src/nowifistate.h index f15d46e..f64892e 100644 --- a/src/nowifistate.h +++ b/src/nowifistate.h @@ -2,6 +2,8 @@ #include "state.h" +#ifdef USE_STATES + class NoWifiState : public State { public: @@ -13,4 +15,6 @@ public: virtual const char* name() { return "NoWifi"; } }; -extern NoWifiState noWifiState; \ No newline at end of file +extern NoWifiState noWifiState; + +#endif \ No newline at end of file diff --git a/src/programmingmodestate.cpp b/src/programmingmodestate.cpp index be52139..32ee313 100644 --- a/src/programmingmodestate.cpp +++ b/src/programmingmodestate.cpp @@ -2,6 +2,7 @@ #include "runningstate.h" #include "knx_facade.h" +#ifdef USE_STATES ProgramModeState programModeState = ProgramModeState(); void ProgramModeState::enterState() @@ -24,3 +25,4 @@ void ProgramModeState::loop() State::loop(); knx.knxLoop(); } +#endif \ No newline at end of file diff --git a/src/programmingmodestate.h b/src/programmingmodestate.h index 489fc8b..0167905 100644 --- a/src/programmingmodestate.h +++ b/src/programmingmodestate.h @@ -2,6 +2,8 @@ #include "state.h" +#ifdef USE_STATES + class ProgramModeState : public State { public: @@ -14,4 +16,6 @@ public: virtual const char* name() { return "ProgramMode"; } }; -extern ProgramModeState programModeState; \ No newline at end of file +extern ProgramModeState programModeState; + +#endif \ No newline at end of file diff --git a/src/runningstate.cpp b/src/runningstate.cpp index a13cc80..c97ef0a 100644 --- a/src/runningstate.cpp +++ b/src/runningstate.cpp @@ -3,6 +3,8 @@ #include "wpsstate.h" #include "knx_facade.h" +#ifdef USE_STATES + RunningState runningState = RunningState(); void RunningState::shortButtonPress() @@ -38,3 +40,4 @@ void RunningState::loop() State::loop(); knx.knxLoop(); } +#endif \ No newline at end of file diff --git a/src/runningstate.h b/src/runningstate.h index 374fb97..88d7b3e 100644 --- a/src/runningstate.h +++ b/src/runningstate.h @@ -1,7 +1,7 @@ #pragma once #include "state.h" - +#ifdef USE_STATES class RunningState : public State { public: @@ -17,4 +17,5 @@ private: bool _initialized = false; }; -extern RunningState runningState; \ No newline at end of file +extern RunningState runningState; +#endif \ No newline at end of file diff --git a/src/samd_platform.cpp b/src/samd_platform.cpp new file mode 100644 index 0000000..3e72a23 --- /dev/null +++ b/src/samd_platform.cpp @@ -0,0 +1,157 @@ +#include "samd_platform.h" + +#ifdef ARDUINO_ARCH_SAMD +#include + +#include +#include + +SamdPlatform::SamdPlatform() +{ +} + +uint32_t SamdPlatform::currentIpAddress() +{ + // not needed + return 0; +} + +uint32_t SamdPlatform::currentSubnetMask() +{ + // not needed + return 0; +} + +uint32_t SamdPlatform::currentDefaultGateway() +{ + // not needed + return 0; +} + +void SamdPlatform::macAddress(uint8_t * addr) +{ + // not needed +} + +uint32_t SamdPlatform::millis() +{ + return::millis(); +} + +void SamdPlatform::mdelay(uint32_t millis) +{ + delay(millis); +} + +void SamdPlatform::restart() +{ + SerialUSB.println("restart"); + NVIC_SystemReset(); +} + +void SamdPlatform::fatalError() +{ + const int period = 200; + while (true) + { + if ((millis() % period) > (period / 2)) + digitalWrite(LED_BUILTIN, HIGH); + else + digitalWrite(LED_BUILTIN, LOW); + } +} + +void SamdPlatform::setupMultiCast(uint32_t addr, uint16_t port) +{ + //not needed +} + +void SamdPlatform::closeMultiCast() +{ + //not needed +} + +bool SamdPlatform::sendBytes(uint8_t * buffer, uint16_t len) +{ + //not needed +} + +int SamdPlatform::readBytes(uint8_t * buffer, uint16_t maxLen) +{ + //not needed + return 0; +} + +uint8_t * SamdPlatform::getEepromBuffer(uint16_t size) +{ + //EEPROM.begin(size); + if(size > EEPROM_EMULATION_SIZE) + fatalError(); + + return EEPROM.getDataPtr(); +} + +void SamdPlatform::commitToEeprom() +{ + EEPROM.commit(); +} + + +void SamdPlatform::setupUart() +{ + SerialKNX.begin(19200, SERIAL_8E1); + while (!SerialKNX) + ; +} + + +void SamdPlatform::closeUart() +{ + SerialKNX.end(); +} + + +int SamdPlatform::uartAvailable() +{ + return SerialKNX.available(); +} + + +size_t SamdPlatform::writeUart(const uint8_t data) +{ + //printHex(" 0) + // printHex("p>", (uint8_t*)&val, 1); + return val; +} + + +size_t SamdPlatform::readBytesUart(uint8_t *buffer, size_t length) +{ + size_t toRead = length; + uint8_t* pos = buffer; + while (toRead > 0) + { + size_t val = SerialKNX.readBytes(pos, toRead); + pos += val; + toRead -= val; + } + //printHex("p>", buffer, length); + return length; +} + +#endif \ No newline at end of file diff --git a/src/samd_platform.h b/src/samd_platform.h new file mode 100644 index 0000000..df7acdb --- /dev/null +++ b/src/samd_platform.h @@ -0,0 +1,50 @@ +#include "knx/platform.h" + +#include "Arduino.h" + +#ifdef ARDUINO_ARCH_SAMD + +#define SerialDBG SerialUSB +#define SerialKNX Serial1 + +class SamdPlatform : public Platform +{ +public: + SamdPlatform(); + + // ip stuff + uint32_t currentIpAddress(); + uint32_t currentSubnetMask(); + uint32_t currentDefaultGateway(); + void macAddress(uint8_t* addr); + + // basic stuff + uint32_t millis(); + void mdelay(uint32_t millis); + void restart(); + void fatalError(); + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port); + void closeMultiCast(); + bool sendBytes(uint8_t* buffer, uint16_t len); + int readBytes(uint8_t* buffer, uint16_t maxLen); + + //uart + virtual void setupUart(); + virtual void closeUart(); + virtual int uartAvailable(); + virtual size_t writeUart(const uint8_t data); + virtual size_t writeUart(const uint8_t *buffer, size_t size); + virtual int readUart(); + virtual size_t readBytesUart(uint8_t *buffer, size_t length); + + //memory + uint8_t* getEepromBuffer(uint16_t size); + void commitToEeprom(); +private: + uint32_t _mulitcastAddr; + uint16_t _mulitcastPort; +}; + +#endif \ No newline at end of file diff --git a/src/state.cpp b/src/state.cpp index bffae1d..4199f46 100644 --- a/src/state.cpp +++ b/src/state.cpp @@ -1,6 +1,8 @@ #include "state.h" #include "Arduino.h" +#ifdef USE_STATES + State* volatile currentState = 0; State* volatile nextState = 0; @@ -51,3 +53,5 @@ void State::loop() { checkStates(); } + +#endif \ No newline at end of file diff --git a/src/state.h b/src/state.h index a8b77a9..9b155b1 100644 --- a/src/state.h +++ b/src/state.h @@ -1,4 +1,7 @@ #pragma once +#include "arch_config.h" + +#ifdef USE_STATES class State { @@ -26,4 +29,6 @@ void switchToSate(State& state); void checkStates(); extern State* volatile currentState; -extern State* volatile nextState; \ No newline at end of file +extern State* volatile nextState; + +#endif \ No newline at end of file diff --git a/src/wpsstate.cpp b/src/wpsstate.cpp index 7c395a6..615f290 100644 --- a/src/wpsstate.cpp +++ b/src/wpsstate.cpp @@ -1,3 +1,6 @@ +#include "arch_config.h" + +#ifdef USE_STATES #include #include "wpsstate.h" @@ -26,3 +29,5 @@ void WpsState::enterState() } } } + +#endif diff --git a/src/wpsstate.h b/src/wpsstate.h index 5460bb4..3f985ab 100644 --- a/src/wpsstate.h +++ b/src/wpsstate.h @@ -2,6 +2,7 @@ #include "state.h" +#ifdef USE_STATES class WpsState : public State { public: @@ -12,3 +13,5 @@ public: }; extern WpsState wpsState; + +#endif diff --git a/visualstudio/ClassDiagram.cd b/visualstudio/ClassDiagram.cd new file mode 100644 index 0000000..fa67e07 --- /dev/null +++ b/visualstudio/ClassDiagram.cd @@ -0,0 +1,95 @@ + + + + + + IBAAAAAAQACAEAIAABAAAAgAAAAAAAAAAAAAAABAAEA= + knx\address_table_object.h + + + + + + AIAAAAAAAACAAAIAgCAAAAAgABAEAAAAAAAQQABAAAA= + knx\application_program_object.h + + + + + + AAAAAAAAAACAAgIAABAAQAgAAAEAAAAAAAAAAABAAEA= + knx\association_table_object.h + + + + + + AAACACEAAAGCIAKAQCAgAACgCECAAEIgAEgAAgJAAAA= + knx\device_object.h + + + + + + AAAAAEAACACAAgIAAhAATAgACAAAAAAAAAAAAABAAAA= + knx\group_object_table_object.h + + + + + + AAAAAAAAAAAAAAAAACAAAAAgAAAAAAAAAAAAABBAAAA= + knx\interface_object.h + + + + + + AAIACIAAYACAAKIAAGAQCAAgWAIAAAAGAAAAAABgAIA= + knx\ip_parameter_object.h + + + + + + AAIACIACBACAAIIAAGAASAgwyAAAAAAAAgAAAAJgAAA= + knx\table_object.h + + + + + + sKoIAAAAQIIxC4gUUEAIAAACiQEgAjQUFCCA5yEAIBw= + knx\bau.h + + + + + + ABIAAFAgAgIwCoAAUiCCQIDAiEBgADQQACAAAAKQABw= + knx\bau57B0.h + + + + + + BACCIBAAICAAICgAAABAgAAQAAAAAAgAAADAEAAAAhA= + linux_platform.h + + + + + + AAAAAAAAAACAAAIAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + knx\save_restore.h + + + + + + AAACIBAAICAAIAAAAABAgAAAAAAAAAgAAADAEAAAAhA= + knx\platform.h + + + + \ No newline at end of file diff --git a/visualstudio/knx-bme680.vgdbproj b/visualstudio/knx-bme680.vgdbproj index 86b5086..81da2fc 100644 --- a/visualstudio/knx-bme680.vgdbproj +++ b/visualstudio/knx-bme680.vgdbproj @@ -10,7 +10,7 @@ 58afeecd-06e2-4bb7-a13f-e1d5dbaed13f true true - ..\examples\knx-esp-bme680 + ..\examples\knx-bme680 basic_config_state_ulp_plus.ino @@ -278,6 +278,63 @@ Sketch + + Arduino Genuino Zero (Native USB Port) + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + main + true + false + false + false + 0 + + + true + Auto + 0 + false + false + true + false + false + + _estack + 0 + false + true + + + arduino:samd:arduino_zero_native + + + + Sketch + + \ No newline at end of file diff --git a/visualstudio/knx-esp.vgdbproj b/visualstudio/knx-demo.vgdbproj similarity index 74% rename from visualstudio/knx-esp.vgdbproj rename to visualstudio/knx-demo.vgdbproj index 4234096..0dc1c7e 100644 --- a/visualstudio/knx-esp.vgdbproj +++ b/visualstudio/knx-demo.vgdbproj @@ -10,12 +10,12 @@ 6165cd6a-91a4-49fa-977a-48f22086ca8e true true - ..\examples\knx-esp-demo + ..\examples\knx-demo Sketch.ino - knx-esp-demo.ino + knx-demo.ino @@ -82,6 +82,12 @@ 238 144 + + 255 + 169 + 169 + 169 + 16 @@ -275,6 +281,63 @@ Sketch + + Arduino Genuino Zero (Native USB Port) + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + main + true + false + false + false + 0 + + + true + Auto + 0 + false + false + true + false + false + + _estack + 0 + false + true + + + arduino:samd:arduino_zero_native + + + + Sketch + + \ No newline at end of file diff --git a/visualstudio/knx-linux-Debug.vgdbsettings b/visualstudio/knx-linux-Debug.vgdbsettings new file mode 100644 index 0000000..d3e6100 --- /dev/null +++ b/visualstudio/knx-linux-Debug.vgdbsettings @@ -0,0 +1,148 @@ + + + Release + + + + RemoteUnix + + + localhost + LinuxSubsystem + Linux + + + false + + localhost + LinuxSubsystem + Linux + + $(ProjectDir) + /home/tkunze/vgdb/knx-linux + + *.cpp + *.h + *.hpp + *.c + *.cc + *.cxx + *.mak + Makefile + *.txt + *.cmake + CMakeLists.txt + *.cmake + + true + true + + true + true + + false + false + false + false + false + $(ProjectDir) + + + + com.sysprogs.toolchain.default-gcc + + 0 + + + knx-linux.vcxproj + 0 + true + + + + + + + + + + + + + Default + + + + true + + + + + Unknown + + true + false + + + + + false + + + + + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + main + true + false + false + false + 0 + + + + + + LANG + en_US.UTF-8 + + + + + $(TargetPath) + 2000 + + + false + Local + false + false + Auto + true + false + + \ No newline at end of file diff --git a/visualstudio/knx-linux-Release.vgdbsettings b/visualstudio/knx-linux-Release.vgdbsettings new file mode 100644 index 0000000..d3e6100 --- /dev/null +++ b/visualstudio/knx-linux-Release.vgdbsettings @@ -0,0 +1,148 @@ + + + Release + + + + RemoteUnix + + + localhost + LinuxSubsystem + Linux + + + false + + localhost + LinuxSubsystem + Linux + + $(ProjectDir) + /home/tkunze/vgdb/knx-linux + + *.cpp + *.h + *.hpp + *.c + *.cc + *.cxx + *.mak + Makefile + *.txt + *.cmake + CMakeLists.txt + *.cmake + + true + true + + true + true + + false + false + false + false + false + $(ProjectDir) + + + + com.sysprogs.toolchain.default-gcc + + 0 + + + knx-linux.vcxproj + 0 + true + + + + + + + + + + + + + Default + + + + true + + + + + Unknown + + true + false + + + + + false + + + + + + + + + false + false + false + false + false + false + false + false + false + + false + false + false + false + false + false + true + false + None + false + false + main + true + false + false + false + 0 + + + + + + LANG + en_US.UTF-8 + + + + + $(TargetPath) + 2000 + + + false + Local + false + false + Auto + true + false + + \ No newline at end of file diff --git a/visualstudio/knx-linux.vcxproj b/visualstudio/knx-linux.vcxproj new file mode 100644 index 0000000..1e732b4 --- /dev/null +++ b/visualstudio/knx-linux.vcxproj @@ -0,0 +1,131 @@ + + + + + Debug + VisualGDB + + + Release + VisualGDB + + + + 15.0 + {819E55F9-05A8-454D-B771-4A99F775DD87} + + + + + GCC + + + + GCC + + + com.sysprogs.toolchain.default-gcc + + + + + + + + + + + + localhost-lxss + + + localhost-lxss + + + + /usr/include/x86_64-linux-gnu;%(ClCompile.AdditionalIncludeDirectories) + + + + + + + + /usr/include/x86_64-linux-gnu;%(ClCompile.AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/visualstudio/knx-linux.vcxproj.filters b/visualstudio/knx-linux.vcxproj.filters new file mode 100644 index 0000000..5cfbad1 --- /dev/null +++ b/visualstudio/knx-linux.vcxproj.filters @@ -0,0 +1,217 @@ + + + + + {7612a532-0bb6-4a82-917a-48cfa6410e4f} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {842f6d29-354f-47a8-bfd9-0fccf0ddf144} + h;hpp;hxx;hm;inl;inc;xsd + + + {c46b2f8f-4105-4638-af5c-09a641257065} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + {c818187b-4f9f-4ee9-86c3-d26e56e49bf9} + *.vgdbsettings + + + {169b6f5b-b022-4422-ace2-819bf2f5e883} + + + {4054619f-7b60-405c-96e8-311c464cf8de} + + + + + + VisualGDB settings + + + VisualGDB settings + + + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + + + + + Source files\knx + + + Source files + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + + + \ No newline at end of file diff --git a/visualstudio/knx.sln b/visualstudio/knx.sln new file mode 100644 index 0000000..69aad4e --- /dev/null +++ b/visualstudio/knx.sln @@ -0,0 +1,57 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.28010.2050 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "knx-linux", "knx-linux.vcxproj", "{819E55F9-05A8-454D-B771-4A99F775DD87}" +EndProject +Project("{803FD0C6-D64E-4E16-9DC3-1DAEC859A3D2}") = "knx-bme680", "knx-bme680.vgdbproj", "{58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}" +EndProject +Project("{803FD0C6-D64E-4E16-9DC3-1DAEC859A3D2}") = "knx-demo", "knx-demo.vgdbproj", "{6165CD6A-91A4-49FA-977A-48F22086CA8E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Arduino Genuino Zero (Native USB Port) = Debug|Arduino Genuino Zero (Native USB Port) + Debug|NodeMCU 1 0 (ESP-12E Module) = Debug|NodeMCU 1 0 (ESP-12E Module) + Debug|VisualGDB = Debug|VisualGDB + Release|Arduino Genuino Zero (Native USB Port) = Release|Arduino Genuino Zero (Native USB Port) + Release|NodeMCU 1 0 (ESP-12E Module) = Release|NodeMCU 1 0 (ESP-12E Module) + Release|VisualGDB = Release|VisualGDB + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {819E55F9-05A8-454D-B771-4A99F775DD87}.Debug|Arduino Genuino Zero (Native USB Port).ActiveCfg = Debug|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Debug|NodeMCU 1 0 (ESP-12E Module).ActiveCfg = Debug|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Debug|VisualGDB.ActiveCfg = Debug|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Debug|VisualGDB.Build.0 = Debug|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Release|Arduino Genuino Zero (Native USB Port).ActiveCfg = Release|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Release|NodeMCU 1 0 (ESP-12E Module).ActiveCfg = Release|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Release|VisualGDB.ActiveCfg = Release|VisualGDB + {819E55F9-05A8-454D-B771-4A99F775DD87}.Release|VisualGDB.Build.0 = Release|VisualGDB + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Debug|Arduino Genuino Zero (Native USB Port).ActiveCfg = Debug|Arduino Genuino Zero (Native USB Port) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Debug|Arduino Genuino Zero (Native USB Port).Build.0 = Debug|Arduino Genuino Zero (Native USB Port) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Debug|NodeMCU 1 0 (ESP-12E Module).ActiveCfg = Debug|NodeMCU 1 0 (ESP-12E Module) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Debug|NodeMCU 1 0 (ESP-12E Module).Build.0 = Debug|NodeMCU 1 0 (ESP-12E Module) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Debug|VisualGDB.ActiveCfg = Debug|Arduino Genuino Zero (Native USB Port) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Release|Arduino Genuino Zero (Native USB Port).ActiveCfg = Release|Arduino Genuino Zero (Native USB Port) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Release|Arduino Genuino Zero (Native USB Port).Build.0 = Release|Arduino Genuino Zero (Native USB Port) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Release|NodeMCU 1 0 (ESP-12E Module).ActiveCfg = Release|NodeMCU 1 0 (ESP-12E Module) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Release|NodeMCU 1 0 (ESP-12E Module).Build.0 = Release|NodeMCU 1 0 (ESP-12E Module) + {58AFEECD-06E2-4BB7-A13F-E1D5DBAED13F}.Release|VisualGDB.ActiveCfg = Release|Arduino Genuino Zero (Native USB Port) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Debug|Arduino Genuino Zero (Native USB Port).ActiveCfg = Debug|Arduino Genuino Zero (Native USB Port) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Debug|Arduino Genuino Zero (Native USB Port).Build.0 = Debug|Arduino Genuino Zero (Native USB Port) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Debug|NodeMCU 1 0 (ESP-12E Module).ActiveCfg = Debug|NodeMCU 1 0 (ESP-12E Module) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Debug|NodeMCU 1 0 (ESP-12E Module).Build.0 = Debug|NodeMCU 1 0 (ESP-12E Module) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Debug|VisualGDB.ActiveCfg = Debug|Arduino Genuino Zero (Native USB Port) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Release|Arduino Genuino Zero (Native USB Port).ActiveCfg = Release|Arduino Genuino Zero (Native USB Port) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Release|Arduino Genuino Zero (Native USB Port).Build.0 = Release|Arduino Genuino Zero (Native USB Port) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Release|NodeMCU 1 0 (ESP-12E Module).ActiveCfg = Release|NodeMCU 1 0 (ESP-12E Module) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Release|NodeMCU 1 0 (ESP-12E Module).Build.0 = Release|NodeMCU 1 0 (ESP-12E Module) + {6165CD6A-91A4-49FA-977A-48F22086CA8E}.Release|VisualGDB.ActiveCfg = Release|Arduino Genuino Zero (Native USB Port) + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {721CAB98-83F8-4035-AC23-77AEA55B634D} + EndGlobalSection +EndGlobal