gatewayTransportSend

This commit is contained in:
Dmitry Borisenko
2022-12-01 02:10:06 +01:00
parent 2c61580157
commit cb50965c3b
293 changed files with 67232 additions and 3 deletions

View File

@@ -0,0 +1,533 @@
/*
* 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 <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2019 Sensnology AB
* Copyright (C) 2017 Frank Holtz
* 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 "MyHwNRF5.h"
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.
void wakeUp1(void) // place to send the interrupts
{
_wokeUpByInterrupt = _wakeUp1Interrupt;
}
void wakeUp2(void) // place to send the second interrupts
{
_wokeUpByInterrupt = _wakeUp2Interrupt;
}
void hwReadConfigBlock(void *buf, void *addr, size_t length)
{
uint8_t *dst = static_cast<uint8_t *>(buf);
const int offs = reinterpret_cast<int>(addr);
(void)NVRAM.read_block(dst, offs, length);
}
void hwWriteConfigBlock(void *buf, void *addr, size_t length)
{
uint8_t *src = static_cast<uint8_t *>(buf);
const int offs = reinterpret_cast<int>(addr);
(void)NVRAM.write_block(src, offs, length);
}
uint8_t hwReadConfig(const int addr)
{
return NVRAM.read(addr);
}
void hwWriteConfig(const int addr, uint8_t value)
{
(void)NVRAM.write(addr, value);
}
bool hwInit(void)
{
#ifdef MY_LOCK_MCU
#ifdef NRF51
// Lock MCU
if((uint32_t)((NRF_UICR->RBPCONF & UICR_RBPCONF_PALL_Msk) >> UICR_RBPCONF_PALL_Pos) !=
UICR_RBPCONF_PALL_Enabled) {
Flash.write((uint32_t *)&NRF_UICR->RBPCONF, (NRF_UICR->RBPCONF & ~UICR_RBPCONF_PALL_Msk));
hwReboot();
}
#else
// Lock MCU
if((uint32_t)((NRF_UICR->APPROTECT & UICR_APPROTECT_PALL_Msk) >> UICR_APPROTECT_PALL_Pos) !=
UICR_APPROTECT_PALL_Enabled) {
Flash.write((uint32_t *)&NRF_UICR->APPROTECT, (NRF_UICR->APPROTECT & ~UICR_APPROTECT_PALL_Msk));
hwReboot();
}
#endif
#endif
#if defined(NRF51) && defined(CONFIG_ENABLE_PINRESET)
// Enabling reset for NRF51 isn't handled by arduino-nrf5. Enable it, if requested.
NRF_POWER->RESET = POWER_RESET_RESET_Enabled;
NRF_POWER->RAMON |= (POWER_RAMON_ONRAM0_RAM0On << POWER_RAMON_ONRAM0_Pos) |
(POWER_RAMON_ONRAM1_RAM1On << POWER_RAMON_ONRAM1_Pos);
#endif
// Clock is manged by sleep modes. Radio depends on HFCLK.
// Force to start HFCLK
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
;
// Enable low latency sleep mode
NRF_POWER->TASKS_CONSTLAT = 1;
// Enable cache on >= NRF52
#ifndef NRF51
NRF_NVMC->ICACHECNF = NVMC_ICACHECNF_CACHEEN_Msk;
#endif
// Suspend UART
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_SUSPEND = 1;
#ifdef MY_DISABLED_SERIAL
// Disable UART, when not configured
#ifdef NRF51
NRF_UART0->POWER = 0;
#endif
#else
// Configure UART
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
#if defined(MY_GATEWAY_SERIAL)
while (!MY_SERIALDEVICE) {
}
#endif
#endif
return true;
}
static nrf_ecb_t hwRngData;
static int8_t hwRndDataReadPos = -1;
void hwRandomNumberInit(void)
{
// Start HWRNG
#ifdef NRF51
NRF_RNG->POWER = 1;
#endif
// Enable "more random" numbers
NRF_RNG->CONFIG = RNG_CONFIG_DERCEN_Enabled << RNG_CONFIG_DERCEN_Pos;
NRF_RNG->TASKS_START = 1;
NRF_RNG->EVENTS_VALRDY = 0;
uint32_t seed = 0;
for (uint8_t i = 0; i < 4; i++) {
// Wait for an random number
while (NRF_RNG->EVENTS_VALRDY == 0) {
yield();
}
seed = (seed << 8) | (uint32_t)NRF_RNG->VALUE;
NRF_RNG->EVENTS_VALRDY = 0;
}
randomSeed(seed);
// Fill ESB data structure for fast random data generation
uint8_t *ecbstruct = (uint8_t *)&hwRngData;
for (uint8_t i = 0; i<sizeof(hwRngData); i++) {
while (NRF_RNG->EVENTS_VALRDY == 0) {
yield();
}
*(ecbstruct + i) = NRF_RNG->VALUE;
NRF_RNG->EVENTS_VALRDY = 0;
}
hwRndDataReadPos = 0;
// Stop HWRNG
NRF_RNG->TASKS_STOP = 1;
#ifdef NRF51
NRF_RNG->POWER = 0;
#endif
}
ssize_t hwGetentropy(void *__buffer, size_t __length)
{
if (hwRndDataReadPos<0) {
// Not initialized
hwRandomNumberInit();
}
// cut length if > 256
if (__length > 256) {
__length = 256;
}
uint8_t *dst = (uint8_t *)__buffer;
// Start random number generator
for (size_t i = 0; i < __length; i++) {
dst[i] = hwRngData.ciphertext[hwRndDataReadPos & 0xfu];
MY_CRITICAL_SECTION {
if (hwRndDataReadPos >= ((int8_t)sizeof(hwRngData.ciphertext)-1))
{
// Retry until no error
bool need_data = true;
while (need_data) {
// Stop if another task is running
NRF_ECB->TASKS_STOPECB = 1;
NRF_ECB->EVENTS_ERRORECB = 0;
NRF_ECB->EVENTS_ENDECB = 0;
uint32_t ptrbackup = NRF_ECB->ECBDATAPTR;
NRF_ECB->ECBDATAPTR = (uint32_t)&hwRngData;
NRF_ECB->TASKS_STARTECB = 1;
while (!NRF_ECB->EVENTS_ENDECB);
NRF_ECB->ECBDATAPTR = ptrbackup;
if (NRF_ECB->EVENTS_ERRORECB == 0) {
need_data = false;
}
}
hwRndDataReadPos=0;
for (uint8_t pos = 0; pos < sizeof(hwRngData.ciphertext); pos++) {
hwRngData.cleartext[pos] ^= hwRngData.ciphertext[pos];
}
} else
{
hwRndDataReadPos++;
}
}
}
return __length;
}
void hwWatchdogReset(void)
{
NRF_WDT->RR[0] = WDT_RR_RR_Reload;
}
void hwReboot(void)
{
NVIC_SystemReset();
while (true)
;
}
static volatile bool nrf5_rtc_event_triggered;
static volatile bool nrf5_pwr_hfclk;
void hwSleepPrepare(uint32_t ms)
{
// Enable low power sleep mode
NRF_POWER->TASKS_LOWPWR = 1;
// Reset RTC trigger flag
nrf5_rtc_event_triggered = false;
if (ms > 0) {
// Configure RTC
#ifdef NRF51
MY_HW_RTC->POWER = 1;
#endif
// Reset RTC
MY_HW_RTC->TASKS_CLEAR = 1;
// Calculate sleep time and prescaler
if (ms<512000) {
// prescaler 0, 30.517 μs resolution -> max 512 s sleep
MY_HW_RTC->PRESCALER = 0;
// Set compare register to 1/30.517 µs to guarantee event triggering
// A minimum of 2 ticks must be guaranteed
// (1000/32768)<<12 == 125
MY_HW_RTC->CC[0] = max(((ms << 12) / 125), 2);
} else {
// 8 Hz -> max 582.542 hours sleep.
MY_HW_RTC->PRESCALER = 4095;
// Set compare register to 1/125ms
// A minimum of 2 ticks must be guaranteed
MY_HW_RTC->CC[0] = max((ms / 125), 2);
}
MY_HW_RTC->INTENSET = RTC_INTENSET_COMPARE0_Msk;
MY_HW_RTC->EVTENSET = RTC_EVTENSET_COMPARE0_Msk;
MY_HW_RTC->EVENTS_COMPARE[0] = 0;
MY_HW_RTC->TASKS_START = 1;
NVIC_SetPriority(MY_HW_RTC_IRQN, 15);
NVIC_ClearPendingIRQ(MY_HW_RTC_IRQN);
NVIC_EnableIRQ(MY_HW_RTC_IRQN);
} else {
NRF_RTC1->TASKS_STOP = 1;
}
// Stop HFCLK
nrf5_pwr_hfclk = NRF_CLOCK->EVENTS_HFCLKSTARTED;
NRF_CLOCK->TASKS_HFCLKSTOP = 1;
// Idle serial device
#ifndef MY_DISABLED_SERIAL
NRF_UART0->TASKS_STOPRX = 1;
NRF_UART0->TASKS_STOPTX = 1;
NRF_UART0->TASKS_SUSPEND = 1;
#endif
// Clear NVRAM log, if needed and a time frame of 4 seconds available
if (ms > 40000) {
// preserve some bytes for writing to NVRAM
NVRAM.clean_up(32);
}
}
void hwSleepEnd(uint32_t ms)
{
// Start HFCLK
if (nrf5_pwr_hfclk) {
NRF_CLOCK->EVENTS_HFCLKSTARTED = 0;
NRF_CLOCK->TASKS_HFCLKSTART = 1;
while (NRF_CLOCK->EVENTS_HFCLKSTARTED == 0)
;
// Enable low latency sleep mode
NRF_POWER->TASKS_CONSTLAT = 1;
}
if (ms > 0) {
// Stop RTC
#ifdef NRF51
MY_HW_RTC->POWER = 0;
#endif
MY_HW_RTC->INTENCLR = RTC_INTENSET_COMPARE0_Msk;
MY_HW_RTC->EVTENCLR = RTC_EVTENSET_COMPARE0_Msk;
MY_HW_RTC->TASKS_STOP = 1;
NVIC_DisableIRQ(MY_HW_RTC_IRQN);
} else {
// Start Arduino RTC for millis()
NRF_RTC1->TASKS_START = 1;
}
// Start serial device
#ifndef MY_DISABLED_SERIAL
NRF_UART0->TASKS_STARTRX = 1;
NRF_UART0->TASKS_STARTTX = 1;
#endif
}
// Halt CPU until next interrupt event
inline void hwWaitForInterrupt(void)
{
__DSB();
__WFI();
}
// Sleep in System ON mode
inline void hwSleep(void)
{
__WFE();
__SEV();
__WFE();
}
int8_t hwSleep(uint32_t ms)
{
hwSleepPrepare(ms);
while (nrf5_rtc_event_triggered == false) {
hwSleep();
}
hwSleepEnd(ms);
return MY_WAKE_UP_BY_TIMER;
}
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(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2,
uint8_t mode2, uint32_t ms)
{
// Disable interrupts until going to sleep, otherwise interrupts occurring
// between attachInterrupt()
// and sleep might cause the MCU to not wakeup from sleep as interrupt has
// already be handled!
MY_CRITICAL_SECTION {
// attach interrupts
_wakeUp1Interrupt = interrupt1;
_wakeUp2Interrupt = interrupt2;
if (interrupt1 != INVALID_INTERRUPT_NUM)
{
attachInterrupt(interrupt1, wakeUp1, mode1);
}
if (interrupt2 != INVALID_INTERRUPT_NUM)
{
attachInterrupt(interrupt2, wakeUp2, mode2);
}
// Reset attribute
_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
}
// Prepare Timer and Hardware
hwSleepPrepare(ms);
// Sleep until timeout or interrupt
while ((nrf5_rtc_event_triggered == false) and
(_wokeUpByInterrupt == INVALID_INTERRUPT_NUM)) {
hwSleep();
}
// 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);
}
// Wake up Hardware
hwSleepEnd(ms);
// Return what woke the mcu.
int8_t ret =
MY_WAKE_UP_BY_TIMER; // default: no interrupt triggered, timer wake up
if (_wokeUpByInterrupt != INVALID_INTERRUPT_NUM) {
ret = static_cast<int8_t>(_wokeUpByInterrupt);
}
// Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
return ret;
}
extern "C" {
// RTC interrupt handler
void MY_HW_RTC_IRQ_HANDLER(void)
{
if (MY_HW_RTC->EVENTS_COMPARE[0] > 0) {
nrf5_rtc_event_triggered = true;
NRF_RESET_EVENT(MY_HW_RTC->EVENTS_COMPARE[0]);
}
}
}
bool hwUniqueID(unique_id_t *uniqueID)
{
uint32_t *buffer = (uint32_t *)uniqueID;
buffer[0] = NRF_FICR->DEVICEID[0];
buffer[1] = NRF_FICR->DEVICEID[1];
buffer[2] = NRF_FICR->DEVICEADDR[0];
buffer[3] = NRF_FICR->DEVICEADDR[1];
return true;
}
uint16_t hwCPUVoltage(void)
{
// VDD is prescaled 1/3 and compared with the internal 1.2V reference
#if defined(NRF_ADC)
// NRF51:
// Sampling is done with lowest resolution to minimize the time
// 20uS@260uA
// Concurrent resource: disable
uint32_t lpcomp_enabled = NRF_LPCOMP->ENABLE;
NRF_LPCOMP->ENABLE = 0;
// Enable and configure ADC
NRF_ADC->ENABLE = 1;
NRF_ADC->CONFIG = (ADC_CONFIG_EXTREFSEL_None << ADC_CONFIG_EXTREFSEL_Pos) |
(ADC_CONFIG_PSEL_Disabled << ADC_CONFIG_PSEL_Pos) |
(ADC_CONFIG_REFSEL_VBG << ADC_CONFIG_REFSEL_Pos) |
(ADC_CONFIG_INPSEL_SupplyOneThirdPrescaling << ADC_CONFIG_INPSEL_Pos) |
(ADC_CONFIG_RES_8bit << ADC_CONFIG_RES_Pos);
NRF_ADC->EVENTS_END = 0;
NRF_ADC->TASKS_START = 1;
while(!NRF_ADC->EVENTS_END);
NRF_ADC->EVENTS_END = 0;
int32_t sample = (int32_t)NRF_ADC->RESULT;
NRF_ADC->TASKS_STOP = 1;
NRF_ADC->ENABLE = 0;
// Restore LPCOMP state
NRF_LPCOMP->ENABLE = lpcomp_enabled;
return (sample*3600)/255;
#elif defined(NRF_SAADC)
// NRF52:
// Sampling time 3uS@700uA
int32_t sample;
NRF_SAADC->ENABLE = SAADC_ENABLE_ENABLE_Enabled << SAADC_ENABLE_ENABLE_Pos;
NRF_SAADC->RESOLUTION = SAADC_RESOLUTION_VAL_8bit << SAADC_RESOLUTION_VAL_Pos;
NRF_SAADC->CH[0].PSELP = SAADC_CH_PSELP_PSELP_VDD << SAADC_CH_PSELP_PSELP_Pos;
NRF_SAADC->CH[0].CONFIG = (SAADC_CH_CONFIG_BURST_Disabled << SAADC_CH_CONFIG_BURST_Pos) |
(SAADC_CH_CONFIG_MODE_SE << SAADC_CH_CONFIG_MODE_Pos) |
(SAADC_CH_CONFIG_TACQ_3us << SAADC_CH_CONFIG_TACQ_Pos) |
(SAADC_CH_CONFIG_REFSEL_Internal << SAADC_CH_CONFIG_REFSEL_Pos) |
(SAADC_CH_CONFIG_GAIN_Gain1_6 << SAADC_CH_CONFIG_GAIN_Pos) |
(SAADC_CH_CONFIG_RESN_Bypass << SAADC_CH_CONFIG_RESN_Pos) |
(SAADC_CH_CONFIG_RESP_Bypass << SAADC_CH_CONFIG_RESP_Pos);
NRF_SAADC->OVERSAMPLE = SAADC_OVERSAMPLE_OVERSAMPLE_Bypass << SAADC_OVERSAMPLE_OVERSAMPLE_Pos;
NRF_SAADC->SAMPLERATE = SAADC_SAMPLERATE_MODE_Task << SAADC_SAMPLERATE_MODE_Pos;
NRF_SAADC->RESULT.MAXCNT = 1;
NRF_SAADC->RESULT.PTR = (uint32_t)&sample;
NRF_SAADC->EVENTS_STARTED = 0;
NRF_SAADC->TASKS_START = 1;
while (!NRF_SAADC->EVENTS_STARTED);
NRF_SAADC->EVENTS_STARTED = 0;
NRF_SAADC->EVENTS_END = 0;
NRF_SAADC->TASKS_SAMPLE = 1;
while (!NRF_SAADC->EVENTS_END);
NRF_SAADC->EVENTS_END = 0;
NRF_SAADC->EVENTS_STOPPED = 0;
NRF_SAADC->TASKS_STOP = 1;
while (!NRF_SAADC->EVENTS_STOPPED);
NRF_SAADC->EVENTS_STOPPED = 1;
NRF_SAADC->ENABLE = (SAADC_ENABLE_ENABLE_Disabled << SAADC_ENABLE_ENABLE_Pos);
return (sample*3600)/255;
#else
// unknown MCU
return 0;
#endif
}
uint16_t hwCPUFrequency(void)
{
#if defined(VARIANT_MCK)
return (VARIANT_MCK) / 100000UL;
#elif defined(F_CPU)
return (F_CPU) / 100000UL;
#else
return 160;
#endif
}
int8_t hwCPUTemperature(void)
{
return -127; // not implemented yet
}
uint16_t hwFreeMem(void)
{
// TODO: Not supported!
return FUNCTION_NOT_SUPPORTED;
}

View File

@@ -0,0 +1,208 @@
/*
* 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 <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2019 Sensnology AB
* Copyright (C) 2017 Frank Holtz
* 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 MyHwNRF5_h
#define MyHwNRF5_h
#ifdef __cplusplus
#include <Arduino.h>
#endif
#define CRYPTO_LITTLE_ENDIAN
#ifndef MY_SERIALDEVICE
#define MY_SERIALDEVICE Serial
#endif
#ifndef MY_DEBUGDEVICE
#define MY_DEBUGDEVICE MY_SERIALDEVICE
#endif
// Define NRF5_SOFTDEVICE when SoftDevice found
#if defined(S110) || defined(S130) || defined(S132) || defined(S140)
#ifndef SOFTDEVICE_PRESENT
#define SOFTDEVICE_PRESENT
#endif
#endif
// Define ARDUINO_ARCH_NRF5, if not defined
#ifndef ARDUINO_ARCH_NRF5
#define ARDUINO_ARCH_NRF5
#endif
#include "hal/architecture/NRF5/drivers/nrf5_wiring_digital.c"
#include "hal/architecture/NRF5/drivers/wdt.h"
#include "hal/architecture/NRF5/drivers/nrf_temp.h"
#include "drivers/NVM/NVRAM.cpp"
#include "drivers/NVM/VirtualPage.cpp"
#include <avr/dtostrf.h>
#include <nrf.h>
#include <SPI.h>
// mapping
#ifndef strncpy_P
#define strncpy_P strncpy
#endif
#ifndef snprintf_P
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
#endif
#ifndef vsnprintf_P
#define vsnprintf_P vsnprintf
#endif
#ifndef printf_P
#define printf_P printf
#endif
// redefine 8 bit types of inttypes.h until fix of https://github.com/sandeepmistry/arduino-nRF5/issues/197
#undef PRId8
#undef PRIi8
#undef PRIo8
#undef PRIu8
#undef PRIx8
#undef PRIX8
#undef PRIdLEAST8
#undef PRIiLEAST8
#undef PRIoLEAST8
#undef PRIuLEAST8
#undef PRIxLEAST8
#undef PRIXLEAST8
#undef PRIdFAST8
#undef PRIiFAST8
#undef PRIoFAST8
#undef PRIuFAST8
#undef PRIxFAST8
#undef PRIXFAST8
#define PRId8 "hd"
#define PRIi8 "hi"
#define PRIo8 "ho"
#define PRIu8 "hu"
#define PRIx8 "hx"
#define PRIX8 "hX"
#define PRIdLEAST8 "hd"
#define PRIiLEAST8 "hi"
#define PRIoLEAST8 "ho"
#define PRIuLEAST8 "hu"
#define PRIxLEAST8 "hx"
#define PRIXLEAST8 "hX"
#define PRIdFAST8 "hd"
#define PRIiFAST8 "hi"
#define PRIoFAST8 "ho"
#define PRIuFAST8 "hu"
#define PRIxFAST8 "hx"
#define PRIXFAST8 "hX"
// Define these as macros to save valuable space
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
#define hwDigitalRead(__pin) digitalRead(__pin)
#define hwPinMode(__pin, __value) nrf5_pinMode(__pin, __value)
#define hwMillis() millis()
// TODO: Can nrf5 determine time slept?
#define hwGetSleepRemaining() (0ul)
bool hwInit(void);
void hwWatchdogReset(void);
void hwReboot(void);
void hwReadConfigBlock(void *buf, void *addr, size_t length);
void hwWriteConfigBlock(void *buf, void *addr, size_t length);
void hwWriteConfig(const int addr, uint8_t value);
uint8_t hwReadConfig(const int addr);
void hwRandomNumberInit(void);
ssize_t hwGetentropy(void *__buffer, size_t __length);
#define MY_HW_HAS_GETENTROPY
// SOFTSPI
#ifdef MY_SOFTSPI
#error Soft SPI is not available on this architecture!
#endif
#define hwSPI SPI //!< hwSPI
/**
* Disable all interrupts.
* Helper function for MY_CRITICAL_SECTION.
*/
static __inline__ uint8_t __disableIntsRetVal(void)
{
__disable_irq();
return 1;
}
/**
* Restore priority mask register.
* Helper function for MY_CRITICAL_SECTION.
*/
static __inline__ void __priMaskRestore(const uint32_t *priMask)
{
__set_PRIMASK(*priMask);
}
/**
* Reset events and read back on nRF52
* http://infocenter.nordicsemi.com/pdf/nRF52_Series_Migration_v1.0.pdf
*/
#if __CORTEX_M == 0x04
#define NRF_RESET_EVENT(event) \
event = 0; \
(void)event
#else
#define NRF_RESET_EVENT(event) event = 0
#endif
/**
* RTC to use for hwSleep
* RTC1 is used by arduino-nRF5
* RTC2 is used on nRF52
* RTC0 is used on nRF51. This conflicts with SoftDevice!
*/
#ifdef NRF_RTC2
#define MY_HW_RTC NRF_RTC2
#define MY_HW_RTC_IRQ_HANDLER RTC2_IRQHandler
#define MY_HW_RTC_IRQN RTC2_IRQn
#else
#define MY_HW_RTC NRF_RTC0
#define MY_HW_RTC_IRQ_HANDLER RTC0_IRQHandler
#define MY_HW_RTC_IRQN RTC0_IRQn
#endif
/** Datastructure for AES ECB unit
*/
typedef struct {
/** AES Key
*/
uint8_t key[16];
/** Unencrypted data
*/
uint8_t cleartext[16];
/** Encrypted data
*/
uint8_t ciphertext[16];
} nrf_ecb_t;
#if !defined(DOXYGEN) && !defined(CPPCHECK)
#define MY_CRITICAL_SECTION \
for (uint32_t __savePriMask \
__attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), \
__ToDo = __disableIntsRetVal(); \
__ToDo; __ToDo = 0)
#else
#define MY_CRITICAL_SECTION
#endif /* DOXYGEN || CPPCHECK */
#endif // #ifndef MyHwNRF5_h

View File

@@ -0,0 +1,39 @@
/*
* 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 <henrik.ekblad@mysensors.org>
* Copyright (C) 2013-2019 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.
*/
// Initialize library and handle sketch functions like we want to
int main(void)
{
init();
#if defined(USBCON)
USBDevice.attach();
#endif
_begin(); // Startup MySensors library
for(;;) {
_process(); // Process incoming data
if (loop) {
loop(); // Call sketch loop
}
if (serialEventRun) {
serialEventRun();
}
}
return 0;
}

View File

@@ -0,0 +1,165 @@
/*
Flash.cpp - Flash library
Original Copyright (c) 2017 Frank Holtz. All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "drivers/NVM/Flash.h"
#include <nrf.h>
FlashClass Flash;
uint32_t FlashClass::page_size() const
{
return (size_t)NRF_FICR->CODEPAGESIZE;
}
uint8_t FlashClass::page_size_bits() const
{
#if defined(NRF51)
return 10;
#elif defined(NRF52)
return 12;
#endif
}
uint32_t FlashClass::page_count() const
{
return (uint32_t)NRF_FICR->CODESIZE;
}
uint32_t FlashClass::specified_erase_cycles() const
{
return FLASH_ERASE_CYCLES;
}
uint32_t *FlashClass::page_address(size_t page)
{
return (uint32_t *)(page << page_size_bits());
}
uint32_t *FlashClass::top_app_page_address()
{
#if !defined(MCUBOOT_PRESENT)
// Bootcode at the top of the flash memory?
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fcom.nordic.infocenter.sdk5.v12.0.0%2Flib_bootloader.html
if (NRF_UICR->NRFFW[0]<0xFFFFFFFF) {
// Return pointer calculated by SoftDevice/bootloader
return (uint32_t *)NRF_UICR->NRFFW[0];
}
#endif
// Return flash length
return (uint32_t *)(Flash.page_count() << Flash.page_size_bits());
}
void FlashClass::erase(uint32_t *address, size_t size)
{
size_t end_address = (size_t)address + size;
// align address
address =
(uint32_t *)((size_t)address & (size_t)((size_t)(~0) - FLASH_PAGE_SIZE));
// Wrong parameters?
if ((size_t)address >= end_address) {
return;
}
// get old nvm controller state
uint32_t old_config = NRF_NVMC->CONFIG;
// Enable erasing flash
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos;
// Erase page(s)
while ((size_t)address < end_address) {
wait_for_ready();
// Erase one 1k/4k page
NRF_NVMC->ERASEPAGE = (size_t)(address);
address = (uint32_t *)((size_t)address + FLASH_PAGE_SIZE);
}
// Disable erasing
wait_for_ready();
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
// Restore old state
wait_for_ready();
NRF_NVMC->CONFIG = old_config;
// Go back if controller is ready
wait_for_ready();
}
void FlashClass::erase_all()
{
// Enable erasing flash
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Een << NVMC_CONFIG_WEN_Pos;
wait_for_ready();
// Erase Flash and UICR
NRF_NVMC->ERASEALL = 1;
wait_for_ready();
// Disable erasing
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
wait_for_ready();
}
void FlashClass::write(uint32_t *address, uint32_t value)
{
// Compare word
if (*address != value) {
// Enable write
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
wait_for_ready();
// Write word
*address = value;
// Disable write
wait_for_ready();
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
wait_for_ready();
}
}
void FlashClass::write_block(uint32_t *dst_address, uint32_t *src_address,
uint16_t word_count)
{
// Enable write
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Wen << NVMC_CONFIG_WEN_Pos;
wait_for_ready();
while (word_count > 0) {
// cppcheck-suppress duplicateConditionalAssign
if (*dst_address != *src_address) {
*dst_address = *src_address;
}
word_count--;
dst_address++;
src_address++;
}
// Disable write
wait_for_ready();
NRF_NVMC->CONFIG = NVMC_CONFIG_WEN_Ren << NVMC_CONFIG_WEN_Pos;
wait_for_ready();
}
void FlashClass::wait_for_ready()
{
while (NRF_NVMC->READY == NVMC_READY_READY_Busy) {
};
}

View File

@@ -0,0 +1,42 @@
/*
* nRF5 output modes
*/
// Standard 0, Standard 1
#ifndef OUTPUT_S0S1
#define OUTPUT_S0S1 (0x10)
#endif
// High Drive 0, Standard 1
#ifndef OUTPUT_H0S1
#define OUTPUT_H0S1 (0x11)
#endif
// Standard 0, High Drive 1
#ifndef OUTPUT_S0H1
#define OUTPUT_S0H1 (0x12)
#endif
// High Drive both
#ifndef OUTPUT_H0H1
#define OUTPUT_H0H1 (0x13)
#endif
// Disconnected 0, Standard 1
#ifndef OUTPUT_D0S1
#define OUTPUT_D0S1 (0x14)
#endif
// Disconnected 0, High Drive 1
#ifndef OUTPUT_D0H1
#define OUTPUT_D0H1 (0x15)
#endif
// Standard 0, Disconnected 1
#ifndef OUTPUT_S0D1
#define OUTPUT_S0D1 (0x16)
#endif
// High Drive 0, Disconnected 1
#ifndef OUTPUT_H0D1
#define OUTPUT_H0D1 (0x17)
#endif

View File

@@ -0,0 +1,102 @@
/*
Copyright (c) 2015 Arduino LLC. All right reserved.
Copyright (c) 2016 Sandeep Mistry All right reserved.
Copyright (c) 2017 Frank Holtz All right reserved.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include "nrf.h"
#include "Arduino.h"
#include "nrf5_wiring_constants.h"
#ifdef __cplusplus
extern "C" {
#endif
void nrf5_pinMode(uint32_t ulPin, uint32_t ulMode)
{
if (ulPin >= PINS_COUNT) {
return;
}
#ifdef ARDUINO_ARCH_NRF52
// Arduino: https://github.com/arduino-org/arduino-core-nrf52
ulPin = g_APinDescription[ulPin].ulPin;
#else
// Sandeep Mistry: https://github.com/sandeepmistry/arduino-nRF5
ulPin = g_ADigitalPinMap[ulPin];
#endif
// Set pin mode according to chapter '22.6.3 I/O Pin Configuration'
switch (ulMode) {
case INPUT:
// Set pin to input mode
NRF_GPIO->PIN_CNF[ulPin] =
((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
break;
case INPUT_PULLUP:
// Set pin to input mode with pull-up resistor enabled
NRF_GPIO->PIN_CNF[ulPin] =
((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos) |
((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
break;
case INPUT_PULLDOWN:
// Set pin to input mode with pull-down resistor enabled
NRF_GPIO->PIN_CNF[ulPin] =
((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos) |
((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos) |
((uint32_t)GPIO_PIN_CNF_PULL_Pulldown << GPIO_PIN_CNF_PULL_Pos) |
((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
break;
case OUTPUT:
// Set pin to output mode
NRF_GPIO->PIN_CNF[ulPin] =
((uint32_t)GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos) |
((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
break;
default:
// calculate nRF specific output modes
if ((ulMode >= OUTPUT_S0S1) && (ulMode <= OUTPUT_H0D1)) {
// Set pin to given output mode
NRF_GPIO->PIN_CNF[ulPin] =
((uint32_t)GPIO_PIN_CNF_DIR_Output << GPIO_PIN_CNF_DIR_Pos) |
((uint32_t)GPIO_PIN_CNF_INPUT_Disconnect << GPIO_PIN_CNF_INPUT_Pos) |
((uint32_t)GPIO_PIN_CNF_PULL_Disabled << GPIO_PIN_CNF_PULL_Pos) |
((uint32_t)(ulMode - OUTPUT_S0S1) << GPIO_PIN_CNF_DRIVE_Pos) |
((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
}
break;
}
}
#ifdef __cplusplus
}
#endif

View File

@@ -0,0 +1,70 @@
/*
* Copyright (c) 2012 - 2018, Nordic Semiconductor ASA
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef NRF_TEMP_H__
#define NRF_TEMP_H__
#ifdef __cplusplus
extern "C" {
#endif
#define MASK_SIGN (0x00000200UL) //!< MASK_SIGN
#define MASK_SIGN_EXTENSION (0xFFFFFC00UL) //!< MASK_SIGN_EXTENSION
/**
* @brief Function for preparing the temp module for temperature measurement.
*
* This function initializes the TEMP module and writes to the hidden configuration register.
*/
static __INLINE void nrf_temp_init(void)
{
/**@note Workaround for PAN_028 rev2.0A anomaly 31 - TEMP: Temperature offset value has to be manually loaded to the TEMP module */
*(uint32_t *) 0x4000C504 = 0;
}
/**
* @brief Function for reading temperature measurement.
*
* The function reads the 10 bit 2's complement value and transforms it to a 32 bit 2's complement value.
*/
static __INLINE int32_t nrf_temp_read(void)
{
/**@note Workaround for PAN_028 rev2.0A anomaly 28 - TEMP: Negative measured values are not represented correctly */
return ((NRF_TEMP->TEMP & MASK_SIGN) != 0) ? (int32_t)(NRF_TEMP->TEMP | MASK_SIGN_EXTENSION) :
(NRF_TEMP->TEMP);
}
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,186 @@
/* Copyright (c) 2002, 2004 Marek Michalkiewicz
Copyright (c) 2005, 2006, 2007 Eric B. Weddington
Copyright (c) 2016 Frank Holtz
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
* Neither the name of the copyright holders nor the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE. */
/* $Id$ */
/*
avr/wdt.h - macros for AVR watchdog timer
*/
#ifndef _NRF5_WDT_H_
#define _NRF5_WDT_H_
#include <nrf.h>
#include <stdint.h>
/** \file */
/** \defgroup avr_watchdog <avr/wdt.h>: Watchdog timer handling
\code #include <avr/wdt.h> \endcode
@ingroup internals
This header file declares the interface to some inline macros
handling the watchdog timer like present in many AVR devices.
In order to prevent the watchdog timer configuration from being
accidentally altered by a crashing application, a special timed
sequence is required in order to change it. The macros within
this header file handle the required sequence automatically
before changing any value. Interrupts will be disabled during
the manipulation.
*/
/**
\ingroup avr_watchdog
Reset the watchdog timer. When the watchdog timer is enabled,
a call to this instruction is required before the timer expires,
otherwise a watchdog-initiated device reset will occur.
*/
#define wdt_reset() NRF_WDT->RR[0] = WDT_RR_RR_Reload
/**
\ingroup avr_watchdog
Enable the watchdog timer, configuring it for expiry after
\c timeout (ms).
The WDT is running in sleep mode.
See also the symbolic constants \c WDTO_15MS et al.
*/
#define wdt_enable(timeout) \
NRF_WDT->CONFIG = NRF_WDT->CONFIG = (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos) | ( WDT_CONFIG_SLEEP_Run << WDT_CONFIG_SLEEP_Pos); \
NRF_WDT->CRV = (32768*timeout)/1000; \
NRF_WDT->RREN |= WDT_RREN_RR0_Msk; \
NRF_WDT->TASKS_START = 1
/**
\ingroup avr_watchdog
Disable the watchdog timer. On nRF5 the timer cannot disabled.
The period is set to 36h of CPU run time. The WDT is stopped in sleep mode.
*/
#define wdt_disable() \
NRF_WDT->CONFIG = NRF_WDT->CONFIG = (WDT_CONFIG_HALT_Pause << WDT_CONFIG_HALT_Pos) | ( WDT_CONFIG_SLEEP_Pause << WDT_CONFIG_SLEEP_Pos); \
NRF_WDT->CRV = 4294967295
/**
\ingroup avr_watchdog
Symbolic constants for the watchdog timeout.
Possible timeout values are: 15 ms, 30 ms, 60 ms, 120 ms, 250 ms,
500 ms, 1 s, 2 s, 4s, 8s. (Not all devices allow 4 s or 8 s.)
Symbolic constants are formed by the prefix
\c WDTO_, followed by the time.
Example that would select a watchdog timer expiry of approximately
500 ms:
\code
wdt_enable(WDTO_500MS);
\endcode
*/
#define WDTO_15MS 15
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_30MS 30
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_60MS 60
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_120MS 120
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_250MS 250
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_500MS 500
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_1S 1000
/** \ingroup avr_watchdog
See \c WDTO_15MS */
#define WDTO_2S 2000
/** \ingroup avr_watchdog
See \c WDTO_15MS
Note: This is only available on the
ATtiny2313,
ATtiny24, ATtiny44, ATtiny84, ATtiny84A,
ATtiny25, ATtiny45, ATtiny85,
ATtiny261, ATtiny461, ATtiny861,
ATmega48, ATmega88, ATmega168,
ATmega48P, ATmega88P, ATmega168P, ATmega328P,
ATmega164P, ATmega324P, ATmega644P, ATmega644,
ATmega640, ATmega1280, ATmega1281, ATmega2560, ATmega2561,
ATmega8HVA, ATmega16HVA, ATmega32HVB,
ATmega406, ATmega1284P,
AT90PWM1, AT90PWM2, AT90PWM2B, AT90PWM3, AT90PWM3B, AT90PWM216, AT90PWM316,
AT90PWM81, AT90PWM161,
AT90USB82, AT90USB162,
AT90USB646, AT90USB647, AT90USB1286, AT90USB1287,
ATtiny48, ATtiny88,
nRF51822, nRF52832
*/
#define WDTO_4S 4000
/** \ingroup avr_watchdog
See \c WDTO_15MS
Note: This is only available on the
ATtiny2313,
ATtiny24, ATtiny44, ATtiny84, ATtiny84A,
ATtiny25, ATtiny45, ATtiny85,
ATtiny261, ATtiny461, ATtiny861,
ATmega48, ATmega48A, ATmega48PA, ATmega88, ATmega168,
ATmega48P, ATmega88P, ATmega168P, ATmega328P,
ATmega164P, ATmega324P, ATmega644P, ATmega644,
ATmega640, ATmega1280, ATmega1281, ATmega2560, ATmega2561,
ATmega8HVA, ATmega16HVA, ATmega32HVB,
ATmega406, ATmega1284P,
ATmega2564RFR2, ATmega256RFR2, ATmega1284RFR2, ATmega128RFR2, ATmega644RFR2, ATmega64RFR2
AT90PWM1, AT90PWM2, AT90PWM2B, AT90PWM3, AT90PWM3B, AT90PWM216, AT90PWM316,
AT90PWM81, AT90PWM161,
AT90USB82, AT90USB162,
AT90USB646, AT90USB647, AT90USB1286, AT90USB1287,
ATtiny48, ATtiny88,
ATxmega16a4u, ATxmega32a4u,
ATxmega16c4, ATxmega32c4,
ATxmega128c3, ATxmega192c3, ATxmega256c3,
nRF51822, nRF52832
*/
#define WDTO_8S 8000
#endif /* _NRF5_WDT_H_ */