diff --git a/examples/knx-demo/knx-demo.ino b/examples/knx-demo/knx-demo.ino index a72b214..f1e22c0 100644 --- a/examples/knx-demo/knx-demo.ino +++ b/examples/knx-demo/knx-demo.ino @@ -1,108 +1,180 @@ #include -#include -#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32) -#include +#define USE_KNX + +#ifdef USE_KNX + #include + + #if (MASK_VERSION != 0x07B0) && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32) + #include + #endif + +#if USE_W5X00 == 1 + #include + #include #endif -// 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) + // 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; + 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); - - if (currentValue > maxValue) + void measureTemp() { - maxValue = currentValue; - goMax.value(maxValue); + 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); + + if (currentValue > maxValue) + { + maxValue = currentValue; + goMax.value(maxValue); + } + + if (currentValue < minValue) + { + minValue = currentValue; + goMin.value(minValue); + } } - if (currentValue < minValue) + // callback from reset-GO + void resetCallback(GroupObject& go) { - minValue = currentValue; - goMin.value(minValue); + if (go.value()) + { + maxValue = 0; + minValue = 10000; + } } -} - -// callback from reset-GO -void resetCallback(GroupObject& go) -{ - if (go.value()) - { - maxValue = 0; - minValue = 10000; - } -} +#endif void setup() { Serial.begin(115200); - ArduinoPlatform::SerialDebug = &Serial; - - randomSeed(millis()); - -#if MASK_VERSION != 0x07B0 && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32) - 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 - goReset.callback(resetCallback); - 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)); + while (!Serial) { + delay(1000); // wait for serial port to connect. Needed for native USB port only, long for vscode stupid text } - // 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); + // IP stuff + #if USE_W5X00 == 1 + println("****** Set SS to pin 4 ******"); + Ethernet.init(4); + byte _ma[6] = {0xC0, 0xFF, 0xEE, 0xC0, 0xDE, 0x00}; + println("****** Bring up ethernet connection ******"); + Ethernet.begin(_ma); + if (Ethernet.hardwareStatus() == EthernetNoHardware) { + println("****** No Ethernet shield found ******."); + println("****** Ideling forever... ******"); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware or link + } + } + if (Ethernet.hardwareStatus() != EthernetW5500) { + println("****** Currently only working on W5500 controller ******"); + println("****** Ideling forever... ******"); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware or link + } + } + if (Ethernet.linkStatus() == LinkOFF) { + println("Link status: Off (No network cable connected or port on switch down)"); + println("****** Ideling forever... ******"); + while (true) { + delay(1); // do nothing, no point running without Ethernet hardware or link + } + } + println("****** Ethernet shield connected ******"); + println("****** W5500 Ethernet controller detected ******"); + println("****** Link status: On ******"); + char ar[50]; + sprintf(ar, "****** Mac address used: %02X:%02X:%02X:%02X:%02X:%02X ******", _ma[0], _ma[1], _ma[2], _ma[3], _ma[4], _ma[5]); + println(ar); + println("****** Ethernet connection up ******"); + println("****** Connected with DHCP ******"); + IPAddress _ip = Ethernet.localIP(); + sprintf(ar, "****** IP address: %d.%d.%d.%d ******", _ip[0], _ip[1], _ip[2], _ip[3]); + println(ar); + _ip = Ethernet.subnetMask(); + sprintf(ar, "****** Subnet mask: %d.%d.%d.%d ******", _ip[0], _ip[1], _ip[2], _ip[3]); + println(ar); + _ip = Ethernet.gatewayIP(); + sprintf(ar, "****** Gateway: %d.%d.%d.%d ******", _ip[0], _ip[1], _ip[2], _ip[3]); + println(ar); + #endif - // start the framework. - knx.start(); + #ifdef USE_KNX + ArduinoPlatform::SerialDebug = &Serial; + println("****** Serial debug running ******"); + + randomSeed(millis()); + + #if ((MASK_VERSION != 0x07B0) && (defined ARDUINO_ARCH_ESP8266 || defined ARDUINO_ARCH_ESP32)) + WiFiManager wifiManager; + wifiManager.autoConnect("knx-demo"); + #endif + + println("****** Start reading configuration ******"); + // 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()) + { + println("****** Configuration found ******"); + // register callback for reset GO + goReset.callback(resetCallback); + 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)); + } + else{ + println("****** No stored configuration found ******"); + } + + // 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 + println("****** Set KNX reset button to pin 1 ******"); + knx.buttonPin(1); + println("****** Starting knx framework ******"); + // start the framework. + knx.start(); + println("****** Knx framework started ******"); + #endif } void loop() { +#ifdef USE_KNX // don't delay here to much. Otherwise you might lose packages or mess up the timing with ETS knx.loop(); @@ -110,5 +182,7 @@ void loop() if (!knx.configured()) return; - measureTemp(); + // measureTemp(); +#endif + } diff --git a/platformio.ini b/platformio.ini index 23ac4f9..d3990e0 100644 --- a/platformio.ini +++ b/platformio.ini @@ -11,17 +11,40 @@ [platformio] src_dir = examples/knx-demo - -[env] +[env:feather_m4_w5500] platform = atmelsam -board = zeroUSB +board = adafruit_feather_m4 framework = arduino build_type = debug monitor_speed = 115200 -lib_ldf_mode = deep+ +; lib_ldf_mode = deep+ lib_extra_dirs = - ${sysenv.USERPROFILE}/Documents/PlatformIO/Projects + ${sysenv.USERPROFILE}/Documents/Arduino/libraries +lib_compat_mode = strict +lib_deps = + build_flags = + ; -DMASK_VERSION=0x07B0 + -DMASK_VERSION=0x57B0 + -DUSE_W5X00=1 + -DKNX_NO_SPI=1 + ; -DKNX_NO_DEFAULT_UART=1 -Wno-unknown-pragmas +; [env:feather_esspresif32] +; platform = espressif32 +; board = esp32dev +; framework = arduino +; build_type = debug +; monitor_speed = 115200 +; ; lib_ldf_mode = deep+ +; lib_extra_dirs = +; ${sysenv.USERPROFILE}/Documents/Arduino/libraries +; lib_compat_mode = strict +; lib_deps = + +; build_flags = +; -DMASK_VERSION=0x57B0, +; -Wno-unknown-pragmas + [env:build] diff --git a/src/knx/knx_value.cpp b/src/knx/knx_value.cpp index c8d9f54..d255c88 100644 --- a/src/knx/knx_value.cpp +++ b/src/knx/knx_value.cpp @@ -1,562 +1,562 @@ -#include "knx_value.h" - -#include -#include -#include - -KNXValue::KNXValue(bool value) -{ - _value.boolValue = value; - _type = BoolType; -} - -KNXValue::KNXValue(uint8_t value) -{ - _value.ucharValue = value; - _type = UCharType; -} - -KNXValue::KNXValue(uint16_t value) -{ - _value.ushortValue = value; - _type = UShortType; -} - -KNXValue::KNXValue(uint32_t value) -{ - _value.uintValue = value; - _type = UIntType; -} - -KNXValue::KNXValue(uint64_t value) -{ - _value.ulongValue = value; - _type = ULongType; -} - -KNXValue::KNXValue(int8_t value) -{ - _value.charValue = value; - _type = CharType; -} - -KNXValue::KNXValue(int16_t value) -{ - _value.shortValue = value; - _type = ShortType; -} - -KNXValue::KNXValue(int32_t value) -{ - _value.intValue = value; - _type = IntType; -} - -KNXValue::KNXValue(int64_t value) -{ - _value.longValue = value; - _type = LongType; -} - -KNXValue::KNXValue(double value) -{ - _value.doubleValue = value; - _type = DoubleType; -} - -KNXValue::KNXValue(const char* value) -{ - _value.stringValue = value; - _type = StringType; -} - -KNXValue::KNXValue(struct tm value) -{ - _value.timeValue = value; - _type = TimeType; -} - -KNXValue::operator bool() const -{ - return boolValue(); -} - -KNXValue::operator uint8_t() const -{ - return ucharValue(); -} - -KNXValue::operator uint16_t() const -{ - return ushortValue(); -} - -KNXValue::operator uint32_t() const -{ - return uintValue(); -} - -KNXValue::operator uint64_t() const -{ - return ulongValue(); -} - -KNXValue::operator int8_t() const -{ - return charValue(); -} - -KNXValue::operator int16_t() const -{ - return shortValue(); -} - -KNXValue::operator int32_t() const -{ - return intValue(); -} - -KNXValue::operator int64_t() const -{ - return longValue(); -} - -KNXValue::operator double() const -{ - return doubleValue(); -} - -KNXValue::operator const char*() const -{ - return stringValue(); -} - -KNXValue::operator struct tm() const -{ - return timeValue(); -} - -KNXValue& KNXValue::operator=(const bool value) -{ - _value.boolValue = value; - _type = BoolType; - return *this; -} - -KNXValue& KNXValue::operator=(const uint8_t value) -{ - _value.ucharValue = value; - _type = UCharType; - return *this; -} - -KNXValue& KNXValue::operator=(const uint16_t value) -{ - _value.ushortValue = value; - _type = UShortType; - return *this; -} - -KNXValue& KNXValue::operator=(const uint32_t value) -{ - _value.uintValue = value; - _type = UIntType; - return *this; -} - -KNXValue& KNXValue::operator=(const uint64_t value) -{ - _value.ulongValue = value; - _type = ULongType; - return *this; -} - -KNXValue& KNXValue::operator=(const int8_t value) -{ - _value.charValue = value; - _type = CharType; - return *this; -} - -KNXValue& KNXValue::operator=(const int16_t value) -{ - _value.shortValue = value; - _type = ShortType; - return *this; -} - -KNXValue& KNXValue::operator=(const int32_t value) -{ - _value.intValue = value; - _type = IntType; - return *this; -} - -KNXValue& KNXValue::operator=(const int64_t value) -{ - _value.longValue = value; - _type = LongType; - return *this; -} - -KNXValue& KNXValue::operator=(const double value) -{ - _value.doubleValue = value; - _type = DoubleType; - return *this; -} - -KNXValue& KNXValue::operator=(const char* value) -{ - _value.stringValue = value; - _type = StringType; - return *this; -} - -KNXValue& KNXValue::operator=(const struct tm value) -{ - _value.timeValue = value; - _type = TimeType; - return *this; -} - -bool KNXValue::boolValue() const -{ - switch (_type) - { - case BoolType: - return _value.boolValue; - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case CharType: - case ShortType: - case IntType: - case LongType: - case TimeType: - return longValue() != 0; - case DoubleType: - return _value.doubleValue != 0; - case StringType: - return strcmp(_value.stringValue, "true") == 0 || strcmp(_value.stringValue, "True") == 0 || longValue() != 0 || doubleValue() != 0; - } - return 0; -} - -uint8_t KNXValue::ucharValue() const -{ - switch (_type) - { - case UCharType: - return _value.ucharValue; - case BoolType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (uint8_t)ulongValue(); - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (uint8_t)longValue(); - } - return 0; -} - -uint16_t KNXValue::ushortValue() const -{ - switch (_type) - { - case UShortType: - return _value.ushortValue; - case BoolType: - case UCharType: - case UIntType: - case ULongType: - case TimeType: - return (uint16_t)ulongValue(); - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (uint16_t)longValue(); - } - return 0; -} - -uint32_t KNXValue::uintValue() const -{ - switch (_type) - { - case UIntType: - return _value.uintValue; - case BoolType: - case UCharType: - case UShortType: - case ULongType: - case TimeType: - return (uint32_t)ulongValue(); - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (uint32_t)longValue(); - } - return 0; -} - -uint64_t KNXValue::ulongValue() const -{ - switch (_type) - { - case ULongType: - return _value.ulongValue; - case BoolType: - return _value.boolValue ? 1 : 0; - case UCharType: - return (uint64_t)_value.ucharValue; - case UShortType: - return (uint64_t)_value.ushortValue; - case UIntType: - return (uint64_t)_value.uintValue; - case TimeType: - { - struct tm* timeptr = const_cast(&_value.timeValue); - return (uint64_t)mktime(timeptr); - } - case CharType: - return (uint64_t)_value.charValue; - case ShortType: - return (uint64_t)_value.shortValue; - case IntType: - return (uint64_t)_value.intValue; - case LongType: - return (uint64_t)_value.longValue; - 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; -} - -int8_t KNXValue::charValue() const -{ - switch (_type) - { - case CharType: - return _value.charValue; - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (int8_t)ulongValue(); - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (int8_t)longValue(); - } - return 0; -} - -int16_t KNXValue::shortValue() const -{ - switch (_type) - { - case ShortType: - return _value.shortValue; - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (int16_t)ulongValue(); - case CharType: - case IntType: - case LongType: - case DoubleType: - case StringType: - return (int16_t)longValue(); - } - return 0; -} - -int32_t KNXValue::intValue() const -{ - switch (_type) - { - case IntType: - return _value.shortValue; - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - return (int32_t)ulongValue(); - case CharType: - case ShortType: - case LongType: - case DoubleType: - case StringType: - return (int32_t)longValue(); - } - return 0; -} - -int64_t KNXValue::longValue() const -{ - switch (_type) - { - case LongType: - return _value.longValue; - case BoolType: - return _value.boolValue ? 1 : 0; - case UCharType: - return (int64_t)_value.ucharValue; - case UShortType: - return (int64_t)_value.ushortValue; - case UIntType: - return (int64_t)_value.uintValue; - case ULongType: - return (int64_t)_value.uintValue; - case TimeType: - return (int64_t)ulongValue(); - case CharType: - return (int64_t)_value.charValue; - case ShortType: - return (int64_t)_value.shortValue; - case IntType: - return (int64_t)_value.intValue; - 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; -} - -double KNXValue::doubleValue() const -{ - switch (_type) - { - case DoubleType: - return _value.doubleValue; - case BoolType: - return _value.boolValue ? 1 : 0; - case UCharType: - return _value.ucharValue; - case UShortType: - return _value.ushortValue; - case UIntType: - return _value.uintValue; - case ULongType: - return _value.uintValue; - case TimeType: - return ulongValue(); - case CharType: - return _value.charValue; - case ShortType: - return _value.shortValue; - case IntType: - return _value.intValue; - case LongType: - return _value.longValue; - case StringType: -#ifndef KNX_NO_STRTOx_CONVERSION - return strtod(_value.stringValue, NULL); -#else - return 0; -#endif - } - return 0; -} - -const char* KNXValue::stringValue() const -{ - switch (_type) - { - case DoubleType: - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case TimeType: - case CharType: - case ShortType: - case IntType: - case LongType: - return ""; // we would have to manage the memory for the string otherwise. Maybe later. - case StringType: - return _value.stringValue; - } - return 0; -} - -struct tm KNXValue::timeValue() const -{ - switch (_type) - { - case TimeType: - return _value.timeValue; - case BoolType: - case UCharType: - case UShortType: - case UIntType: - case ULongType: - case CharType: - case ShortType: - case IntType: - case LongType: - case DoubleType: - case StringType: - { - time_t timeVal = ulongValue(); - struct tm timeStruct; - gmtime_r(&timeVal, &timeStruct); - return timeStruct; - } - } - struct tm tmp = {0}; - return tmp; -} - -KNXValue::KNXValue(float value) -{ - _value.doubleValue = value; - _type = DoubleType; -} - -KNXValue& KNXValue::operator=(const float value) -{ - _value.doubleValue = value; - _type = DoubleType; - return *this; -} - -KNXValue::operator float() const -{ - return doubleValue(); +#include "knx_value.h" + +#include +#include +#include + +KNXValue::KNXValue(bool value) +{ + _value.boolValue = value; + _type = BoolType; +} + +KNXValue::KNXValue(uint8_t value) +{ + _value.ucharValue = value; + _type = UCharType; +} + +KNXValue::KNXValue(uint16_t value) +{ + _value.ushortValue = value; + _type = UShortType; +} + +KNXValue::KNXValue(uint32_t value) +{ + _value.uintValue = value; + _type = UIntType; +} + +KNXValue::KNXValue(uint64_t value) +{ + _value.ulongValue = value; + _type = ULongType; +} + +KNXValue::KNXValue(int8_t value) +{ + _value.charValue = value; + _type = CharType; +} + +KNXValue::KNXValue(int16_t value) +{ + _value.shortValue = value; + _type = ShortType; +} + +KNXValue::KNXValue(int32_t value) +{ + _value.intValue = value; + _type = IntType; +} + +KNXValue::KNXValue(int64_t value) +{ + _value.longValue = value; + _type = LongType; +} + +KNXValue::KNXValue(double value) +{ + _value.doubleValue = value; + _type = DoubleType; +} + +KNXValue::KNXValue(const char* value) +{ + _value.stringValue = value; + _type = StringType; +} + +KNXValue::KNXValue(struct tm value) +{ + _value.timeValue = value; + _type = TimeType; +} + +KNXValue::operator bool() const +{ + return boolValue(); +} + +KNXValue::operator uint8_t() const +{ + return ucharValue(); +} + +KNXValue::operator uint16_t() const +{ + return ushortValue(); +} + +KNXValue::operator uint32_t() const +{ + return uintValue(); +} + +KNXValue::operator uint64_t() const +{ + return ulongValue(); +} + +KNXValue::operator int8_t() const +{ + return charValue(); +} + +KNXValue::operator int16_t() const +{ + return shortValue(); +} + +KNXValue::operator int32_t() const +{ + return intValue(); +} + +KNXValue::operator int64_t() const +{ + return longValue(); +} + +KNXValue::operator double() const +{ + return doubleValue(); +} + +KNXValue::operator const char*() const +{ + return stringValue(); +} + +KNXValue::operator struct tm() const +{ + return timeValue(); +} + +KNXValue& KNXValue::operator=(const bool value) +{ + _value.boolValue = value; + _type = BoolType; + return *this; +} + +KNXValue& KNXValue::operator=(const uint8_t value) +{ + _value.ucharValue = value; + _type = UCharType; + return *this; +} + +KNXValue& KNXValue::operator=(const uint16_t value) +{ + _value.ushortValue = value; + _type = UShortType; + return *this; +} + +KNXValue& KNXValue::operator=(const uint32_t value) +{ + _value.uintValue = value; + _type = UIntType; + return *this; +} + +KNXValue& KNXValue::operator=(const uint64_t value) +{ + _value.ulongValue = value; + _type = ULongType; + return *this; +} + +KNXValue& KNXValue::operator=(const int8_t value) +{ + _value.charValue = value; + _type = CharType; + return *this; +} + +KNXValue& KNXValue::operator=(const int16_t value) +{ + _value.shortValue = value; + _type = ShortType; + return *this; +} + +KNXValue& KNXValue::operator=(const int32_t value) +{ + _value.intValue = value; + _type = IntType; + return *this; +} + +KNXValue& KNXValue::operator=(const int64_t value) +{ + _value.longValue = value; + _type = LongType; + return *this; +} + +KNXValue& KNXValue::operator=(const double value) +{ + _value.doubleValue = value; + _type = DoubleType; + return *this; +} + +KNXValue& KNXValue::operator=(const char* value) +{ + _value.stringValue = value; + _type = StringType; + return *this; +} + +KNXValue& KNXValue::operator=(const struct tm value) +{ + _value.timeValue = value; + _type = TimeType; + return *this; +} + +bool KNXValue::boolValue() const +{ + switch (_type) + { + case BoolType: + return _value.boolValue; + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case CharType: + case ShortType: + case IntType: + case LongType: + case TimeType: + return longValue() != 0; + case DoubleType: + return _value.doubleValue != 0; + case StringType: + return strcmp(_value.stringValue, "true") == 0 || strcmp(_value.stringValue, "True") == 0 || longValue() != 0 || doubleValue() != 0; + } + return 0; +} + +uint8_t KNXValue::ucharValue() const +{ + switch (_type) + { + case UCharType: + return _value.ucharValue; + case BoolType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (uint8_t)ulongValue(); + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (uint8_t)longValue(); + } + return 0; +} + +uint16_t KNXValue::ushortValue() const +{ + switch (_type) + { + case UShortType: + return _value.ushortValue; + case BoolType: + case UCharType: + case UIntType: + case ULongType: + case TimeType: + return (uint16_t)ulongValue(); + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (uint16_t)longValue(); + } + return 0; +} + +uint32_t KNXValue::uintValue() const +{ + switch (_type) + { + case UIntType: + return _value.uintValue; + case BoolType: + case UCharType: + case UShortType: + case ULongType: + case TimeType: + return (uint32_t)ulongValue(); + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (uint32_t)longValue(); + } + return 0; +} + +uint64_t KNXValue::ulongValue() const +{ + switch (_type) + { + case ULongType: + return _value.ulongValue; + case BoolType: + return _value.boolValue ? 1 : 0; + case UCharType: + return (uint64_t)_value.ucharValue; + case UShortType: + return (uint64_t)_value.ushortValue; + case UIntType: + return (uint64_t)_value.uintValue; + case TimeType: + { + struct tm* timeptr = const_cast(&_value.timeValue); + return (uint64_t)mktime(timeptr); + } + case CharType: + return (uint64_t)_value.charValue; + case ShortType: + return (uint64_t)_value.shortValue; + case IntType: + return (uint64_t)_value.intValue; + case LongType: + return (uint64_t)_value.longValue; + 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; +} + +int8_t KNXValue::charValue() const +{ + switch (_type) + { + case CharType: + return _value.charValue; + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (int8_t)ulongValue(); + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (int8_t)longValue(); + } + return 0; +} + +int16_t KNXValue::shortValue() const +{ + switch (_type) + { + case ShortType: + return _value.shortValue; + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (int16_t)ulongValue(); + case CharType: + case IntType: + case LongType: + case DoubleType: + case StringType: + return (int16_t)longValue(); + } + return 0; +} + +int32_t KNXValue::intValue() const +{ + switch (_type) + { + case IntType: + return _value.shortValue; + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + return (int32_t)ulongValue(); + case CharType: + case ShortType: + case LongType: + case DoubleType: + case StringType: + return (int32_t)longValue(); + } + return 0; +} + +int64_t KNXValue::longValue() const +{ + switch (_type) + { + case LongType: + return _value.longValue; + case BoolType: + return _value.boolValue ? 1 : 0; + case UCharType: + return (int64_t)_value.ucharValue; + case UShortType: + return (int64_t)_value.ushortValue; + case UIntType: + return (int64_t)_value.uintValue; + case ULongType: + return (int64_t)_value.uintValue; + case TimeType: + return (int64_t)ulongValue(); + case CharType: + return (int64_t)_value.charValue; + case ShortType: + return (int64_t)_value.shortValue; + case IntType: + return (int64_t)_value.intValue; + 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; +} + +double KNXValue::doubleValue() const +{ + switch (_type) + { + case DoubleType: + return _value.doubleValue; + case BoolType: + return _value.boolValue ? 1 : 0; + case UCharType: + return _value.ucharValue; + case UShortType: + return _value.ushortValue; + case UIntType: + return _value.uintValue; + case ULongType: + return _value.uintValue; + case TimeType: + return ulongValue(); + case CharType: + return _value.charValue; + case ShortType: + return _value.shortValue; + case IntType: + return _value.intValue; + case LongType: + return _value.longValue; + case StringType: +#ifndef KNX_NO_STRTOx_CONVERSION + return strtod(_value.stringValue, NULL); +#else + return 0; +#endif + } + return 0; +} + +const char* KNXValue::stringValue() const +{ + switch (_type) + { + case DoubleType: + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case TimeType: + case CharType: + case ShortType: + case IntType: + case LongType: + return ""; // we would have to manage the memory for the string otherwise. Maybe later. + case StringType: + return _value.stringValue; + } + return 0; +} + +struct tm KNXValue::timeValue() const +{ + switch (_type) + { + case TimeType: + return _value.timeValue; + case BoolType: + case UCharType: + case UShortType: + case UIntType: + case ULongType: + case CharType: + case ShortType: + case IntType: + case LongType: + case DoubleType: + case StringType: + { + time_t timeVal = ulongValue(); + struct tm timeStruct; + gmtime_r(&timeVal, &timeStruct); + return timeStruct; + } + } + struct tm tmp = {0}; + return tmp; +} + +KNXValue::KNXValue(float value) +{ + _value.doubleValue = value; + _type = DoubleType; +} + +KNXValue& KNXValue::operator=(const float value) +{ + _value.doubleValue = value; + _type = DoubleType; + return *this; +} + +KNXValue::operator float() const +{ + return doubleValue(); } \ No newline at end of file diff --git a/src/knx_facade.cpp b/src/knx_facade.cpp index 1dee9fc..8fa35ad 100644 --- a/src/knx_facade.cpp +++ b/src/knx_facade.cpp @@ -41,7 +41,21 @@ } #endif - #ifdef ARDUINO_ARCH_SAMD + #ifdef __SAMD51__ + // predefined global instance for TP or RF + #if MASK_VERSION == 0x07B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x27B0 + KnxFacade knx(buttonEvent); + #elif MASK_VERSION == 0x57B0 + KnxFacade knx(buttonEvent); + #else + #error "Mask version not supported on SAMD51" + #endif + #elif (defined(__SAMD21E17A__) || \ + defined(__SAMD21G18A__) || \ + defined(__SAMD21E18A__) || \ + defined(__SAMD21J18A__)) // predefined global instance for TP or RF or TP/RF coupler #if MASK_VERSION == 0x07B0 KnxFacade knx(buttonEvent); @@ -50,7 +64,7 @@ #elif MASK_VERSION == 0x2920 KnxFacade knx(buttonEvent); #else - #error "Mask version not supported on ARDUINO_ARCH_SAMD" + #error "Mask version not supported on SAMD21" #endif #elif defined(ARDUINO_ARCH_RP2040) // predefined global instance for TP or RF or TP/RF coupler @@ -98,4 +112,4 @@ // no predefined global instance #endif -#endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE +#endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE \ No newline at end of file diff --git a/src/knx_facade.h b/src/knx_facade.h index 7facf61..089e4d9 100644 --- a/src/knx_facade.h +++ b/src/knx_facade.h @@ -12,7 +12,15 @@ #define USERDATA_SAVE_SIZE 0 #endif -#ifdef ARDUINO_ARCH_SAMD +#ifdef __SAMD51__ + #include "samd51_platform.h" + #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE + void buttonUp(); + #endif +#elif (defined(__SAMD21E17A__) || \ + defined(__SAMD21G18A__) || \ + defined(__SAMD21E18A__) || \ + defined(__SAMD21J18A__)) #include "samd_platform.h" #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE void buttonUp(); @@ -468,7 +476,21 @@ template class KnxFacade : private SaveRestore }; #ifndef KNX_NO_AUTOMATIC_GLOBAL_INSTANCE - #ifdef ARDUINO_ARCH_SAMD + #ifdef __SAMD51__ + // predefined global instance for TP or RF + #if MASK_VERSION == 0x07B0 + extern KnxFacade knx; + #elif MASK_VERSION == 0x27B0 + extern KnxFacade knx; + #elif MASK_VERSION == 0x57B0 + extern KnxFacade knx; + #else + #error "Mask version not supported on SAMD51" + #endif + #elif (defined(__SAMD21E17A__) || \ + defined(__SAMD21G18A__) || \ + defined(__SAMD21E18A__) || \ + defined(__SAMD21J18A__)) // predefined global instance for TP or RF or TP/RF coupler #if MASK_VERSION == 0x07B0 extern KnxFacade knx; @@ -477,7 +499,7 @@ template class KnxFacade : private SaveRestore #elif MASK_VERSION == 0x2920 extern KnxFacade knx; #else - #error "Mask version not supported on ARDUINO_ARCH_SAMD" + #error "Mask version not supported on SAMD21" #endif #elif defined(ARDUINO_ARCH_RP2040) // predefined global instance for TP or RF or TP/RF coupler @@ -522,4 +544,4 @@ template class KnxFacade : private SaveRestore #else // Non-Arduino platforms and Linux platform // no predefined global instance #endif -#endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE +#endif // KNX_NO_AUTOMATIC_GLOBAL_INSTANCE \ No newline at end of file diff --git a/src/samd51_platform.cpp b/src/samd51_platform.cpp new file mode 100644 index 0000000..f2ad8bf --- /dev/null +++ b/src/samd51_platform.cpp @@ -0,0 +1,338 @@ +#include "samd51_platform.h" + +#ifdef __SAMD51__ + +#include +#include + +#if KNX_FLASH_SIZE % 1024 +#error "KNX_FLASH_SIZE must be multiple of 1024" +#endif + +#ifndef KNX_SERIAL +#define KNX_SERIAL Serial1 +#endif + +Samd51Platform::Samd51Platform() +#ifndef KNX_NO_DEFAULT_UART + : ArduinoPlatform(&KNX_SERIAL) +#endif +{ + init(); +} + +Samd51Platform::Samd51Platform( HardwareSerial* s) : ArduinoPlatform(s) +{ + init(); +} + +uint32_t Samd51Platform::uniqueSerialNumber() +{ + // 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) + + return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3; +} + +void Samd51Platform::restart() +{ + println("restart"); + NVIC_SystemReset(); +} + +#if USE_W5X00 == 1 + + uint32_t Samd51Platform::currentIpAddress() + { + // IPAddress _ip = Ethernet.localIP(); + // _ipAddress = htonl(_ip); + // return _ipAddress; + + return Ethernet.localIP(); + + // _ipAddress = 0x0A063232; + // return _ipAddress; + + // return 0x0A063232; + } + + uint32_t Samd51Platform::currentSubnetMask() + { + // IPAddress _nm = Ethernet.subnetMask(); + // _netmask = htonl(_nm); + // return _netmask; + + return Ethernet.subnetMask(); + + // _netmask = 0xFFFFFF00; + // return _netmask; + + // return 0xFFFFFF00; + } + + uint32_t Samd51Platform::currentDefaultGateway() + { + // IPAddress _gw = Ethernet.gatewayIP(); + // _defaultGateway = htonl(_gw); + // return _defaultGateway; + + return Ethernet.gatewayIP(); + + // _defaultGateway = 0x0A063201; + // return _defaultGateway; + + // return 0x0A063201; + } + + void Samd51Platform::macAddress(uint8_t * mac_address) + { + //Ethernet.macAddress(mac_address); //try this first, not sure if this will work, is for ethernet3 lib + memcpy(mac_address, _macAddress, sizeof(_macAddress) / sizeof(_macAddress[0])); //sizeof should resolve to be just 6 + } + + void Samd51Platform::setupMultiCast(uint32_t addr, uint16_t port) + { + IPAddress _mcastaddr(htonl(addr)); + + KNX_DEBUG_SERIAL.printf("setup multicast on %d.%d.%d.%d:%d\n", _mcastaddr[0], _mcastaddr[1], _mcastaddr[2], _mcastaddr[3], port); + uint8_t result = _udp.beginMulticast(_multicastAddr, _multicastPort); + KNX_DEBUG_SERIAL.printf("result %d\n", result); + } + + void Samd51Platform::closeMultiCast() + { + _udp.stop(); + } + + bool Samd51Platform::sendBytesMultiCast(uint8_t * buffer, uint16_t len) + { + //printHex("<- ",buffer, len); + _udp.beginPacket(_multicastAddr, _multicastPort); + _udp.write(buffer, len); + _udp.endPacket(); + return true; + } + + int Samd51Platform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen) + { + int len = _udp.parsePacket(); + if (len == 0) + return 0; + + if (len > maxLen) + { + KNX_DEBUG_SERIAL.printf("udp buffer to small. was %d, needed %d\n", maxLen, len); + fatalError(); + } + + _udp.read(buffer, len); + printHex("-> ", buffer, len); + return len; + } + + bool Samd51Platform::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; + } + +#endif + +extern uint32_t __etext; +extern uint32_t __data_start__; +extern uint32_t __data_end__; + +static const uint32_t pageSizes[] = {8, 16, 32, 64, 128, 256, 512, 1024}; + +void Samd51Platform::init() +{ + // println("Entered Init .h variables active, rest and .cpp commented"); + + // #if USE_W5X00 == 1 + // IPAddress _ip = Ethernet.localIP(); + // _ipAddress = htonl(_ip); + // _ip = Ethernet.subnetMask(); + // _netmask = htonl(_ip); + // _ip = Ethernet.gatewayIP(); + // _defaultGateway = htonl(_ip); + // #endif + + _memoryType = Flash; + _pageSize = pageSizes[NVMCTRL->PARAM.bit.PSZ]; + _pageCnt = NVMCTRL->PARAM.bit.NVMP; + _rowSize = (_pageSize * _pageCnt / 64); + + //find end of program flash and set limit to next row + uint32_t endEddr = (uint32_t)(&__etext + (&__data_end__ - &__data_start__)); // text + data MemoryBlock + _MemoryStart = getRowAddr(_pageSize * _pageCnt - KNX_FLASH_SIZE - 1); // 23295 + _MemoryEnd = getRowAddr(_pageSize * _pageCnt - 1); + //chosen flash size is not available anymore + if (_MemoryStart < endEddr) { + println("KNX_FLASH_SIZE is not available (possible too much flash use by firmware)"); + fatalError(); + } +} + +// Invalidate all CMCC cache entries if CMCC cache is enabled. +static void invalidate_CMCC_cache() +{ + if (CMCC->SR.bit.CSTS) { + CMCC->CTRL.bit.CEN = 0; + while (CMCC->SR.bit.CSTS) {} + CMCC->MAINT0.bit.INVALL = 1; + CMCC->CTRL.bit.CEN = 1; + } +} + +static inline uint32_t read_unaligned_uint32(volatile void *data) +{ + union { + uint32_t u32; + uint8_t u8[4]; + } res; + const uint8_t *d = (const uint8_t *)data; + res.u8[0] = d[0]; + res.u8[1] = d[1]; + res.u8[2] = d[2]; + res.u8[3] = d[3]; + return res.u32; +} + +size_t Samd51Platform::flashEraseBlockSize() +{ + return (_pageSize / 64); //PAGES_PER_ROW; +} + +size_t Samd51Platform::flashPageSize() +{ + return _pageSize; +} + +uint8_t* Samd51Platform::userFlashStart() +{ + return (uint8_t*)_MemoryStart; +} + +size_t Samd51Platform::userFlashSizeEraseBlocks() +{ + if (KNX_FLASH_SIZE <= 0) + return 0; + else + return ((KNX_FLASH_SIZE - 1) / (flashPageSize() * flashEraseBlockSize())) + 1; +} + +void Samd51Platform::flashErase(uint16_t eraseBlockNum) +{ + noInterrupts(); + + eraseRow((void *)(_MemoryStart + eraseBlockNum * _rowSize)); + // flash_range_erase(KNX_FLASH_OFFSET + eraseBlockNum * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + + interrupts(); +} + +void Samd51Platform::flashWritePage(uint16_t pageNumber, uint8_t* data) +{ + noInterrupts(); + + write((void *)(_MemoryStart + pageNumber * _pageSize), data, _pageSize); + // flash_range_program(KNX_FLASH_OFFSET + pageNumber * flashPageSize(), data, flashPageSize()); + + interrupts(); +} + +void Samd51Platform::writeBufferedEraseBlock() +{ + if (_bufferedEraseblockNumber > -1 && _bufferedEraseblockDirty) + { + noInterrupts(); + + eraseRow((void *)(_MemoryStart + _bufferedEraseblockNumber * _rowSize)); + write((void *)(_MemoryStart + _bufferedEraseblockNumber * _rowSize), _eraseblockBuffer, _rowSize); + // flash_range_erase(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), flashPageSize() * flashEraseBlockSize()); + // flash_range_program(KNX_FLASH_OFFSET + _bufferedEraseblockNumber * flashPageSize() * flashEraseBlockSize(), _eraseblockBuffer, flashPageSize() * flashEraseBlockSize()); + + interrupts(); + + _bufferedEraseblockDirty = false; + } +} + +uint32_t Samd51Platform::getRowAddr(uint32_t flasAddr) +{ + return flasAddr & ~(_rowSize - 1); +} + +void Samd51Platform::write(const volatile void *flash_ptr, const void *data, uint32_t size) +{ + // Calculate data boundaries + size = (size + 3) / 4; + volatile uint32_t *src_addr = (volatile uint32_t *)data; + volatile uint32_t *dst_addr = (volatile uint32_t *)flash_ptr; + + // Disable automatic page write + NVMCTRL->CTRLA.bit.WMODE = 0; + while (NVMCTRL->STATUS.bit.READY == 0) { } + // Disable NVMCTRL cache while writing, per SAMD51 errata. + bool original_CACHEDIS0 = NVMCTRL->CTRLA.bit.CACHEDIS0; + bool original_CACHEDIS1 = NVMCTRL->CTRLA.bit.CACHEDIS1; + NVMCTRL->CTRLA.bit.CACHEDIS0 = true; + NVMCTRL->CTRLA.bit.CACHEDIS1 = true; + + // Do writes in pages + while (size) + { + // Execute "PBC" Page Buffer Clear + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_PBC; + while (NVMCTRL->INTFLAG.bit.DONE == 0) { } + + // Fill page buffer + uint32_t i; + for (i = 0; i < (_pageSize / 4) && size; i++) + { + *dst_addr = read_unaligned_uint32(src_addr); + src_addr += 4; + dst_addr++; + size--; + } + + // Execute "WP" Write Page + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_WP; + while (NVMCTRL->INTFLAG.bit.DONE == 0) { } + invalidate_CMCC_cache(); + // Restore original NVMCTRL cache settings. + NVMCTRL->CTRLA.bit.CACHEDIS0 = original_CACHEDIS0; + NVMCTRL->CTRLA.bit.CACHEDIS1 = original_CACHEDIS1; + } +} + +void Samd51Platform::erase(const volatile void *flash_ptr, uint32_t size) +{ + const uint8_t *ptr = (const uint8_t *)flash_ptr; + while (size > _rowSize) + { + eraseRow(ptr); + ptr += _rowSize; + size -= _rowSize; + } + eraseRow(ptr); +} + +void Samd51Platform::eraseRow(const volatile void *flash_ptr) +{ + NVMCTRL->ADDR.reg = ((uint32_t)flash_ptr); + NVMCTRL->CTRLB.reg = NVMCTRL_CTRLB_CMDEX_KEY | NVMCTRL_CTRLB_CMD_EB; + while (!NVMCTRL->INTFLAG.bit.DONE) { } + invalidate_CMCC_cache(); +} + +#endif diff --git a/src/samd51_platform.h b/src/samd51_platform.h new file mode 100644 index 0000000..5a58268 --- /dev/null +++ b/src/samd51_platform.h @@ -0,0 +1,77 @@ +#include +#include "arduino_platform.h" +#include +#include +#include + +#ifdef __SAMD51__ + +class Samd51Platform : public ArduinoPlatform +{ +public: + Samd51Platform(); + Samd51Platform( HardwareSerial* s); + + // unique serial number + uint32_t uniqueSerialNumber() override; + + void restart(); + + #if USE_W5X00 == 1 + // ip config + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* data) override; + + //multicast + void setupMultiCast(uint32_t addr, uint16_t port) override; + void closeMultiCast() override; + bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; + int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; + + bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len) override; + #endif + + // size of one EraseBlock in pages + virtual size_t flashEraseBlockSize(); + // size of one flash page in bytes + virtual size_t flashPageSize(); + // start of user flash aligned to start of an erase block + virtual uint8_t* userFlashStart(); + // size of the user flash in EraseBlocks + virtual size_t userFlashSizeEraseBlocks(); + // relativ to userFlashStart + virtual void flashErase(uint16_t eraseBlockNum); + // write a single page to flash (pageNumber relative to userFashStart + virtual void flashWritePage(uint16_t pageNumber, uint8_t* data); + + // writes _eraseblockBuffer to flash - overrides Plattform::writeBufferedEraseBlock() for performance optimization only + void writeBufferedEraseBlock(); + +private: + void init(); + uint32_t _MemoryEnd = 0; + uint32_t _MemoryStart = 0; + uint32_t _pageSize; + uint32_t _rowSize; + uint32_t _pageCnt; + + uint32_t getRowAddr(uint32_t flasAddr); + void write(const volatile void* flash_ptr, const void* data, uint32_t size); + void erase(const volatile void* flash_ptr, uint32_t size); + void eraseRow(const volatile void* flash_ptr); + + #if USE_W5X00 == 1 + uint8_t _macAddress[6] = {0xC0, 0xFF, 0xEE, 0xC0, 0xDE, 0x00}; + uint32_t _ipAddress = 0; + uint32_t _netmask = 0; + uint32_t _defaultGateway = 0; + + uint32_t _multicastAddr = -1; + uint16_t _multicastPort = -1; + EthernetUDP _udp; + #endif +}; + +#endif diff --git a/src/samd_platform.cpp b/src/samd_platform.cpp index 49b9ec4..fa7dab4 100644 --- a/src/samd_platform.cpp +++ b/src/samd_platform.cpp @@ -1,6 +1,10 @@ #include "samd_platform.h" -#ifdef ARDUINO_ARCH_SAMD +#if(defined(__SAMD21E17A__) || \ + defined(__SAMD21G18A__) || \ + defined(__SAMD21E18A__) || \ + defined(__SAMD21J18A__)) + #include #include @@ -35,21 +39,11 @@ 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 - + #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) + return SERIAL_NUMBER_WORD_0 ^ SERIAL_NUMBER_WORD_1 ^ SERIAL_NUMBER_WORD_2 ^ SERIAL_NUMBER_WORD_3; } diff --git a/src/samd_platform.h b/src/samd_platform.h index 948a5d8..52d150a 100644 --- a/src/samd_platform.h +++ b/src/samd_platform.h @@ -2,7 +2,10 @@ #include "Arduino.h" -#ifdef ARDUINO_ARCH_SAMD +#if (defined(__SAMD21E17A__) || \ + defined(__SAMD21G18A__) || \ + defined(__SAMD21E18A__) || \ + defined(__SAMD21J18A__)) #define PAGES_PER_ROW 4