Restructure HAL files (arch) (#820)
This commit is contained in:
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file MyHw.h
|
||||
*
|
||||
* MySensors hardware abstraction layer
|
||||
*/
|
||||
|
||||
#ifndef MyHw_h
|
||||
#define MyHw_h
|
||||
|
||||
// Implement these as functions or macros
|
||||
/*
|
||||
#define hwInit() MY_SERIALDEVICE.begin(BAUD_RATE)
|
||||
#define hwWatchdogReset() wdt_reset()
|
||||
#define hwReboot() wdt_enable(WDTO_15MS); while (1)
|
||||
#define hwMillis() millis()
|
||||
|
||||
#define hwDigitalWrite(__pin, __value)
|
||||
#define hwDigitalRead(__pin)
|
||||
#define hwPinMode(__pin, __value)
|
||||
|
||||
void hwReadConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfig(int adr, uint8_t value);
|
||||
uint8_t hwReadConfig(int adr);
|
||||
*/
|
||||
|
||||
/**
|
||||
* Sleep for a defined time, using minimum power.
|
||||
* @param ms Time to sleep, in [ms].
|
||||
* @return Nonsense, please ignore.
|
||||
*/
|
||||
|
||||
typedef uint8_t unique_id_t[16];
|
||||
|
||||
/**
|
||||
* Sleep for a defined time, using minimum power.
|
||||
* @param ms Time to sleep, in [ms].
|
||||
* @return -1.
|
||||
*/
|
||||
int8_t hwSleep(unsigned long ms);
|
||||
|
||||
/**
|
||||
* Sleep for a defined time, using minimum power, or until woken by interrupt.
|
||||
* @param interrupt Interrupt number, which can wake the mcu from sleep.
|
||||
* @param mode Interrupt mode, as passed to attachInterrupt.
|
||||
* @param ms Time to sleep, in [ms].
|
||||
* @return -1 when woken by timer, or interrupt number when woken by interrupt.
|
||||
*/
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms);
|
||||
|
||||
/**
|
||||
* Sleep for a defined time, using minimum power, or until woken by one of the interrupts.
|
||||
* @param interrupt1 Interrupt1 number, which can wake the mcu from sleep.
|
||||
* @param mode1 Interrupt1 mode, as passed to attachInterrupt.
|
||||
* @param interrupt2 Interrupt2 number, which can wake the mcu from sleep.
|
||||
* @param mode2 Interrupt2 mode, as passed to attachInterrupt.
|
||||
* @param ms Time to sleep, in [ms].
|
||||
* @return -1 when woken by timer, or interrupt number when woken by interrupt.
|
||||
*/
|
||||
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
|
||||
unsigned long ms);
|
||||
|
||||
/**
|
||||
* Retrieve unique ID
|
||||
* @param uniqueID uniqueID
|
||||
* @return True if unique ID successfully retrieved
|
||||
*/
|
||||
bool hwUniqueID(unique_id_t* uniqueID);
|
||||
|
||||
/**
|
||||
* CPU voltage
|
||||
* @return CPU voltage in mV
|
||||
*/
|
||||
uint16_t hwCPUVoltage();
|
||||
|
||||
/**
|
||||
* CPU frequency
|
||||
* @return CPU frequency in 1/10Mhz
|
||||
*/
|
||||
uint16_t hwCPUFrequency();
|
||||
|
||||
/**
|
||||
* Free memory
|
||||
* @return free memory in bytes
|
||||
*/
|
||||
uint16_t hwFreeMem();
|
||||
|
||||
#if defined(DEBUG_OUTPUT_ENABLED)
|
||||
void hwDebugPrint(const char *fmt, ... );
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def MY_CRITICAL_SECTION
|
||||
* @brief Creates a block of code that is guaranteed to be executed atomically.
|
||||
* Upon entering the block all interrupts are disabled, and re-enabled upon
|
||||
* exiting the block from any exit path.
|
||||
* A typical example that requires atomic access is a 16 (or more) bit variable
|
||||
* that is shared between the main execution path and an ISR, on an 8-bit
|
||||
* platform (e.g AVR):
|
||||
* @code
|
||||
* volatile uint16_t val = 0;
|
||||
*
|
||||
* void interrupHandler()
|
||||
* {
|
||||
* val = ~val;
|
||||
* }
|
||||
*
|
||||
* void loop()
|
||||
* {
|
||||
* uint16_t copy_val;
|
||||
* MY_CRITICAL_SECTION
|
||||
* {
|
||||
* copy_val = val;
|
||||
* }
|
||||
* }
|
||||
* @endcode
|
||||
* All code within the MY_CRITICAL_SECTION block will be protected from being
|
||||
* interrupted during execution.
|
||||
*/
|
||||
#ifdef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif // #ifdef MyHw_h
|
||||
@@ -0,0 +1,295 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 "MyHwAVR.h"
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#define WDTO_SLEEP_FOREVER (0xFFu)
|
||||
#define INVALID_INTERRUPT_NUM (0xFFu)
|
||||
|
||||
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()
|
||||
{
|
||||
// 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()
|
||||
{
|
||||
sleep_disable();
|
||||
detachInterrupt(_wakeUp2Interrupt);
|
||||
// First interrupt occurred will be reported only
|
||||
if (INVALID_INTERRUPT_NUM == _wokeUpByInterrupt) {
|
||||
_wokeUpByInterrupt = _wakeUp2Interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool interruptWakeUp()
|
||||
{
|
||||
return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM;
|
||||
}
|
||||
|
||||
void clearPendingInterrupt(const uint8_t interrupt)
|
||||
{
|
||||
EIFR = _BV(interrupt);
|
||||
}
|
||||
|
||||
// Watchdog Timer interrupt service routine. This routine is required
|
||||
// to allow automatic WDIF and WDIE bit clearance in hardware.
|
||||
ISR (WDT_vect)
|
||||
{
|
||||
}
|
||||
|
||||
void hwPowerDown(const uint8_t wdto)
|
||||
{
|
||||
// Let serial prints finish (debug, log etc)
|
||||
#ifndef MY_DISABLED_SERIAL
|
||||
MY_SERIALDEVICE.flush();
|
||||
#endif
|
||||
|
||||
// disable ADC for power saving
|
||||
ADCSRA &= ~(1 << ADEN);
|
||||
// save WDT settings
|
||||
uint8_t WDTsave = WDTCSR;
|
||||
if (wdto != WDTO_SLEEP_FOREVER) {
|
||||
wdt_enable(wdto);
|
||||
// enable WDT interrupt before system reset
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDIE);
|
||||
} else {
|
||||
// if sleeping forever, disable WDT
|
||||
wdt_disable();
|
||||
}
|
||||
set_sleep_mode(SLEEP_MODE_PWR_DOWN);
|
||||
cli();
|
||||
sleep_enable();
|
||||
#if defined __AVR_ATmega328P__
|
||||
sleep_bod_disable();
|
||||
#endif
|
||||
// Enable interrupts & sleep until WDT or ext. interrupt
|
||||
sei();
|
||||
// Directly sleep CPU, to prevent race conditions!
|
||||
// Ref: chapter 7.7 of ATMega328P datasheet
|
||||
sleep_cpu();
|
||||
sleep_disable();
|
||||
// restore previous WDT settings
|
||||
cli();
|
||||
wdt_reset();
|
||||
// enable WDT changes
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||||
// restore saved WDT settings
|
||||
WDTCSR = WDTsave;
|
||||
sei();
|
||||
// enable ADC
|
||||
ADCSRA |= (1 << ADEN);
|
||||
}
|
||||
|
||||
void hwInternalSleep(unsigned long ms)
|
||||
{
|
||||
// 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) {
|
||||
for (uint8_t period = 9u; ; --period) {
|
||||
const uint16_t comparatorMS = 1 << (period + 4);
|
||||
if ( ms >= comparatorMS) {
|
||||
hwPowerDown(period); // 8192ms => 9, 16ms => 0
|
||||
ms -= comparatorMS;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int8_t hwSleep(unsigned long ms)
|
||||
{
|
||||
hwInternalSleep(ms);
|
||||
return MY_WAKE_UP_BY_TIMER;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long 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,
|
||||
unsigned long 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);
|
||||
}
|
||||
|
||||
if (ms > 0u) {
|
||||
// sleep for defined time
|
||||
hwInternalSleep(ms);
|
||||
} else {
|
||||
// sleep until ext interrupt triggered
|
||||
hwPowerDown(WDTO_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<int8_t>(_wokeUpByInterrupt);
|
||||
}
|
||||
// Clear woke-up-by-interrupt flag, so next sleeps won't return immediately.
|
||||
_wokeUpByInterrupt = INVALID_INTERRUPT_NUM;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t* uniqueID)
|
||||
{
|
||||
// not implemented yet
|
||||
(void)uniqueID;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage()
|
||||
{
|
||||
// Measure Vcc against 1.1V Vref
|
||||
#if defined(__AVR_ATmega32U4__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
|
||||
ADMUX = (_BV(REFS0) | _BV(MUX4) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
|
||||
#elif defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
|
||||
ADMUX = (_BV(MUX5) | _BV(MUX0));
|
||||
#elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)
|
||||
ADMUX = (_BV(MUX3) | _BV(MUX2));
|
||||
#else
|
||||
ADMUX = (_BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1));
|
||||
#endif
|
||||
// Vref settle
|
||||
delay(70);
|
||||
// Do conversion
|
||||
ADCSRA |= _BV(ADSC);
|
||||
while (bit_is_set(ADCSRA,ADSC)) {};
|
||||
// return Vcc in mV
|
||||
return (1125300UL) / ADC;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency()
|
||||
{
|
||||
cli();
|
||||
// setup timer1
|
||||
TIFR1 = 0xFF;
|
||||
TCNT1 = 0;
|
||||
TCCR1A = 0;
|
||||
TCCR1C = 0;
|
||||
// save WDT settings
|
||||
uint8_t WDTsave = WDTCSR;
|
||||
wdt_enable(WDTO_500MS);
|
||||
// enable WDT interrupt mode => first timeout WDIF, 2nd timeout reset
|
||||
WDTCSR |= (1 << WDIE);
|
||||
wdt_reset();
|
||||
// start timer1 with 1024 prescaling
|
||||
TCCR1B = _BV(CS12) | _BV(CS10);
|
||||
// wait until wdt interrupt
|
||||
while (bit_is_clear(WDTCSR,WDIF)) {};
|
||||
// stop timer
|
||||
TCCR1B = 0;
|
||||
// restore WDT settings
|
||||
wdt_reset();
|
||||
WDTCSR |= (1 << WDCE) | (1 << WDE);
|
||||
WDTCSR = WDTsave;
|
||||
sei();
|
||||
// return frequency in 1/10MHz (accuracy +- 10%)
|
||||
return TCNT1 * 2048UL / 100000UL;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem()
|
||||
{
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
}
|
||||
|
||||
void hwDebugPrint(const char *fmt, ... )
|
||||
{
|
||||
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
|
||||
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;%lu "),
|
||||
C_INTERNAL, I_LOG_MESSAGE, hwMillis());
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
#else
|
||||
// prepend timestamp
|
||||
MY_SERIALDEVICE.print(hwMillis());
|
||||
MY_SERIALDEVICE.print(F(" "));
|
||||
#endif
|
||||
va_list args;
|
||||
va_start (args, fmt );
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// Truncate message if this is gateway node
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
|
||||
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
|
||||
#else
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#endif
|
||||
va_end (args);
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
MY_SERIALDEVICE.flush();
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 "MyHw.h"
|
||||
#include <avr/eeprom.h>
|
||||
#include <avr/pgmspace.h>
|
||||
#include <avr/sleep.h>
|
||||
#include <avr/power.h>
|
||||
#include <avr/interrupt.h>
|
||||
#include <avr/wdt.h>
|
||||
#include <util/atomic.h>
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE Serial
|
||||
#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)
|
||||
|
||||
bool hwInit(void);
|
||||
|
||||
#define hwWatchdogReset() wdt_reset()
|
||||
#define hwReboot() wdt_enable(WDTO_15MS); while (1)
|
||||
#define hwMillis() millis()
|
||||
#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN))
|
||||
#define hwReadConfig(__pos) eeprom_read_byte((uint8_t*)(__pos))
|
||||
#define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t*)(__pos), (__val))
|
||||
#define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void*)(__buf), (void*)(__pos), (__length))
|
||||
#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((void*)(__buf), (void*)(__pos), (__length))
|
||||
|
||||
void hwInternalSleep(unsigned long ms);
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,161 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 "MyHwESP8266.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1, MY_ESP8266_SERIAL_MODE, 1);
|
||||
MY_SERIALDEVICE.setDebugOutput(true);
|
||||
#endif
|
||||
EEPROM.begin(EEPROM_size);
|
||||
return true;
|
||||
}
|
||||
|
||||
void hwReadConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
uint8_t* dst = static_cast<uint8_t*>(buf);
|
||||
int pos = reinterpret_cast<int>(addr);
|
||||
while (length-- > 0) {
|
||||
*dst++ = EEPROM.read(pos++);
|
||||
}
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
uint8_t* src = static_cast<uint8_t*>(buf);
|
||||
int pos = reinterpret_cast<int>(addr);
|
||||
while (length-- > 0) {
|
||||
EEPROM.write(pos++, *src++);
|
||||
}
|
||||
// see implementation, commit only executed if diff
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(const int addr)
|
||||
{
|
||||
uint8_t value;
|
||||
hwReadConfigBlock(&value, reinterpret_cast<void*>(addr), 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
void hwWriteConfig(const int addr, uint8_t value)
|
||||
{
|
||||
hwWriteConfigBlock(&value, reinterpret_cast<void*>(addr), 1);
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
// padding
|
||||
memset((uint8_t*)uniqueID, 0x0A, sizeof(unique_id_t));
|
||||
uint32_t val = ESP.getChipId();
|
||||
(void)memcpy((uint8_t*)uniqueID, &val, 4);
|
||||
val = ESP.getFlashChipId();
|
||||
(void)memcpy((uint8_t*)uniqueID + 4, &val, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int8_t hwSleep(unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
|
||||
unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
#if defined(MY_SPECIAL_DEBUG)
|
||||
// settings for getVcc()
|
||||
ADC_MODE(ADC_VCC);
|
||||
#else
|
||||
// [default] settings for analogRead(A0)
|
||||
ADC_MODE(ADC_TOUT);
|
||||
#endif
|
||||
|
||||
uint16_t hwCPUVoltage()
|
||||
{
|
||||
#if defined(MY_SPECIAL_DEBUG)
|
||||
// in mV, requires ADC_VCC set
|
||||
return ESP.getVcc();
|
||||
#else
|
||||
// not possible
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency()
|
||||
{
|
||||
// in 1/10Mhz
|
||||
return ESP.getCpuFreqMHz()*10;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem()
|
||||
{
|
||||
return ESP.getFreeHeap();
|
||||
}
|
||||
|
||||
void hwDebugPrint(const char *fmt, ... )
|
||||
{
|
||||
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
|
||||
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;%lu "), C_INTERNAL, I_LOG_MESSAGE,
|
||||
hwMillis());
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
#else
|
||||
// prepend timestamp
|
||||
MY_SERIALDEVICE.print(hwMillis());
|
||||
MY_SERIALDEVICE.print(" ");
|
||||
#endif
|
||||
va_list args;
|
||||
va_start (args, fmt );
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// Truncate message if this is gateway node
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
|
||||
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
|
||||
#else
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#endif
|
||||
va_end (args);
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
MY_SERIALDEVICE.flush();
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 MyHwESP8266_h
|
||||
#define MyHwESP8266_h
|
||||
|
||||
#include "MyHw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE Serial
|
||||
#endif
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
|
||||
#define EEPROM_size (1024)
|
||||
|
||||
// Define these as macros to save valuable space
|
||||
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
|
||||
#define hwDigitalRead(__pin) digitalRead(__pin)
|
||||
#define hwPinMode(__pin, __value) pinMode(__pin, __value)
|
||||
#define hwWatchdogReset() wdt_reset()
|
||||
#define hwReboot() ESP.restart()
|
||||
#define hwMillis() millis()
|
||||
#define hwRandomNumberInit() randomSeed(RANDOM_REG32)
|
||||
|
||||
bool hwInit(void);
|
||||
void hwReadConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfig(const int addr, uint8_t value);
|
||||
uint8_t hwReadConfig(const int addr);
|
||||
|
||||
/**
|
||||
* Restore interrupt state.
|
||||
* Helper function for MY_CRITICAL_SECTION.
|
||||
*/
|
||||
static __inline__ void __psRestore(const uint32_t *__s)
|
||||
{
|
||||
xt_wsr_ps( *__s );
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = xt_rsil(15), __ToDo = 1; __ToDo ; __ToDo = 0 )
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif // #ifdef ARDUINO_ARCH_ESP8266
|
||||
@@ -0,0 +1,150 @@
|
||||
/**
|
||||
* 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-2017 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 "MyHwLinuxGeneric.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <time.h>
|
||||
#include "SoftEeprom.h"
|
||||
#include "log.h"
|
||||
|
||||
static SoftEeprom eeprom = SoftEeprom(MY_LINUX_CONFIG_FILE, 1024); // ATMega328 has 1024 bytes
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#ifdef MY_GATEWAY_SERIAL
|
||||
#ifdef MY_LINUX_SERIAL_GROUPNAME
|
||||
if (!MY_SERIALDEVICE.setGroupPerm(MY_LINUX_SERIAL_GROUPNAME)) {
|
||||
logError("Unable to change permission for serial port device.\n");
|
||||
exit(1);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void hwReadConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
eeprom.readBlock(buf, addr, length);
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
eeprom.writeBlock(buf, addr, length);
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(int addr)
|
||||
{
|
||||
return eeprom.readByte(addr);
|
||||
}
|
||||
|
||||
void hwWriteConfig(int addr, uint8_t value)
|
||||
{
|
||||
eeprom.writeByte(addr, value);
|
||||
}
|
||||
|
||||
void hwRandomNumberInit()
|
||||
{
|
||||
randomSeed(time(NULL));
|
||||
}
|
||||
|
||||
unsigned long hwMillis()
|
||||
{
|
||||
return millis();
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
// not implemented yet
|
||||
(void)uniqueID;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not supported!
|
||||
int8_t hwSleep(unsigned long ms)
|
||||
{
|
||||
(void)ms;
|
||||
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
// Not supported!
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
|
||||
{
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
// Not supported!
|
||||
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
|
||||
unsigned long ms)
|
||||
{
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage()
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency()
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem()
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void hwDigitalWrite(uint8_t pin, uint8_t value)
|
||||
{
|
||||
digitalWrite(pin, value);
|
||||
}
|
||||
|
||||
int hwDigitalRead(uint8_t pin)
|
||||
{
|
||||
return digitalRead(pin);
|
||||
}
|
||||
|
||||
void hwPinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
pinMode(pin, mode);
|
||||
}
|
||||
|
||||
void hwDebugPrint(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vlogDebug(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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-2017 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 MyHwLinuxGeneric_h
|
||||
#define MyHwLinuxGeneric_h
|
||||
|
||||
#include <cstdlib>
|
||||
#include <pthread.h>
|
||||
#include "MyHw.h"
|
||||
#include "SerialPort.h"
|
||||
#include "SerialSimulator.h"
|
||||
|
||||
#ifdef MY_GATEWAY_SERIAL
|
||||
#ifdef MY_LINUX_IS_SERIAL_PTY
|
||||
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PTY, true);
|
||||
#else
|
||||
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT);
|
||||
#endif
|
||||
#else
|
||||
SerialSimulator Serial = SerialSimulator();
|
||||
#endif
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE Serial
|
||||
#endif
|
||||
|
||||
// Define these as macros (do nothing)
|
||||
#define hwWatchdogReset()
|
||||
#define hwReboot()
|
||||
|
||||
inline void hwDigitalWrite(uint8_t, uint8_t);
|
||||
inline int hwDigitalRead(uint8_t);
|
||||
inline void hwPinMode(uint8_t, uint8_t);
|
||||
|
||||
bool hwInit(void);
|
||||
inline void hwReadConfigBlock(void* buf, void* addr, size_t length);
|
||||
inline void hwWriteConfigBlock(void* buf, void* addr, size_t length);
|
||||
inline uint8_t hwReadConfig(int addr);
|
||||
inline void hwWriteConfig(int addr, uint8_t value);
|
||||
inline void hwRandomNumberInit();
|
||||
inline unsigned long hwMillis();
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
static pthread_mutex_t hw_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static __inline__ void __hwUnlock(const uint8_t *__s)
|
||||
{
|
||||
pthread_mutex_unlock(&hw_mutex);
|
||||
(void)__s;
|
||||
}
|
||||
|
||||
static __inline__ void __hwLock()
|
||||
{
|
||||
pthread_mutex_lock(&hw_mutex);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(DOXYGEN)
|
||||
#define ATOMIC_BLOCK_CLEANUP
|
||||
#elif defined(MY_RF24_IRQ_PIN)
|
||||
#define ATOMIC_BLOCK_CLEANUP uint8_t __atomic_loop \
|
||||
__attribute__((__cleanup__( __hwUnlock ))) = 1
|
||||
#else
|
||||
#define ATOMIC_BLOCK_CLEANUP
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#if defined(DOXYGEN)
|
||||
#define ATOMIC_BLOCK
|
||||
#elif defined(MY_RF24_IRQ_PIN)
|
||||
#define ATOMIC_BLOCK for ( ATOMIC_BLOCK_CLEANUP, __hwLock(); \
|
||||
__atomic_loop ; __atomic_loop = 0 )
|
||||
#else
|
||||
#define ATOMIC_BLOCK
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION ATOMIC_BLOCK
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 "MyHwSAMD.h"
|
||||
|
||||
|
||||
/*
|
||||
int8_t pinIntTrigger = 0;
|
||||
void wakeUp() //place to send the interrupts
|
||||
{
|
||||
pinIntTrigger = 1;
|
||||
}
|
||||
void wakeUp2() //place to send the second interrupts
|
||||
{
|
||||
pinIntTrigger = 2;
|
||||
}
|
||||
|
||||
// Watchdog Timer interrupt service routine. This routine is required
|
||||
// to allow automatic WDIF and WDIE bit clearance in hardware.
|
||||
ISR (WDT_vect)
|
||||
{
|
||||
// WDIE & WDIF is cleared in hardware upon entering this ISR
|
||||
wdt_disable();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void hwReadConfigBlock(void* buf, void* adr, size_t length)
|
||||
{
|
||||
uint8_t* dst = static_cast<uint8_t*>(buf);
|
||||
const int offs = reinterpret_cast<int>(adr);
|
||||
(void)eep.read(offs, dst, length);
|
||||
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length)
|
||||
{
|
||||
uint8_t* src = static_cast<uint8_t*>(buf);
|
||||
const int offs = reinterpret_cast<int>(adr);
|
||||
// use update() instead of write() to reduce e2p wear off
|
||||
(void)eep.update(offs, src, length);
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(int adr)
|
||||
{
|
||||
return eep.read(adr);
|
||||
}
|
||||
|
||||
void hwWriteConfig(int adr, uint8_t value)
|
||||
{
|
||||
(void)eep.update(adr, value);
|
||||
}
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
|
||||
const uint8_t eepInit = eep.begin(MY_EXT_EEPROM_TWI_CLOCK);
|
||||
#if defined(SENSEBENDER_GW_SAMD_V1)
|
||||
// check connection to external EEPROM - only sensebender GW
|
||||
return eepInit==0;
|
||||
#else
|
||||
(void)eepInit;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
void hwWatchdogReset(void)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
}
|
||||
|
||||
void hwReboot(void)
|
||||
{
|
||||
NVIC_SystemReset();
|
||||
while (true);
|
||||
}
|
||||
|
||||
int8_t hwSleep(unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
|
||||
unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
(void)memcpy((uint8_t*)uniqueID, (uint32_t *)0x0080A00C, 4);
|
||||
(void)memcpy((uint8_t*)uniqueID + 4, (uint32_t *)0x0080A040, 12);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage()
|
||||
{
|
||||
|
||||
// disable ADC
|
||||
while (ADC->STATUS.bit.SYNCBUSY);
|
||||
ADC->CTRLA.bit.ENABLE = 0x00;
|
||||
|
||||
// internal 1V reference (default)
|
||||
analogReference(AR_INTERNAL1V0);
|
||||
// 12 bit resolution (default)
|
||||
analogWriteResolution(12);
|
||||
// MUXp 0x1B = SCALEDIOVCC/4 => connected to Vcc
|
||||
ADC->INPUTCTRL.bit.MUXPOS = 0x1B ;
|
||||
|
||||
// enable ADC
|
||||
while (ADC->STATUS.bit.SYNCBUSY);
|
||||
ADC->CTRLA.bit.ENABLE = 0x01;
|
||||
// start conversion
|
||||
while (ADC->STATUS.bit.SYNCBUSY);
|
||||
ADC->SWTRIG.bit.START = 1;
|
||||
// clear the Data Ready flag
|
||||
ADC->INTFLAG.bit.RESRDY = 1;
|
||||
// start conversion again, since The first conversion after the reference is changed must not be used.
|
||||
while (ADC->STATUS.bit.SYNCBUSY);
|
||||
ADC->SWTRIG.bit.START = 1;
|
||||
|
||||
// waiting for conversion to complete
|
||||
while (!ADC->INTFLAG.bit.RESRDY);
|
||||
const uint32_t valueRead = ADC->RESULT.reg;
|
||||
|
||||
// disable ADC
|
||||
while (ADC->STATUS.bit.SYNCBUSY);
|
||||
ADC->CTRLA.bit.ENABLE = 0x00;
|
||||
|
||||
return valueRead * 4;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency()
|
||||
{
|
||||
// TODO: currently reporting compile time frequency (in 1/10MHz)
|
||||
return F_CPU / 100000UL;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem()
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
void hwDebugPrint(const char *fmt, ... )
|
||||
{
|
||||
if (MY_SERIALDEVICE) {
|
||||
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
|
||||
snprintf(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;%lu "), C_INTERNAL, I_LOG_MESSAGE,
|
||||
hwMillis());
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
#else
|
||||
// prepend timestamp
|
||||
MY_SERIALDEVICE.print(hwMillis());
|
||||
MY_SERIALDEVICE.print(" ");
|
||||
#endif
|
||||
va_list args;
|
||||
va_start (args, fmt );
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// Truncate message if this is gateway node
|
||||
vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
|
||||
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
|
||||
#else
|
||||
vsnprintf(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#endif
|
||||
va_end (args);
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
// MY_SERIALDEVICE.flush();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 MyHwSAMD_h
|
||||
#define MyHwSAMD_h
|
||||
|
||||
#include "MyHw.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#include <avr/dtostrf.h>
|
||||
|
||||
// defines for sensebender gw variant.h
|
||||
#define MY_EXT_EEPROM_I2C_ADDRESS (0x50u)
|
||||
#define MY_EXT_EEPROM_SIZE (kbits_512)
|
||||
#define MY_EXT_EEPROM_PAGE_SIZE (32u)
|
||||
#define MY_EXT_EEPROM_TWI_CLOCK (twiClock100kHz) // can be set to 400kHz with precaution if other i2c devices on bus
|
||||
|
||||
extEEPROM eep(MY_EXT_EEPROM_SIZE, 1, MY_EXT_EEPROM_PAGE_SIZE,
|
||||
MY_EXT_EEPROM_I2C_ADDRESS); //device size, number of devices, page size
|
||||
|
||||
|
||||
#define min(a,b) ((a)<(b)?(a):(b))
|
||||
#define max(a,b) ((a)>(b)?(a):(b))
|
||||
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
|
||||
|
||||
// Define these as macros to save valuable space
|
||||
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
|
||||
#define hwDigitalRead(__pin) digitalRead(__pin)
|
||||
#define hwPinMode(__pin, __value) pinMode(__pin, __value)
|
||||
#define hwMillis() millis()
|
||||
#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN))
|
||||
|
||||
bool hwInit(void);
|
||||
void hwWatchdogReset(void);
|
||||
void hwReboot(void);
|
||||
void hwReadConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfig(int adr, uint8_t value);
|
||||
uint8_t hwReadConfig(int adr);
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE SerialUSB
|
||||
#endif
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION for ( uint32_t __savePriMask __attribute__((__cleanup__(__priMaskRestore))) = __get_PRIMASK(), __ToDo = __disableIntsRetVal(); __ToDo ; __ToDo = 0 )
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif // #ifdef ARDUINO_ARCH_SAMD
|
||||
@@ -0,0 +1,176 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 "MyHwSTM32F1.h"
|
||||
#include <EEPROM.h>
|
||||
|
||||
|
||||
/*
|
||||
* Pinout STM32F103C8 dev board:
|
||||
* http://wiki.stm32duino.com/images/a/ae/Bluepillpinout.gif
|
||||
*
|
||||
* Wiring RFM69 radio / SPI1
|
||||
* --------------------------------------------------
|
||||
* CLK PA5
|
||||
* MISO PA6
|
||||
* MOSI PA7
|
||||
* CSN PA4
|
||||
* CE NA
|
||||
* IRQ PA3 (default)
|
||||
*
|
||||
* Wiring RF24 radio / SPI1
|
||||
* --------------------------------------------------
|
||||
* CLK PA5
|
||||
* MISO PA6
|
||||
* MOSI PA7
|
||||
* CSN PA4
|
||||
* CE PB0 (default)
|
||||
* IRQ NA
|
||||
*
|
||||
*/
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#endif
|
||||
if (EEPROM.init() == EEPROM_OK) {
|
||||
|
||||
uint16 cnt;
|
||||
EEPROM.count(&cnt);
|
||||
if(cnt>=EEPROM.maxcount()) {
|
||||
// tmp, WIP: format eeprom if full
|
||||
EEPROM.format();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void hwReadConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
uint8_t* dst = static_cast<uint8_t*>(buf);
|
||||
int pos = reinterpret_cast<int>(addr);
|
||||
while (length-- > 0) {
|
||||
*dst++ = EEPROM.read(pos++);
|
||||
}
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
uint8_t* src = static_cast<uint8_t*>(buf);
|
||||
int pos = reinterpret_cast<int>(addr);
|
||||
while (length-- > 0) {
|
||||
EEPROM.write(pos++, *src++);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(const int addr)
|
||||
{
|
||||
uint8_t value;
|
||||
hwReadConfigBlock(&value, reinterpret_cast<void*>(addr), 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
void hwWriteConfig(const int addr, uint8_t value)
|
||||
{
|
||||
hwWriteConfigBlock(&value, reinterpret_cast<void*>(addr), 1);
|
||||
}
|
||||
|
||||
int8_t hwSleep(unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt, uint8_t mode, unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint8_t interrupt1, uint8_t mode1, uint8_t interrupt2, uint8_t mode2,
|
||||
unsigned long ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t* uniqueID)
|
||||
{
|
||||
(void)memcpy((uint8_t*)uniqueID, (uint32_t*)0x1FFFF7E0, 16);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage()
|
||||
{
|
||||
adc_reg_map *regs = ADC1->regs;
|
||||
regs->CR2 |= ADC_CR2_TSVREFE; // enable VREFINT and temp sensor
|
||||
regs->SMPR1 = ADC_SMPR1_SMP17; // sample rate for VREFINT ADC channel
|
||||
return 1200 * 4096 / adc_read(ADC1, 17);
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency()
|
||||
{
|
||||
return F_CPU/100000UL;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem()
|
||||
{
|
||||
//Not yet implemented
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hwDebugPrint(const char *fmt, ...)
|
||||
{
|
||||
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
|
||||
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%d;0;%d;%lu "), C_INTERNAL, I_LOG_MESSAGE,
|
||||
hwMillis());
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
#else
|
||||
// prepend timestamp
|
||||
MY_SERIALDEVICE.print(hwMillis());
|
||||
MY_SERIALDEVICE.print(" ");
|
||||
#endif
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
#ifdef MY_GATEWAY_FEATURE
|
||||
// Truncate message if this is gateway node
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
|
||||
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
|
||||
#else
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#endif
|
||||
va_end(args);
|
||||
MY_SERIALDEVICE.print(fmtBuffer);
|
||||
// Disable flush since current STM32duino implementation performs a reset
|
||||
// instead of an actual flush
|
||||
//MY_SERIALDEVICE.flush();
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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 MyHwSTM32F1_h
|
||||
#define MyHwSTM32F1_h
|
||||
|
||||
#include "MyHw.h"
|
||||
|
||||
#include <libmaple/iwdg.h>
|
||||
#include <itoa.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
// mapping
|
||||
#define snprintf_P snprintf
|
||||
#define vsnprintf_P vsnprintf
|
||||
|
||||
|
||||
// emulated EEPROM (experimental)
|
||||
#define EEPROM_PAGE_SIZE (uint16_t)1024
|
||||
#define EEPROM_SIZE (uint16_t)2048
|
||||
#define EEPROM_START_ADDRESS ((uint32_t)(0x8000000 + 128 * EEPROM_PAGE_SIZE - 2 * EEPROM_PAGE_SIZE))
|
||||
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE Serial
|
||||
#endif
|
||||
|
||||
// Define these as macros to save valuable space
|
||||
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
|
||||
#define hwDigitalRead(__pin) digitalRead(__pin)
|
||||
#define hwPinMode(__pin, __value) pinMode(__pin, __value)
|
||||
#define hwWatchdogReset() iwdg_feed()
|
||||
#define hwReboot() nvic_sys_reset()
|
||||
#define hwMillis() millis()
|
||||
void (*serialEventRun)() = NULL;
|
||||
|
||||
bool hwInit(void);
|
||||
void hwReadConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfigBlock(void* buf, void* adr, size_t length);
|
||||
void hwWriteConfig(const int addr, uint8_t value);
|
||||
uint8_t hwReadConfig(const int addr);
|
||||
|
||||
|
||||
#define hwRandomNumberInit() randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN))
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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
|
||||
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
#if defined(USBCON)
|
||||
#if defined(ARDUINO_ARCH_SAMD)
|
||||
__libc_init_array();
|
||||
USBDevice.init();
|
||||
#endif
|
||||
USBDevice.attach();
|
||||
#endif
|
||||
_begin(); // Startup MySensors library
|
||||
|
||||
for(;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) {
|
||||
loop(); // Call sketch loop
|
||||
}
|
||||
if (serialEventRun) {
|
||||
serialEventRun();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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.
|
||||
*/
|
||||
|
||||
//This may be used to change user task stack size:
|
||||
//#define CONT_STACKSIZE 4096
|
||||
#include "Schedule.h"
|
||||
extern "C" {
|
||||
#include "ets_sys.h"
|
||||
#include "os_type.h"
|
||||
#include "osapi.h"
|
||||
#include "mem.h"
|
||||
#include "user_interface.h"
|
||||
#include "cont.h"
|
||||
}
|
||||
#include <core_version.h>
|
||||
|
||||
#define LOOP_TASK_PRIORITY 1
|
||||
#define LOOP_QUEUE_SIZE 1
|
||||
|
||||
#define OPTIMISTIC_YIELD_TIME_US 16000
|
||||
|
||||
struct rst_info resetInfo;
|
||||
|
||||
extern "C" {
|
||||
extern const uint32_t __attribute__((section(".ver_number"))) core_version =
|
||||
ARDUINO_ESP8266_GIT_VER;
|
||||
const char* core_release =
|
||||
#ifdef ARDUINO_ESP8266_RELEASE
|
||||
ARDUINO_ESP8266_RELEASE;
|
||||
#else
|
||||
NULL;
|
||||
#endif
|
||||
} // extern "C"
|
||||
|
||||
int atexit(void(*func)())
|
||||
{
|
||||
(void)func;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void ets_update_cpu_frequency(int freqmhz);
|
||||
void initVariant() __attribute__((weak));
|
||||
void initVariant()
|
||||
{
|
||||
}
|
||||
|
||||
void preloop_update_frequency() __attribute__((weak));
|
||||
void preloop_update_frequency()
|
||||
{
|
||||
#if defined(F_CPU) && (F_CPU == 160000000L)
|
||||
REG_SET_BIT(0x3ff00014, BIT(0));
|
||||
ets_update_cpu_frequency(160);
|
||||
#endif
|
||||
}
|
||||
|
||||
extern void(*__init_array_start)(void);
|
||||
extern void(*__init_array_end)(void);
|
||||
|
||||
cont_t g_cont __attribute__((aligned(16)));
|
||||
static os_event_t g_loop_queue[LOOP_QUEUE_SIZE];
|
||||
|
||||
static uint32_t g_micros_at_task_start;
|
||||
|
||||
extern "C" void esp_yield()
|
||||
{
|
||||
if (cont_can_yield(&g_cont)) {
|
||||
cont_yield(&g_cont);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void esp_schedule()
|
||||
{
|
||||
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
||||
}
|
||||
|
||||
extern "C" void __yield()
|
||||
{
|
||||
if (cont_can_yield(&g_cont)) {
|
||||
esp_schedule();
|
||||
esp_yield();
|
||||
} else {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void yield(void) __attribute__((weak, alias("__yield")));
|
||||
|
||||
extern "C" void optimistic_yield(uint32_t interval_us)
|
||||
{
|
||||
if (cont_can_yield(&g_cont) &&
|
||||
(system_get_time() - g_micros_at_task_start) > interval_us) {
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
static void loop_wrapper()
|
||||
{
|
||||
static bool setup_done = false;
|
||||
preloop_update_frequency();
|
||||
if (!setup_done) {
|
||||
_begin(); // Startup MySensors library
|
||||
setup_done = true;
|
||||
}
|
||||
_process(); // Process incoming data
|
||||
loop();
|
||||
run_scheduled_functions();
|
||||
esp_schedule();
|
||||
}
|
||||
|
||||
static void loop_task(os_event_t *events)
|
||||
{
|
||||
(void)events;
|
||||
g_micros_at_task_start = system_get_time();
|
||||
cont_run(&g_cont, &loop_wrapper);
|
||||
if (cont_check(&g_cont) != 0) {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
static void do_global_ctors(void)
|
||||
{
|
||||
void(**p)(void) = &__init_array_end;
|
||||
while (p != &__init_array_start) {
|
||||
(*--p)();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void __gdb_init() {}
|
||||
extern "C" void gdb_init(void) __attribute__((weak, alias("__gdb_init")));
|
||||
|
||||
extern "C" void __gdb_do_break() {}
|
||||
extern "C" void gdb_do_break(void) __attribute__((weak, alias("__gdb_do_break")));
|
||||
|
||||
void init_done()
|
||||
{
|
||||
system_set_os_print(1);
|
||||
gdb_init();
|
||||
do_global_ctors();
|
||||
esp_schedule();
|
||||
}
|
||||
|
||||
|
||||
extern "C" void user_init(void)
|
||||
{
|
||||
struct rst_info *rtc_info_ptr = system_get_rst_info();
|
||||
memcpy((void *)&resetInfo, (void *)rtc_info_ptr, sizeof(resetInfo));
|
||||
|
||||
uart_div_modify(0, UART_CLK_FREQ / (115200));
|
||||
|
||||
init();
|
||||
|
||||
initVariant();
|
||||
|
||||
cont_init(&g_cont);
|
||||
|
||||
ets_task(loop_task,
|
||||
LOOP_TASK_PRIORITY, g_loop_queue,
|
||||
LOOP_QUEUE_SIZE);
|
||||
|
||||
system_init_done_cb(&init_done);
|
||||
}
|
||||
@@ -0,0 +1,450 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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
|
||||
|
||||
#include <stdio.h>
|
||||
#include <csignal>
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <getopt.h>
|
||||
#include "log.h"
|
||||
#include "MySensorsCore.h"
|
||||
|
||||
void handle_sigint(int sig)
|
||||
{
|
||||
if (sig == SIGINT) {
|
||||
logNotice("Received SIGINT\n\n");
|
||||
} else if (sig == SIGTERM) {
|
||||
logNotice("Received SIGTERM\n\n");
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
detachInterrupt(MY_RF24_IRQ_PIN);
|
||||
#endif
|
||||
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
MY_SERIALDEVICE.end();
|
||||
#endif
|
||||
|
||||
closelog();
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
static int daemonize(void)
|
||||
{
|
||||
pid_t pid, sid;
|
||||
|
||||
/* Fork off the parent process */
|
||||
pid = fork();
|
||||
if (pid < 0) {
|
||||
logError("fork: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
/* If we got a good PID, then we can exit the parent process. */
|
||||
if (pid > 0) {
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
/* At this point we are executing as the child process */
|
||||
|
||||
/* Change the file mode mask */
|
||||
umask(0);
|
||||
|
||||
/* Create a new SID for the child process */
|
||||
sid = setsid();
|
||||
if (sid < 0) {
|
||||
logError("setsid: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Change the current working directory. This prevents the current
|
||||
directory from being locked; hence not being able to remove it. */
|
||||
if ((chdir("/")) < 0) {
|
||||
logError("chdir(\"/\"): %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (freopen( "/dev/null", "r", stdin) == NULL) {
|
||||
logError("freopen: %s\n", strerror(errno));
|
||||
}
|
||||
if (freopen( "/dev/null", "r", stdout) == NULL) {
|
||||
logError("freopen: %s\n", strerror(errno));
|
||||
}
|
||||
if (freopen( "/dev/null", "r", stderr) == NULL) {
|
||||
logError("freopen: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void print_usage()
|
||||
{
|
||||
printf("Usage: mysgw [options]\n\n" \
|
||||
"Options:\n" \
|
||||
" -h, --help Display a short summary of all program options.\n" \
|
||||
" -d, --debug Enable debug.\n" \
|
||||
" -b, --background Run as a background process.\n"
|
||||
" --gen-soft-hmac-key Generate and print a soft hmac key.\n"
|
||||
" --gen-soft-serial-key Generate and print a soft serial key.\n"
|
||||
" --gen-aes-key Generate and print an aes encryption key.\n"
|
||||
" --print-soft-hmac-key Print the soft hmac key from the config file.\n"
|
||||
" --print-soft-serial-key Print the soft serial key from the config file.\n"
|
||||
" --print-aes-key Print the aes encryption key from the config file.\n"
|
||||
" --set-soft-hmac-key Write a soft hmac key to the config file.\n"
|
||||
" --set-soft-serial-key Write a soft serial key to the config file.\n"
|
||||
" --set-aes-key Write an aes encryption key to the config file.\n");
|
||||
}
|
||||
|
||||
void print_soft_sign_hmac_key(uint8_t *key_ptr = NULL)
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
if (key_ptr == NULL) {
|
||||
hwReadConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
|
||||
key_ptr = key;
|
||||
}
|
||||
|
||||
printf("SOFT_HMAC_KEY | ");
|
||||
for (int i = 0; i < 32; i++) {
|
||||
printf("%02X", key_ptr[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
|
||||
printf("#define MY_SOFT_HMAC_KEY ");
|
||||
for (int i=0; i<32; i++) {
|
||||
printf("%#02X", key_ptr[i]);
|
||||
if (i < 31) {
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void generate_soft_sign_hmac_key()
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
for (int i = 0; i < 32; i++) {
|
||||
key[i] = random(256) ^ micros();
|
||||
unsigned long enter = hwMillis();
|
||||
while (hwMillis() - enter < (unsigned long)2);
|
||||
}
|
||||
|
||||
print_soft_sign_hmac_key(key);
|
||||
|
||||
printf("To use this key, run mysgw with:\n"
|
||||
" --set-soft-hmac-key=");
|
||||
for (int i = 0; i < 32; i++) {
|
||||
printf("%02X", key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void set_soft_sign_hmac_key(char *key_str)
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
if (strlen(key_str) != 64) {
|
||||
printf("invalid key!\n");
|
||||
} else {
|
||||
for (int i = 0; i < 64; ++i) {
|
||||
int n;
|
||||
char c = key_str[i];
|
||||
if (c <= '9') {
|
||||
n = c - '0';
|
||||
} else if (c >= 'a') {
|
||||
n = c - 'a' + 10;
|
||||
} else {
|
||||
n = c - 'A' + 10;
|
||||
}
|
||||
|
||||
if ((i & 0x1) == 0) {
|
||||
key[i/2] = n * 16;
|
||||
} else {
|
||||
key[i/2] += n;
|
||||
}
|
||||
}
|
||||
hwWriteConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_HMAC_KEY_ADDRESS, 32);
|
||||
print_soft_sign_hmac_key();
|
||||
}
|
||||
}
|
||||
|
||||
void print_soft_sign_serial_key(uint8_t *key_ptr = NULL)
|
||||
{
|
||||
uint8_t key[9];
|
||||
|
||||
if (key_ptr == NULL) {
|
||||
hwReadConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
|
||||
key_ptr = key;
|
||||
}
|
||||
|
||||
printf("SOFT_SERIAL | ");
|
||||
for (int i = 0; i < 9; i++) {
|
||||
printf("%02X", key_ptr[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
|
||||
printf("#define MY_SOFT_SERIAL ");
|
||||
for (int i=0; i<9; i++) {
|
||||
printf("%#02X", key_ptr[i]);
|
||||
if (i < 8) {
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void generate_soft_sign_serial_key()
|
||||
{
|
||||
uint8_t key[9];
|
||||
|
||||
for (int i = 0; i < 9; i++) {
|
||||
key[i] = random(256) ^ micros();
|
||||
unsigned long enter = hwMillis();
|
||||
while (hwMillis() - enter < (unsigned long)2);
|
||||
}
|
||||
|
||||
print_soft_sign_serial_key(key);
|
||||
|
||||
printf("To use this key, run mysgw with:\n"
|
||||
" --set-soft-serial-key=");
|
||||
for (int i = 0; i < 9; i++) {
|
||||
printf("%02X", key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void set_soft_sign_serial_key(char *key_str)
|
||||
{
|
||||
uint8_t key[9];
|
||||
|
||||
if (strlen(key_str) != 18) {
|
||||
printf("invalid key!\n");
|
||||
} else {
|
||||
for (int i = 0; i < 18; ++i) {
|
||||
int n;
|
||||
char c = key_str[i];
|
||||
if (c <= '9') {
|
||||
n = c - '0';
|
||||
} else if (c >= 'a') {
|
||||
n = c - 'a' + 10;
|
||||
} else {
|
||||
n = c - 'A' + 10;
|
||||
}
|
||||
|
||||
if ((i & 0x1) == 0) {
|
||||
key[i/2] = n * 16;
|
||||
} else {
|
||||
key[i/2] += n;
|
||||
}
|
||||
}
|
||||
hwWriteConfigBlock(&key, reinterpret_cast<void*>EEPROM_SIGNING_SOFT_SERIAL_ADDRESS, 9);
|
||||
print_soft_sign_serial_key();
|
||||
}
|
||||
}
|
||||
|
||||
void print_aes_key(uint8_t *key_ptr = NULL)
|
||||
{
|
||||
uint8_t key[16];
|
||||
|
||||
if (key_ptr == NULL) {
|
||||
hwReadConfigBlock(&key, reinterpret_cast<void*>EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
|
||||
key_ptr = key;
|
||||
}
|
||||
|
||||
printf("AES_KEY | ");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02X", key_ptr[i]);
|
||||
}
|
||||
printf("\n\n");
|
||||
|
||||
printf("The next line is intended to be used in SecurityPersonalizer.ino:\n");
|
||||
printf("#define MY_AES_KEY ");
|
||||
for (int i=0; i<16; i++) {
|
||||
printf("%#02X", key_ptr[i]);
|
||||
if (i < 15) {
|
||||
printf(",");
|
||||
}
|
||||
}
|
||||
printf("\n\n");
|
||||
}
|
||||
|
||||
void generate_aes_key()
|
||||
{
|
||||
uint8_t key[16];
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
key[i] = random(256) ^ micros();
|
||||
unsigned long enter = hwMillis();
|
||||
while (hwMillis() - enter < (unsigned long)2);
|
||||
}
|
||||
|
||||
print_aes_key(key);
|
||||
|
||||
printf("To use this key, run mysgw with:\n"
|
||||
" --set-aes-key=");
|
||||
for (int i = 0; i < 16; i++) {
|
||||
printf("%02X", key[i]);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
void set_aes_key(char *key_str)
|
||||
{
|
||||
uint8_t key[16];
|
||||
|
||||
if (strlen(key_str) != 32) {
|
||||
printf("invalid key!\n");
|
||||
} else {
|
||||
for (int i = 0; i < 32; ++i) {
|
||||
int n;
|
||||
char c = key_str[i];
|
||||
if (c <= '9') {
|
||||
n = c - '0';
|
||||
} else if (c >= 'a') {
|
||||
n = c - 'a' + 10;
|
||||
} else {
|
||||
n = c - 'A' + 10;
|
||||
}
|
||||
|
||||
if ((i & 0x1) == 0) {
|
||||
key[i/2] = n * 16;
|
||||
} else {
|
||||
key[i/2] += n;
|
||||
}
|
||||
}
|
||||
hwWriteConfigBlock(&key, reinterpret_cast<void*>EEPROM_RF_ENCRYPTION_AES_KEY_ADDRESS, 16);
|
||||
print_aes_key();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt, log_opts, debug = 0, foreground = 1;
|
||||
char *key = NULL;
|
||||
|
||||
/* register the signal handler */
|
||||
signal(SIGINT, handle_sigint);
|
||||
signal(SIGTERM, handle_sigint);
|
||||
|
||||
hwRandomNumberInit();
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"debug", no_argument, 0, 'd'},
|
||||
{"background", no_argument, 0, 'b'},
|
||||
{"gen-soft-hmac-key", no_argument, 0, 'A'},
|
||||
{"gen-soft-serial-key", no_argument, 0, 'B'},
|
||||
{"gen-aes-key", no_argument, 0, 'C'},
|
||||
{"print-soft-hmac-key", no_argument, 0, 'D'},
|
||||
{"print-soft-serial-key", no_argument, 0, 'E'},
|
||||
{"print-aes-key", no_argument, 0, 'F'},
|
||||
{"set-soft-hmac-key", required_argument, 0, 'G'},
|
||||
{"set-soft-serial-key", required_argument, 0, 'H'},
|
||||
{"set-aes-key", required_argument, 0, 'I'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int long_index = 0;
|
||||
while ((opt = getopt_long(argc, argv,"hdbABCDEFGHI", long_options, &long_index )) != -1) {
|
||||
switch (opt) {
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'd':
|
||||
debug = 1;
|
||||
break;
|
||||
case 'b':
|
||||
foreground = 0;
|
||||
break;
|
||||
case 'A':
|
||||
generate_soft_sign_hmac_key();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'B':
|
||||
generate_soft_sign_serial_key();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'C':
|
||||
generate_aes_key();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'D':
|
||||
print_soft_sign_hmac_key();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'E':
|
||||
print_soft_sign_serial_key();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'F':
|
||||
print_aes_key();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'G':
|
||||
key = strdup(optarg);
|
||||
set_soft_sign_hmac_key(key);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'H':
|
||||
key = strdup(optarg);
|
||||
set_soft_sign_serial_key(key);
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'I':
|
||||
key = strdup(optarg);
|
||||
set_aes_key(key);
|
||||
exit(EXIT_SUCCESS);
|
||||
default:
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
log_opts = LOG_CONS;
|
||||
if (foreground && isatty(STDIN_FILENO)) {
|
||||
// Also print syslog to stderror
|
||||
log_opts |= LOG_PERROR;
|
||||
}
|
||||
if (!debug) {
|
||||
// Ignore debug type messages
|
||||
setlogmask(LOG_UPTO (LOG_INFO));
|
||||
}
|
||||
logOpen(log_opts, LOG_USER);
|
||||
|
||||
if (!foreground && !debug) {
|
||||
if (daemonize() != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
logInfo("Starting gateway...\n");
|
||||
logInfo("Protocol version - %s\n", MYSENSORS_LIBRARY_VERSION);
|
||||
|
||||
_begin(); // Startup MySensors library
|
||||
|
||||
for (;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) {
|
||||
loop(); // Call sketch loop
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* 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-2017 Sensnology AB
|
||||
* Full contributor list: https://github.com/mysensors/Arduino/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
|
||||
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
// Force init to be called *first*, i.e. before static object allocation.
|
||||
// Otherwise, statically allocated objects that need libmaple may fail.
|
||||
__attribute__(( constructor (101))) void premain()
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
_begin();
|
||||
|
||||
for(;;) {
|
||||
_process();
|
||||
if (loop) {
|
||||
loop();
|
||||
}
|
||||
if (serialEventRun) {
|
||||
serialEventRun();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user