diff --git a/MyASM.S b/MyASM.S index 22763eb5..7bfff35c 100644 --- a/MyASM.S +++ b/MyASM.S @@ -24,15 +24,15 @@ doNothing: nop .size doNothing, .-doNothing - + #elif defined(ARDUINO_ARCH_NRF5) /* workaround to prevent compiler error */ .thumb_func doNothing: nop .size doNothing, .-doNothing - -#elif defined(ARDUINO_ARCH_AVR) + +#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) #include "hal/crypto/AVR/drivers/SHA256/SHA256.S" diff --git a/MyConfig.h b/MyConfig.h index 4f6de24f..4c509c71 100755 --- a/MyConfig.h +++ b/MyConfig.h @@ -2607,6 +2607,12 @@ */ #define ARDUINO_ARCH_AVR +/** + * @def ARDUINO_ARCH_MEGAAVR + * @brief Automatically set when building for megaAVR targets + */ +#define ARDUINO_ARCH_MEGAAVR + /** * @def ARDUINO_ARCH_STM32F1 * @brief Automatically set when building for STM32F1 targets @@ -2778,5 +2784,12 @@ #define MY_SX126x_MAX_POWER_LEVEL_DBM // SOFT-SPI #define MY_SOFTSPI + +/** + * @def MY_ROUTES_SIZE + * @brief Specifies the size allocated for routing table + */ +#define MY_ROUTES_SIZE + #endif /** @}*/ // End of MyConfig group diff --git a/MySensors.h b/MySensors.h index 9f877678..ec01be34 100644 --- a/MySensors.h +++ b/MySensors.h @@ -63,6 +63,9 @@ #elif defined(ARDUINO_ARCH_AVR) #include "hal/architecture/AVR/MyHwAVR.cpp" #include "hal/crypto/AVR/MyCryptoAVR.cpp" +#elif defined(ARDUINO_ARCH_MEGAAVR) +#include "hal/architecture/AVR/MyHwMegaAVR.cpp" +#include "hal/crypto/AVR/MyCryptoAVR.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "drivers/extEEPROM/extEEPROM.cpp" #include "hal/architecture/SAMD/MyHwSAMD.cpp" @@ -335,8 +338,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs // activate feature based on architecture #if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32) || defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_NRF5) || defined(ARDUINO_ARCH_STM32F1) || defined(TEENSYDUINO) || defined(__linux__) || defined(__ASR6501__) || defined (__ASR6502__) #define MY_RAM_ROUTING_TABLE_ENABLED -#elif defined(ARDUINO_ARCH_AVR) -#if defined(__avr_atmega1280__) || defined(__avr_atmega1284__) || defined(__avr_atmega2560__) +#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) +#if defined(__avr_atmega1280__) || defined(__avr_atmega1284__) || defined(__avr_atmega2560__) || defined(__avr_attiny3224__) || defined(__avr_attiny3227__) // >4kb, enable it #define MY_RAM_ROUTING_TABLE_ENABLED #else @@ -457,6 +460,8 @@ MY_DEFAULT_RX_LED_PIN in your sketch instead to enable LEDs // HW mains #if defined(ARDUINO_ARCH_AVR) #include "hal/architecture/AVR/MyMainAVR.cpp" +#elif defined(ARDUINO_ARCH_MEGAAVR) +#include "hal/architecture/AVR/MyMainAVR.cpp" #elif defined(ARDUINO_ARCH_SAMD) #include "hal/architecture/SAMD/MyMainSAMD.cpp" #elif defined(ARDUINO_ARCH_ESP8266) diff --git a/core/MyCapabilities.h b/core/MyCapabilities.h index 50030ef8..44d76900 100644 --- a/core/MyCapabilities.h +++ b/core/MyCapabilities.h @@ -163,7 +163,7 @@ #define MY_CAP_ARCH "E" #elif defined(ARDUINO_ARCH_ESP32) #define MY_CAP_ARCH "F" -#elif defined(ARDUINO_ARCH_AVR) +#elif defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) #define MY_CAP_ARCH "A" #elif defined(ARDUINO_ARCH_STM32F1) #define MY_CAP_ARCH "M" diff --git a/core/MyEepromAddresses.h b/core/MyEepromAddresses.h index 91b60dcd..621ed313 100644 --- a/core/MyEepromAddresses.h +++ b/core/MyEepromAddresses.h @@ -32,22 +32,26 @@ #define MyEepromAddresses_h // EEPROM variable sizes, in bytes -#define SIZE_NODE_ID (1u) //!< Size node ID -#define SIZE_PARENT_NODE_ID (1u) //!< Size parent node ID -#define SIZE_DISTANCE (1u) //!< Size GW distance -#define SIZE_ROUTES (256u) //!< Size routing table -#define SIZE_CONTROLLER_CONFIG (23u) //!< Size controller config -#define SIZE_PERSONALIZATION_CHECKSUM (1u) //!< Size personalization checksum -#define SIZE_FIRMWARE_TYPE (2u) //!< Size firmware type -#define SIZE_FIRMWARE_VERSION (2u) //!< Size firmware version -#define SIZE_FIRMWARE_BLOCKS (2u) //!< Size firmware blocks -#define SIZE_FIRMWARE_CRC (2u) //!< Size firmware CRC +#define SIZE_NODE_ID (1u) //!< Size node ID +#define SIZE_PARENT_NODE_ID (1u) //!< Size parent node ID +#define SIZE_DISTANCE (1u) //!< Size GW distance +#ifdef MY_ROUTES_SIZE +#define SIZE_ROUTES (MY_ROUTES_SIZE) //!< Size routing table 148 is the +#else +#define SIZE_ROUTES (256u) //!< Size routing table 148 is the +#endif +#define SIZE_CONTROLLER_CONFIG (23u) //!< Size controller config +#define SIZE_PERSONALIZATION_CHECKSUM (1u) //!< Size personalization checksum +#define SIZE_FIRMWARE_TYPE (2u) //!< Size firmware type +#define SIZE_FIRMWARE_VERSION (2u) //!< Size firmware version +#define SIZE_FIRMWARE_BLOCKS (2u) //!< Size firmware blocks +#define SIZE_FIRMWARE_CRC (2u) //!< Size firmware CRC #define SIZE_SIGNING_REQUIREMENT_TABLE (32u) //!< Size signing requirement table #define SIZE_WHITELIST_REQUIREMENT_TABLE (32u) //!< Size whitelist requirement table -#define SIZE_SIGNING_SOFT_HMAC_KEY (32u) //!< Size soft signing HMAC key -#define SIZE_SIGNING_SOFT_SERIAL (9u) //!< Size soft signing serial -#define SIZE_RF_ENCRYPTION_AES_KEY (16u) //!< Size RF AES encryption key -#define SIZE_NODE_LOCK_COUNTER (1u) //!< Size node lock counter +#define SIZE_SIGNING_SOFT_HMAC_KEY (32u) //!< Size soft signing HMAC key +#define SIZE_SIGNING_SOFT_SERIAL (9u) //!< Size soft signing serial +#define SIZE_RF_ENCRYPTION_AES_KEY (16u) //!< Size RF AES encryption key +#define SIZE_NODE_LOCK_COUNTER (1u) //!< Size node lock counter /** @brief EEPROM start address */ diff --git a/drivers/ATSHA204/ATSHA204.cpp b/drivers/ATSHA204/ATSHA204.cpp index 84a0d6bc..a634fbf7 100644 --- a/drivers/ATSHA204/ATSHA204.cpp +++ b/drivers/ATSHA204/ATSHA204.cpp @@ -4,7 +4,7 @@ /* Local data and function prototypes */ static uint8_t device_pin; -#ifdef ARDUINO_ARCH_AVR +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) static volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; #endif static void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); @@ -416,7 +416,7 @@ static uint8_t sha204c_check_crc(uint8_t *response) void atsha204_init(uint8_t pin) { -#if defined(ARDUINO_ARCH_AVR) +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers diff --git a/drivers/ATSHA204/ATSHA204.h b/drivers/ATSHA204/ATSHA204.h index be27d5a7..ee88c9a1 100644 --- a/drivers/ATSHA204/ATSHA204.h +++ b/drivers/ATSHA204/ATSHA204.h @@ -225,7 +225,7 @@ /* Low level HW access macros */ /* function calls is not working, as it will have too much overhead */ -#if !defined(ARDUINO_ARCH_AVR) // For everything else than AVR use pinMode / digitalWrite +#if !defined(ARDUINO_ARCH_AVR) && !defined(ARDUINO_ARCH_MEGAAVR) // For everything else than AVR use pinMode / digitalWrite #define SHA204_SET_OUTPUT() pinMode(device_pin, OUTPUT) #define SHA204_SET_INPUT() pinMode(device_pin, INPUT) #define SHA204_POUT_HIGH() digitalWrite(device_pin, HIGH) diff --git a/examples/SecurityPersonalizer/SecurityPersonalizer.ino b/examples/SecurityPersonalizer/SecurityPersonalizer.ino index 87a802aa..2a07d0e0 100644 --- a/examples/SecurityPersonalizer/SecurityPersonalizer.ino +++ b/examples/SecurityPersonalizer/SecurityPersonalizer.ino @@ -1343,6 +1343,8 @@ static void probe_and_print_peripherals(void) F("+--------------+--------------+--------------+------------------------------+--------+")); #if defined(ARDUINO_ARCH_AVR) Serial.print(F("| AVR | DETECTED | N/A | ")); +#elif defined(ARDUINO_ARCH_MEGAAVR) + Serial.print(F("| megaAVR | DETECTED | N/A | ")); #elif defined(ARDUINO_ARCH_ESP8266) Serial.print(F("| ESP8266 | DETECTED | N/A | ")); #elif defined(ARDUINO_ARCH_SAMD) @@ -1869,4 +1871,4 @@ static void dump_detailed_atsha204a_configuration(void) #define RESET_EEPROM_PERSONALIZATION #endif -/** @}*/ \ No newline at end of file +/** @}*/ diff --git a/examples/SecurityPersonalizer/sha204_library.cpp b/examples/SecurityPersonalizer/sha204_library.cpp index 866f5136..0d44cc1b 100644 --- a/examples/SecurityPersonalizer/sha204_library.cpp +++ b/examples/SecurityPersonalizer/sha204_library.cpp @@ -11,7 +11,7 @@ atsha204Class::atsha204Class(uint8_t pin) { -#if defined(ARDUINO_ARCH_AVR) +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) device_pin = digitalPinToBitMask(pin); // Find the bit value of the pin uint8_t port = digitalPinToPort(pin); // temoporarily used to get the next three registers diff --git a/examples/SecurityPersonalizer/sha204_library.h b/examples/SecurityPersonalizer/sha204_library.h index 349d39cc..ef2e3af2 100644 --- a/examples/SecurityPersonalizer/sha204_library.h +++ b/examples/SecurityPersonalizer/sha204_library.h @@ -283,7 +283,7 @@ /* Low level HW access macros */ /* function calls is not working, as it will have too much overhead */ -#if !defined(ARDUINO_ARCH_AVR) // For everything else than AVR use pinMode / digitalWrite +#if !defined(ARDUINO_ARCH_AVR) && !defined(ARDUINO_ARCH_MEGAAVR) // For everything else than AVR use pinMode / digitalWrite #define SHA204_SET_OUTPUT() pinMode(device_pin, OUTPUT) #define SHA204_SET_INPUT() pinMode(device_pin, INPUT) #define SHA204_POUT_HIGH() digitalWrite(device_pin, HIGH) @@ -304,7 +304,7 @@ class atsha204Class { private: uint8_t device_pin; -#ifdef ARDUINO_ARCH_AVR +#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR) volatile uint8_t *device_port_DDR, *device_port_OUT, *device_port_IN; #endif void sha204c_calculate_crc(uint8_t length, uint8_t *data, uint8_t *crc); diff --git a/hal/architecture/AVR/MyHwMegaAVR.cpp b/hal/architecture/AVR/MyHwMegaAVR.cpp new file mode 100644 index 00000000..58659b1b --- /dev/null +++ b/hal/architecture/AVR/MyHwMegaAVR.cpp @@ -0,0 +1,432 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2022 Sensnology AB + * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#include "MyHwMegaAVR.h" + +void hwRtcInit(void) +{ + // Initialize RTC to 1kHz internal oscillator + while (RTC.STATUS > 0) { } /* Wait for all register to be synchronized */ + + RTC.CTRLA = RTC_PRESCALER_DIV32768_gc /* 32768 */ + | 0 << RTC_RTCEN_bp /* Enable: disabled */ + | 0 << RTC_RUNSTDBY_bp; /* Run In Standby: disabled */ + + RTC.CLKSEL = RTC_CLKSEL_INT1K_gc; /* 32KHz divided by 32 */ +} + +bool hwInit(void) +{ + hwRtcInit(); +#if !defined(MY_DISABLED_SERIAL) + MY_SERIALDEVICE.begin(MY_BAUD_RATE); +#if defined(MY_GATEWAY_SERIAL) + while (!MY_SERIALDEVICE) {} +#endif +#endif + return true; +} + +#define PIT_SLEEP_FOREVER 0 + +volatile uint8_t _wokeUpByInterrupt = + INVALID_INTERRUPT_NUM; // Interrupt number that woke the mcu. +volatile uint8_t _wakeUp1Interrupt = + INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp1-callback. +volatile uint8_t _wakeUp2Interrupt = + INVALID_INTERRUPT_NUM; // Interrupt number for wakeUp2-callback. + +static uint32_t sleepRemainingMs = 0ul; + +void wakeUp1(void) +{ + // Disable sleep. When an interrupt occurs after attachInterrupt, + // but before sleeping the CPU would not wake up. + // Ref: http://playground.arduino.cc/Learning/ArduinoSleepCode + sleep_disable(); + detachInterrupt(_wakeUp1Interrupt); + // First interrupt occurred will be reported only + if (INVALID_INTERRUPT_NUM == _wokeUpByInterrupt) { + _wokeUpByInterrupt = _wakeUp1Interrupt; + } +} +void wakeUp2(void) +{ + sleep_disable(); + detachInterrupt(_wakeUp2Interrupt); + // First interrupt occurred will be reported only + if (INVALID_INTERRUPT_NUM == _wokeUpByInterrupt) { + _wokeUpByInterrupt = _wakeUp2Interrupt; + } +} + +inline bool interruptWakeUp(void) +{ + return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM; +} + +void clearPendingInterrupt(const uint8_t interrupt) +{ + // TODO: Check do I need that + //EIFR = _BV(interrupt); +} + +void pit_reset() +{ + RTC.PITCTRLA = 0; + RTC.PITINTCTRL = 0; +} + +void hwPitRtcInit(uint8_t cycles) +{ + while (RTC.PITSTATUS > 0) { }/* Wait for all register to be synchronized */ + + /* + RTC_PERIOD_CYC16_gc = (0x03<<3), /* RTC Clock Cycles 16 + RTC_PERIOD_CYC32_gc = (0x04<<3), /* RTC Clock Cycles 32 + RTC_PERIOD_CYC64_gc = (0x05<<3), /* RTC Clock Cycles 64 + RTC_PERIOD_CYC128_gc = (0x06<<3), /* RTC Clock Cycles 128 + RTC_PERIOD_CYC256_gc = (0x07<<3), /* RTC Clock Cycles 256 + RTC_PERIOD_CYC512_gc = (0x08<<3), /* RTC Clock Cycles 512 + RTC_PERIOD_CYC1024_gc = (0x09<<3), /* RTC Clock Cycles 1024 + RTC_PERIOD_CYC2048_gc = (0x0A<<3), /* RTC Clock Cycles 2048 + RTC_PERIOD_CYC4096_gc = (0x0B<<3), /* RTC Clock Cycles 4096 + RTC_PERIOD_CYC8192_gc = (0x0C<<3), /* RTC Clock Cycles 8192 + RTC_PERIOD_CYC16384_gc = (0x0D<<3), /* RTC Clock Cycles 16384 + RTC_PERIOD_CYC32768_gc = (0x0E<<3), /* RTC Clock Cycles 32768 + */ + RTC.PITCTRLA = cycles + | 1 << RTC_PITEN_bp; /* Enable: enabled */ + + RTC.PITINTCTRL = 1 << RTC_PI_bp; /* Periodic Interrupt: enabled */ +} + +uint8_t getSleepingPeriod(uint32_t ms) +{ + for (uint8_t period = 14u; period > 2; --period) { + const uint16_t comparatorMS = (32768 >> (15 - period)); + if (ms >= comparatorMS) { + return period; + } + } + + return 3; // 16ms with 1kHz internal oscillator +} + +uint32_t hwPowerDown(uint32_t ms) +{ + // Let serial prints finish (debug, log etc) +#ifndef MY_DISABLED_SERIAL + MY_SERIALDEVICE.flush(); +#endif + if (_beforeSleep) { + _beforeSleep(); + } + ADC0.CTRLA &= ~ADC_ENABLE_bm; // ADC off + + if (ms != PIT_SLEEP_FOREVER) { + + // Sleeping with watchdog only supports multiples of 16ms. + // Round up to next multiple of 16ms, to assure we sleep at least the + // requested amount of time. Sleep of 0ms will not sleep at all! + ms += 15u; + + while (!interruptWakeUp() && ms >= 16) { + uint8_t period = getSleepingPeriod(ms); + const uint16_t comparatorMS = 32768 >> (15 - period); + + cli(); + hwPitRtcInit(period << 3); + sei(); + + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_enable(); + sleep_cpu(); + sleep_disable(); + + cli(); + RTC.PITCTRLA = 0; /* RTC Clock Cycles Off, Enable: disabled */ + sei(); + + ms -= comparatorMS; + } + } else { + // Eternal sleep + set_sleep_mode(SLEEP_MODE_PWR_DOWN); + sleep_enable(); + sleep_cpu(); + sleep_disable(); + + sei(); + } + + ADC0.CTRLA |= ADC_ENABLE_bm; // ADC on + + if (_afterSleep) { + _afterSleep(); + } + + if (interruptWakeUp()) { + return ms; + } + return 0ul; +} + +ISR (RTC_PIT_vect) +{ + RTC.PITINTFLAGS = 1; // Clear interrupt flag +} + +int8_t hwSleep(uint32_t ms) +{ + // Return what woke the mcu. + // Default: no interrupt triggered, timer wake up + int8_t ret = MY_WAKE_UP_BY_TIMER; + sleepRemainingMs = 0ul; + if (ms > 0u) { + // sleep for defined time + sleepRemainingMs = hwPowerDown(ms); + } else { + // sleep until ext interrupt triggered + hwPowerDown(PIT_SLEEP_FOREVER); + } + if (interruptWakeUp()) { + ret = static_cast(_wokeUpByInterrupt); + } + // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. + _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; + + return ret; +} + +int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms) +{ + return hwSleep(interrupt, mode, INVALID_INTERRUPT_NUM, 0u, ms); +} + +int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2, + const uint8_t mode2, + uint32_t ms) +{ + // ATMega328P supports following modes to wake from sleep: LOW, CHANGE, RISING, FALLING + // Datasheet states only LOW can be used with INT0/1 to wake from sleep, which is incorrect. + // Ref: http://gammon.com.au/interrupts + + // Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt() + // and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled! + cli(); + // attach interrupts + _wakeUp1Interrupt = interrupt1; + _wakeUp2Interrupt = interrupt2; + + // Attach external interrupt handlers, and clear any pending interrupt flag + // to prevent waking immediately again. + // Ref: https://forum.arduino.cc/index.php?topic=59217.0 + if (interrupt1 != INVALID_INTERRUPT_NUM) { + clearPendingInterrupt(interrupt1); + attachInterrupt(interrupt1, wakeUp1, mode1); + } + if (interrupt2 != INVALID_INTERRUPT_NUM) { + clearPendingInterrupt(interrupt2); + attachInterrupt(interrupt2, wakeUp2, mode2); + } + + sleepRemainingMs = 0ul; + if (ms > 0u) { + // sleep for defined time + sleepRemainingMs = hwPowerDown(ms); + } else { + // sleep until ext interrupt triggered + hwPowerDown(PIT_SLEEP_FOREVER); + } + + // Assure any interrupts attached, will get detached when they did not occur. + if (interrupt1 != INVALID_INTERRUPT_NUM) { + detachInterrupt(interrupt1); + } + if (interrupt2 != INVALID_INTERRUPT_NUM) { + detachInterrupt(interrupt2); + } + + // Return what woke the mcu. + // Default: no interrupt triggered, timer wake up + int8_t ret = MY_WAKE_UP_BY_TIMER; + if (interruptWakeUp()) { + ret = static_cast(_wokeUpByInterrupt); + } + // Clear woke-up-by-interrupt flag, so next sleeps won't return immediately. + _wokeUpByInterrupt = INVALID_INTERRUPT_NUM; + + return ret; +} + +uint32_t hwGetSleepRemaining(void) +{ + return sleepRemainingMs; +} + +inline void hwRandomNumberInit(void) +{ + // This function initializes the random number generator with a seed + // of 32 bits. This method is good enough to earn FIPS 140-2 conform + // random data. This should reach to generate 32 Bit for randomSeed(). + uint32_t seed = 0; + uint32_t timeout = millis() + 20; + + // Trigger floating effect of an unconnected pin + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP); + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT); + delay(10); + + // Generate 32 bits of datas + for (uint8_t i=0; i<32; i++) { + const int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN); + // Wait until the analog value has changed + while ((pinValue == analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) && (timeout>=millis())) { + seed ^= (millis() << i); + // Check of data generation is slow + if (timeout<=millis()) { + // Trigger pin again + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP); + pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT); + // Pause a short while + delay(seed % 10); + timeout = millis() + 20; + } + } + } + randomSeed(seed); +} + +bool hwUniqueID(unique_id_t *uniqueID) +{ + // padding + (void)memset(uniqueID, MY_HWID_PADDING_BYTE, sizeof(unique_id_t)); + // no unique ID for non-PB AVR, use HW specifics for diversification + *((uint8_t *)uniqueID) = SIGNATURE_2; + *((uint8_t *)uniqueID + 1) = SIGNATURE_1; + *((uint8_t *)uniqueID + 2) = SIGNATURE_0; + *((uint8_t *)uniqueID + 3) = SIGROW.DEVICEID0; + *((uint8_t *)uniqueID + 4) = SIGROW.DEVICEID1; + *((uint8_t *)uniqueID + 5) = SIGROW.DEVICEID2; + + // SIGROW.SERNUM[9:0]. + for(uint8_t idx = 0; idx < 10; idx++) { + *((uint8_t *)uniqueID + 6 + idx) = *(&SIGROW.SERNUM0 + idx); + } + + + return true; // unique ID returned +} + +uint16_t hwCPUVoltage(void) +{ + analogReference(INTERNAL1V024); + + for (uint8_t i = 0; i < 10; i++) { + analogRead(ADC_VDDDIV10); + } + + uint16_t adc = analogRead(ADC_VDDDIV10); + uint16_t voltage = adc * (uint16_t) 10.24; // value in mV + + return voltage; // value in mV +} + +uint16_t hwCPUFrequency(void) +{ +#ifdef F_CPU + return F_CPU / 100000UL; +#else + cli(); + const uint8_t rtcPitCtrlA = RTC.PITCTRLA; + const uint8_t rtcPitIntCtrl = RTC.PITINTCTRL; + const uint8_t rtcPitPitIntFlags = RTC.PITINTFLAGS; + + const uint8_t tcaEvCtrl = TCA0.SINGLE.EVCTRL; + const uint8_t tcaCtrlA = TCA0.SINGLE.CTRLA; + + + // setup timer1 + TCA0.SINGLE.CNT = 0x0; /* Count: 0x0 */ + + TCA0.SINGLE.EVCTRL = 0 << TCA_SINGLE_CNTAEI_bp /* Count on Event Input A: disabled */ + | 0 << TCA_SINGLE_CNTBEI_bp /* Count on Event Input B: disabled */ + | TCA_SINGLE_EVACTA_CNT_POSEDGE_gc /* Count on positive edge event */ + | TCA_SINGLE_EVACTB_UPDOWN_gc; /* Count on prescaled clock. Event controls count direction. + Up-count when event line is 0, down-count when event line + is 1. */ + TCA0.SINGLE.CTRLA = TCA_SINGLE_CLKSEL_DIV1024_gc /* System Clock */ + | 1 << TCA_SINGLE_ENABLE_bp /* Module Enable: enabled */ + | 0 << TCA_SINGLE_RUNSTDBY_bp; /* Run Standby: disabled */ + + // set pit + while (RTC.PITSTATUS > + 0) {} /* Wait for all register to be synchronized */ + RTC.PITCTRLA = RTC_PERIOD_CYC16384_gc /* RTC Clock Cycles 16384 - 500ms */ + | 1 << RTC_PITEN_bp; /* Enable: enabled */ + RTC.PITINTCTRL = 1 << RTC_PI_bp; /* Periodic Interrupt: enabled */ + + // wait for pit to interrupt + while (bit_is_clear(RTC.PITINTFLAGS, RTC_PI_bp)) {}; + + TCA0.SINGLE.CTRLA = 0; /* Enable: disabled */ + + RTC.PITCTRLA &= ~(1 << RTC_PITEN_bp); /* Enable: disabled */ + + sei(); + + const uint16_t result = (TCA0.SINGLE.CNT * 2048UL) / 100000UL; + + // Reset timers + RTC.PITCTRLA = rtcPitCtrlA; + RTC.PITINTCTRL = rtcPitIntCtrl; + RTC.PITINTFLAGS = rtcPitPitIntFlags; + + TCA0.SINGLE.EVCTRL = tcaEvCtrl; + TCA0.SINGLE.CTRLA = tcaCtrlA; + + // return frequency in 1/10MHz (accuracy +- 10%) + return result; +#endif +} + +int8_t hwCPUTemperature(void) +{ + analogReference(INTERNAL1V024); + uint16_t adc_reading = analogRead(ADC_TEMPERATURE); + + int8_t sigrow_offset = SIGROW.TEMPSENSE1; // Read signed offset from signature row + uint8_t sigrow_gain = SIGROW.TEMPSENSE0; // Read unsigned gain/slope from signature row + + uint32_t temp = adc_reading - sigrow_offset; + temp *= sigrow_gain; // Result might overflow 16-bit variable (10-bit + 8-bit) + temp += 0x80; // Add 256/2 to get correct integer rounding on division below + temp >>= 8; // Divide result by 256 to get processed temperature in Kelvin + uint16_t temperature_in_K = temp; + + return temperature_in_K - 273.15; // value in Celsius +} + +uint16_t hwFreeMem(void) +{ + extern int __heap_start, *__brkval; + int v; + return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval); +} diff --git a/hal/architecture/AVR/MyHwMegaAVR.h b/hal/architecture/AVR/MyHwMegaAVR.h new file mode 100644 index 00000000..5a4b5702 --- /dev/null +++ b/hal/architecture/AVR/MyHwMegaAVR.h @@ -0,0 +1,95 @@ +/* + * The MySensors Arduino library handles the wireless radio link and protocol + * between your home built sensors/actuators and HA controller of choice. + * The sensors forms a self healing radio network with optional repeaters. Each + * repeater and gateway builds a routing tables in EEPROM which keeps track of the + * network topology allowing messages to be routed to nodes. + * + * Created by Henrik Ekblad + * Copyright (C) 2013-2022 Sensnology AB + * Full contributor list: https://github.com/mysensors/MySensors/graphs/contributors + * + * Documentation: http://www.mysensors.org + * Support Forum: http://forum.mysensors.org + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + */ + +#ifndef MyHwAVR_h +#define MyHwAVR_h + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// Fast IO driver +#include "drivers/DigitalWriteFast/digitalWriteFast.h" + +// SOFTSPI +#ifdef MY_SOFTSPI +#include "hal/architecture/AVR/drivers/DigitalIO/DigitalIO.h" +#endif + +#ifdef __cplusplus +#include +#endif + +#define CRYPTO_LITTLE_ENDIAN + +#ifndef MY_SERIALDEVICE +#define MY_SERIALDEVICE Serial +#endif + +#ifndef MY_DEBUGDEVICE +#define MY_DEBUGDEVICE MY_SERIALDEVICE +#endif + +// AVR temperature calibration reference: http://ww1.microchip.com/downloads/en/AppNotes/Atmel-8108-Calibration-of-the-AVRs-Internal-Temperature-Reference_ApplicationNote_AVR122.pdf +#ifndef MY_AVR_TEMPERATURE_OFFSET +#define MY_AVR_TEMPERATURE_OFFSET (324.31f) +#endif + +#ifndef MY_AVR_TEMPERATURE_GAIN +#define MY_AVR_TEMPERATURE_GAIN (1.22f) +#endif + +// Define these as macros to save valuable space +#define hwDigitalWrite(__pin, __value) digitalWriteFast(__pin, __value) +#define hwDigitalRead(__pin) digitalReadFast(__pin) +#define hwPinMode(__pin, __value) pinModeFast(__pin, __value) + +void (*_beforeSleep)() ; +void (*_afterSleep)() ; + +bool hwInit(void); +void pit_reset(); + +#define hwWatchdogReset() pit_reset() +#define hwReboot() wdt_enable(WDTO_15MS); while (1) +#define hwMillis() millis() +#define hwReadConfig(__pos) eeprom_read_byte((const uint8_t *)__pos) +#define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t *)__pos, (uint8_t)__val) +#define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void *)__buf, (const void *)__pos, (uint32_t)__length) +#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((const void *)__buf, (void *)__pos, (uint32_t)__length) + +inline void hwRandomNumberInit(void); + +#if defined(MY_SOFTSPI) +SoftSPI hwSPI; //!< hwSPI +#else +#define hwSPI SPI //!< hwSPI +#endif + +#ifndef DOXYGEN +#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE) +#endif /* DOXYGEN */ + +#endif diff --git a/keywords.txt b/keywords.txt index 796c890d..89d9091e 100755 --- a/keywords.txt +++ b/keywords.txt @@ -79,6 +79,7 @@ MY_TRANSPORT_TIMEOUT_EXT_FAILURE_STATE_MS LITERAL1 MY_TRANSPORT_TIMEOUT_FAILURE_STATE_MS LITERAL1 MY_TRANSPORT_UPLINK_CHECK_DISABLED LITERAL1 MY_TRANSPORT_WAIT_READY_MS LITERAL1 +MY_ROUTES_SIZE LITERAL1 # debug MY_DEBUG LITERAL1