mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-30 11:59:12 +03:00
добавление mysensors в процессе не рабочая версия
This commit is contained in:
370
lib/MySensors/hal/architecture/AVR/MyHwAVR.cpp
Normal file
370
lib/MySensors/hal/architecture/AVR/MyHwAVR.cpp
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MyHwAVR.h"
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
#define WDTO_SLEEP_FOREVER (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.
|
||||
|
||||
static uint32_t sleepRemainingMs = 0ul;
|
||||
|
||||
void wakeUp1(void)
|
||||
{
|
||||
// Disable sleep. When an interrupt occurs after attachInterrupt,
|
||||
// but before sleeping the CPU would not wake up.
|
||||
// Ref: http://playground.arduino.cc/Learning/ArduinoSleepCode
|
||||
sleep_disable();
|
||||
detachInterrupt(_wakeUp1Interrupt);
|
||||
// First interrupt occurred will be reported only
|
||||
if (INVALID_INTERRUPT_NUM == _wokeUpByInterrupt) {
|
||||
_wokeUpByInterrupt = _wakeUp1Interrupt;
|
||||
}
|
||||
}
|
||||
void wakeUp2(void)
|
||||
{
|
||||
sleep_disable();
|
||||
detachInterrupt(_wakeUp2Interrupt);
|
||||
// First interrupt occurred will be reported only
|
||||
if (INVALID_INTERRUPT_NUM == _wokeUpByInterrupt) {
|
||||
_wokeUpByInterrupt = _wakeUp2Interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool interruptWakeUp(void)
|
||||
{
|
||||
return _wokeUpByInterrupt != INVALID_INTERRUPT_NUM;
|
||||
}
|
||||
|
||||
void clearPendingInterrupt(const uint8_t interrupt)
|
||||
{
|
||||
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
|
||||
const 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);
|
||||
}
|
||||
|
||||
uint32_t hwInternalSleep(uint32_t 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (interruptWakeUp()) {
|
||||
return ms;
|
||||
}
|
||||
return 0ul;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint32_t ms)
|
||||
{
|
||||
// Return what woke the mcu.
|
||||
// Default: no interrupt triggered, timer wake up
|
||||
int8_t ret = MY_WAKE_UP_BY_TIMER;
|
||||
sleepRemainingMs = 0ul;
|
||||
if (ms > 0u) {
|
||||
// sleep for defined time
|
||||
sleepRemainingMs = hwInternalSleep(ms);
|
||||
} else {
|
||||
// sleep until ext interrupt triggered
|
||||
hwPowerDown(WDTO_SLEEP_FOREVER);
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
return hwSleep(interrupt, mode, INVALID_INTERRUPT_NUM, 0u, ms);
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t ms)
|
||||
{
|
||||
// ATMega328P supports following modes to wake from sleep: LOW, CHANGE, RISING, FALLING
|
||||
// Datasheet states only LOW can be used with INT0/1 to wake from sleep, which is incorrect.
|
||||
// Ref: http://gammon.com.au/interrupts
|
||||
|
||||
// Disable interrupts until going to sleep, otherwise interrupts occurring between attachInterrupt()
|
||||
// and sleep might cause the ATMega to not wakeup from sleep as interrupt has already be handled!
|
||||
cli();
|
||||
// attach interrupts
|
||||
_wakeUp1Interrupt = interrupt1;
|
||||
_wakeUp2Interrupt = interrupt2;
|
||||
|
||||
// Attach external interrupt handlers, and clear any pending interrupt flag
|
||||
// to prevent waking immediately again.
|
||||
// Ref: https://forum.arduino.cc/index.php?topic=59217.0
|
||||
if (interrupt1 != INVALID_INTERRUPT_NUM) {
|
||||
clearPendingInterrupt(interrupt1);
|
||||
attachInterrupt(interrupt1, wakeUp1, mode1);
|
||||
}
|
||||
if (interrupt2 != INVALID_INTERRUPT_NUM) {
|
||||
clearPendingInterrupt(interrupt2);
|
||||
attachInterrupt(interrupt2, wakeUp2, mode2);
|
||||
}
|
||||
|
||||
sleepRemainingMs = 0ul;
|
||||
if (ms > 0u) {
|
||||
// sleep for defined time
|
||||
sleepRemainingMs = 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;
|
||||
}
|
||||
|
||||
uint32_t hwGetSleepRemaining(void)
|
||||
{
|
||||
return sleepRemainingMs;
|
||||
}
|
||||
|
||||
inline void hwRandomNumberInit(void)
|
||||
{
|
||||
// This function initializes the random number generator with a seed
|
||||
// of 32 bits. This method is good enough to earn FIPS 140-2 conform
|
||||
// random data. This should reach to generate 32 Bit for randomSeed().
|
||||
uint32_t seed = 0;
|
||||
uint32_t timeout = millis() + 20;
|
||||
|
||||
// Trigger floating effect of an unconnected pin
|
||||
pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP);
|
||||
pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT);
|
||||
delay(10);
|
||||
|
||||
// Generate 32 bits of datas
|
||||
for (uint8_t i=0; i<32; i++) {
|
||||
const int pinValue = analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN);
|
||||
// Wait until the analog value has changed
|
||||
while ((pinValue == analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN)) && (timeout>=millis())) {
|
||||
seed ^= (millis() << i);
|
||||
// Check of data generation is slow
|
||||
if (timeout<=millis()) {
|
||||
// Trigger pin again
|
||||
pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT_PULLUP);
|
||||
pinMode(MY_SIGNING_SOFT_RANDOMSEED_PIN, INPUT);
|
||||
// Pause a short while
|
||||
delay(seed % 10);
|
||||
timeout = millis() + 20;
|
||||
}
|
||||
}
|
||||
}
|
||||
randomSeed(seed);
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
// padding
|
||||
(void)memset(uniqueID, MY_HWID_PADDING_BYTE, sizeof(unique_id_t));
|
||||
// no unique ID for non-PB AVR, use HW specifics for diversification
|
||||
*((uint8_t *)uniqueID) = SIGNATURE_2;
|
||||
*((uint8_t *)uniqueID + 1) = SIGNATURE_1;
|
||||
*((uint8_t *)uniqueID + 2) = SIGNATURE_0;
|
||||
*((uint8_t *)uniqueID + 3) = OSCCAL;
|
||||
#if defined(__AVR_ATmega328PB__)
|
||||
// ATMEGA328PB specifics, has unique ID
|
||||
for(uint8_t idx = 0; idx < 10; idx++) {
|
||||
*((uint8_t *)uniqueID + 4 + idx) = boot_signature_byte_get(0xE + idx);
|
||||
}
|
||||
return true; // unique ID returned
|
||||
#else
|
||||
return false; // no unique ID returned
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
// 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(void)
|
||||
{
|
||||
cli();
|
||||
// save WDT & timer settings
|
||||
const uint8_t WDTsave = WDTCSR;
|
||||
const uint8_t TCCR1Asave = TCCR1A;
|
||||
const uint8_t TCCR1Bsave = TCCR1B;
|
||||
const uint8_t TCCR1Csave = TCCR1C;
|
||||
// setup timer1
|
||||
TIFR1 = 0xFF;
|
||||
TCNT1 = 0;
|
||||
TCCR1A = 0;
|
||||
TCCR1C = 0;
|
||||
// set wdt
|
||||
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();
|
||||
const uint16_t result = TCNT1 * 2048UL / 100000UL;
|
||||
// restore timer settings
|
||||
TCCR1A = TCCR1Asave;
|
||||
TCCR1B = TCCR1Bsave;
|
||||
TCCR1C = TCCR1Csave;
|
||||
// return frequency in 1/10MHz (accuracy +- 10%)
|
||||
return result;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
#if defined(__AVR_ATmega168A__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328BP__) || defined(__AVR_ATmega32U4__)
|
||||
// Set the internal reference and mux.
|
||||
ADMUX = (_BV(REFS1) | _BV(REFS0) | _BV(MUX3));
|
||||
ADCSRA |= _BV(ADEN); // enable the ADC
|
||||
delay(20); // wait for voltages to become stable.
|
||||
ADCSRA |= _BV(ADSC); // Start the ADC
|
||||
// Wait until conversion done
|
||||
while (bit_is_set(ADCSRA, ADSC));
|
||||
// temperature is in degrees Celsius
|
||||
return static_cast<int8_t>((ADCW - MY_AVR_TEMPERATURE_OFFSET) / MY_AVR_TEMPERATURE_GAIN);
|
||||
#else
|
||||
return -127; // not available
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
extern int __heap_start, *__brkval;
|
||||
int v;
|
||||
return (int) &v - (__brkval == 0 ? (int) &__heap_start : (int) __brkval);
|
||||
}
|
||||
92
lib/MySensors/hal/architecture/AVR/MyHwAVR.h
Normal file
92
lib/MySensors/hal/architecture/AVR/MyHwAVR.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MyHwAVR_h
|
||||
#define MyHwAVR_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 <avr/boot.h>
|
||||
#include <util/atomic.h>
|
||||
#include <SPI.h>
|
||||
|
||||
// Fast IO driver
|
||||
#include "drivers/DigitalWriteFast/digitalWriteFast.h"
|
||||
|
||||
// SOFTSPI
|
||||
#ifdef MY_SOFTSPI
|
||||
#include "hal/architecture/AVR/drivers/DigitalIO/DigitalIO.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
// AVR temperature calibration reference: http://ww1.microchip.com/downloads/en/AppNotes/Atmel-8108-Calibration-of-the-AVRs-Internal-Temperature-Reference_ApplicationNote_AVR122.pdf
|
||||
#ifndef MY_AVR_TEMPERATURE_OFFSET
|
||||
#define MY_AVR_TEMPERATURE_OFFSET (324.31f)
|
||||
#endif
|
||||
|
||||
#ifndef MY_AVR_TEMPERATURE_GAIN
|
||||
#define MY_AVR_TEMPERATURE_GAIN (1.22f)
|
||||
#endif
|
||||
|
||||
// Define these as macros to save valuable space
|
||||
#define hwDigitalWrite(__pin, __value) digitalWriteFast(__pin, __value)
|
||||
#define hwDigitalRead(__pin) digitalReadFast(__pin)
|
||||
#define hwPinMode(__pin, __value) pinModeFast(__pin, __value)
|
||||
|
||||
bool hwInit(void);
|
||||
|
||||
#define hwWatchdogReset() wdt_reset()
|
||||
#define hwReboot() wdt_enable(WDTO_15MS); while (1)
|
||||
#define hwMillis() millis()
|
||||
#define hwReadConfig(__pos) eeprom_read_byte((const uint8_t *)__pos)
|
||||
#define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t *)__pos, (uint8_t)__val)
|
||||
#define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void *)__buf, (const void *)__pos, (uint32_t)__length)
|
||||
#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((const void *)__buf, (void *)__pos, (uint32_t)__length)
|
||||
|
||||
inline void hwRandomNumberInit(void);
|
||||
uint32_t hwInternalSleep(uint32_t ms);
|
||||
|
||||
#if defined(MY_SOFTSPI)
|
||||
SoftSPI<MY_SOFT_SPI_MISO_PIN, MY_SOFT_SPI_MOSI_PIN, MY_SOFT_SPI_SCK_PIN, 0> hwSPI; //!< hwSPI
|
||||
#else
|
||||
#define hwSPI SPI //!< hwSPI
|
||||
#endif
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif
|
||||
39
lib/MySensors/hal/architecture/AVR/MyMainAVR.cpp
Normal file
39
lib/MySensors/hal/architecture/AVR/MyMainAVR.cpp
Normal 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;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Fast Digital I/O functions
|
||||
*
|
||||
*/
|
||||
#ifndef DigitalIO_h
|
||||
#define DigitalIO_h 1
|
||||
//------------------------------------------------------------------------------
|
||||
/** DigitalPin version YYYYMMDD */
|
||||
#define DIGITAL_IO_VERSION 20151127
|
||||
//------------------------------------------------------------------------------
|
||||
#include "DigitalPin.h"
|
||||
#include "I2cConstants.h"
|
||||
#include "PinIO.h"
|
||||
#include "SoftI2cMaster.h"
|
||||
#include "SoftSPI.h"
|
||||
#endif // DigitalIO_h
|
||||
@@ -0,0 +1,416 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Fast Digital Pin functions
|
||||
*
|
||||
* @defgroup digitalPin Fast Pin I/O
|
||||
* @details Fast Digital I/O functions and template class.
|
||||
* @{
|
||||
*/
|
||||
#ifndef DigitalPin_h
|
||||
#define DigitalPin_h
|
||||
#if defined(__AVR__) || defined(DOXYGEN)
|
||||
#include <avr/io.h>
|
||||
/** GpioPinMap type */
|
||||
struct GpioPinMap_t {
|
||||
volatile uint8_t* pin; /**< address of PIN for this pin */
|
||||
volatile uint8_t* ddr; /**< address of DDR for this pin */
|
||||
volatile uint8_t* port; /**< address of PORT for this pin */
|
||||
uint8_t mask; /**< bit mask for this pin */
|
||||
};
|
||||
|
||||
/** Initializer macro. */
|
||||
#define GPIO_PIN(reg, bit) {&PIN##reg, &DDR##reg, &PORT##reg, 1 << bit}
|
||||
|
||||
// Include pin map for current board.
|
||||
#include "boards/GpioPinMap.h"
|
||||
//------------------------------------------------------------------------------
|
||||
/** generate bad pin number error */
|
||||
void badPinNumber(void)
|
||||
__attribute__((error("Pin number is too large or not a constant")));
|
||||
//------------------------------------------------------------------------------
|
||||
/** Check for valid pin number
|
||||
* @param[in] pin Number of pin to be checked.
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void badPinCheck(uint8_t pin)
|
||||
{
|
||||
if (!__builtin_constant_p(pin) || pin >= NUM_DIGITAL_PINS) {
|
||||
badPinNumber();
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** DDR register address
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return register address
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
volatile uint8_t* ddrReg(uint8_t pin)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
return GpioPinMap[pin].ddr;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Bit mask for pin
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return mask
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
uint8_t pinMask(uint8_t pin)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
return GpioPinMap[pin].mask;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** PIN register address
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return register address
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
volatile uint8_t* pinReg(uint8_t pin)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
return GpioPinMap[pin].pin;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** PORT register address
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return register address
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
volatile uint8_t* portReg(uint8_t pin)
|
||||
{
|
||||
badPinCheck(pin);
|
||||
return GpioPinMap[pin].port;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Fast write helper.
|
||||
* @param[in] address I/O register address
|
||||
* @param[in] mask bit mask for pin
|
||||
* @param[in] level value for bit
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastBitWriteSafe(volatile uint8_t* address, uint8_t mask, bool level)
|
||||
{
|
||||
uint8_t s;
|
||||
if (address > reinterpret_cast<uint8_t*>(0X3F)) {
|
||||
s = SREG;
|
||||
cli();
|
||||
}
|
||||
if (level) {
|
||||
*address |= mask;
|
||||
} else {
|
||||
*address &= ~mask;
|
||||
}
|
||||
if (address > reinterpret_cast<uint8_t*>(0X3F)) {
|
||||
SREG = s;
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Read pin value.
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return value read
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
bool fastDigitalRead(uint8_t pin)
|
||||
{
|
||||
return *pinReg(pin) & pinMask(pin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Toggle a pin.
|
||||
* @param[in] pin Arduino pin number
|
||||
*
|
||||
* If the pin is in output mode toggle the pin level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalToggle(uint8_t pin)
|
||||
{
|
||||
if (pinReg(pin) > reinterpret_cast<uint8_t*>(0X3F)) {
|
||||
// must write bit to high address port
|
||||
*pinReg(pin) = pinMask(pin);
|
||||
} else {
|
||||
// will compile to sbi and PIN register will not be read.
|
||||
*pinReg(pin) |= pinMask(pin);
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set pin value.
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] level value to write
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, bool level)
|
||||
{
|
||||
fastBitWriteSafe(portReg(pin), pinMask(pin), level);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Write the DDR register.
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] level value to write
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDdrWrite(uint8_t pin, bool level)
|
||||
{
|
||||
fastBitWriteSafe(ddrReg(pin), pinMask(pin), level);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set pin mode.
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] mode INPUT, OUTPUT, or INPUT_PULLUP.
|
||||
*
|
||||
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
|
||||
* and disabled if the mode is INPUT.
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastPinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
fastDdrWrite(pin, mode == OUTPUT);
|
||||
if (mode != OUTPUT) {
|
||||
fastDigitalWrite(pin, mode == INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
#else // defined(__AVR__)
|
||||
#if defined(CORE_TEENSY)
|
||||
//------------------------------------------------------------------------------
|
||||
/** read pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return value read
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
bool fastDigitalRead(uint8_t pin)
|
||||
{
|
||||
return *portInputRegister(pin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] level value to write
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, bool value)
|
||||
{
|
||||
if (value) {
|
||||
*portSetRegister(pin) = 1;
|
||||
} else {
|
||||
*portClearRegister(pin) = 1;
|
||||
}
|
||||
}
|
||||
#elif defined(__SAM3X8E__) || defined(__SAM3X8H__)
|
||||
//------------------------------------------------------------------------------
|
||||
/** read pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return value read
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
bool fastDigitalRead(uint8_t pin)
|
||||
{
|
||||
return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] level value to write
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, bool value)
|
||||
{
|
||||
if (value) {
|
||||
g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
|
||||
} else {
|
||||
g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
|
||||
}
|
||||
}
|
||||
#elif defined(ESP8266)
|
||||
//------------------------------------------------------------------------------
|
||||
/** Set pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] val value to write
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
void fastDigitalWrite(uint8_t pin, uint8_t val)
|
||||
{
|
||||
if (pin < 16) {
|
||||
if (val) {
|
||||
GPOS = (1 << pin);
|
||||
} else {
|
||||
GPOC = (1 << pin);
|
||||
}
|
||||
} else if (pin == 16) {
|
||||
if (val) {
|
||||
GP16O |= 1;
|
||||
} else {
|
||||
GP16O &= ~1;
|
||||
}
|
||||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Read pin value
|
||||
* @param[in] pin Arduino pin number
|
||||
* @return value read
|
||||
*/
|
||||
static inline __attribute__((always_inline))
|
||||
bool fastDigitalRead(uint8_t pin)
|
||||
{
|
||||
if (pin < 16) {
|
||||
return GPIP(pin);
|
||||
} else if (pin == 16) {
|
||||
return GP16I & 0x01;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#else // CORE_TEENSY
|
||||
//------------------------------------------------------------------------------
|
||||
inline void fastDigitalWrite(uint8_t pin, bool value)
|
||||
{
|
||||
digitalWrite(pin, value);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline bool fastDigitalRead(uint8_t pin)
|
||||
{
|
||||
return digitalRead(pin);
|
||||
}
|
||||
#endif // CORE_TEENSY
|
||||
//------------------------------------------------------------------------------
|
||||
inline void fastDigitalToggle(uint8_t pin)
|
||||
{
|
||||
fastDigitalWrite(pin, !fastDigitalRead(pin));
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
inline void fastPinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
pinMode(pin, mode);
|
||||
}
|
||||
#endif // __AVR__
|
||||
//------------------------------------------------------------------------------
|
||||
/** set pin configuration
|
||||
* @param[in] pin Arduino pin number
|
||||
* @param[in] mode mode INPUT or OUTPUT.
|
||||
* @param[in] level If mode is output, set level high/low.
|
||||
* If mode is input, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
#define fastPinConfig(pin, mode, level)\
|
||||
{fastPinMode(pin, mode); fastDigitalWrite(pin, level);}
|
||||
//==============================================================================
|
||||
/**
|
||||
* @class DigitalPin
|
||||
* @brief Fast digital port I/O
|
||||
*/
|
||||
template<uint8_t PinNumber>
|
||||
class DigitalPin
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Constructor */
|
||||
DigitalPin() {}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Asignment operator.
|
||||
* @param[in] value If true set the pin's level high else set the
|
||||
* pin's level low.
|
||||
*
|
||||
* @return This DigitalPin instance.
|
||||
*/
|
||||
inline DigitalPin & operator = (bool value) __attribute__((always_inline))
|
||||
{
|
||||
write(value);
|
||||
return *this;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Parenthesis operator.
|
||||
* @return Pin's level
|
||||
*/
|
||||
inline operator bool () const __attribute__((always_inline))
|
||||
{
|
||||
return read();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Set pin configuration.
|
||||
* @param[in] mode: INPUT or OUTPUT.
|
||||
* @param[in] level If mode is OUTPUT, set level high/low.
|
||||
* If mode is INPUT, enable or disable the pin's 20K pullup.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void config(uint8_t mode, bool level)
|
||||
{
|
||||
fastPinConfig(PinNumber, mode, level);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void high()
|
||||
{
|
||||
write(true);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void low()
|
||||
{
|
||||
write(false);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/**
|
||||
* Set pin mode.
|
||||
* @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
|
||||
*
|
||||
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
|
||||
* and disabled if the mode is INPUT.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void mode(uint8_t mode)
|
||||
{
|
||||
fastPinMode(PinNumber, mode);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** @return Pin's level. */
|
||||
inline __attribute__((always_inline))
|
||||
bool read() const
|
||||
{
|
||||
return fastDigitalRead(PinNumber);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Toggle a pin.
|
||||
*
|
||||
* If the pin is in output mode toggle the pin's level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void toggle()
|
||||
{
|
||||
fastDigitalToggle(PinNumber);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Write the pin's level.
|
||||
* @param[in] value If true set the pin's level high else set the
|
||||
* pin's level low.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void write(bool value)
|
||||
{
|
||||
fastDigitalWrite(PinNumber, value);
|
||||
}
|
||||
};
|
||||
#endif // DigitalPin_h
|
||||
/** @} */
|
||||
@@ -0,0 +1,62 @@
|
||||
/* Arduino I2C Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino I2C Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino I2C Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file I2cConstants.h
|
||||
* @brief Two Wire Interface constants.
|
||||
*
|
||||
* @defgroup twoWire I2C constants
|
||||
* @details Two Wire Interface library.
|
||||
* @{
|
||||
*/
|
||||
#ifndef I2cConstants_h
|
||||
#define I2cConstants_h
|
||||
#include <inttypes.h>
|
||||
|
||||
/** Option argument for transfer() of transferContinue() to continue a
|
||||
an I2C operation. */
|
||||
const uint8_t I2C_CONTINUE = 0;
|
||||
|
||||
/** Option argument for transfer() of transferContinue() to end a
|
||||
transfer with a STOP condition */
|
||||
const uint8_t I2C_STOP = 1;
|
||||
|
||||
/** Option argument for transfer() of transferContinue() to end a
|
||||
transfer with a repeated START condition */
|
||||
const uint8_t I2C_REP_START = 2;
|
||||
|
||||
/** Set I2C bus speed to 100 kHz. Used by TwiMaster class. */
|
||||
const uint8_t I2C_100KHZ = 0;
|
||||
|
||||
/** Set I2C bus speed to 400 kHz. Used by TwiMaster class. */
|
||||
const uint8_t I2C_400KHZ = 1;
|
||||
|
||||
/** Bit to OR with address for a read operation. */
|
||||
const uint8_t I2C_READ = 1;
|
||||
|
||||
/** Bit to OR with address for write operation. */
|
||||
const uint8_t I2C_WRITE = 0;
|
||||
|
||||
/** Disable internal pull-ups on SDA and SCL. Used by TwiMaster class. */
|
||||
const uint8_t I2C_NO_PULLUPS = 0;
|
||||
|
||||
/** Enable internal pull-ups on SDA and SCL. Used by TwiMaster class. */
|
||||
const uint8_t I2C_INTERNAL_PULLUPS = 1;
|
||||
#endif // I2cConstants_h
|
||||
/** @} */
|
||||
@@ -0,0 +1,75 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Digital AVR port I/O with runtime pin number.
|
||||
*
|
||||
* @defgroup runtimeDigital Runtime Pin I/O
|
||||
* @details Two Wire Interface library.
|
||||
* @{
|
||||
*/
|
||||
#if defined(__AVR__) || defined(DOXYGEN) // AVR only
|
||||
#include "PinIO.h"
|
||||
#include <util/atomic.h>
|
||||
#include <Arduino.h>
|
||||
//==============================================================================
|
||||
/** Constructor
|
||||
* @param[in] pin Pin assigned to this object.
|
||||
*/
|
||||
PinIO::PinIO(uint8_t pin)
|
||||
{
|
||||
begin(pin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Initialize pin bit mask and port address.
|
||||
* @param[in] pin Arduino board pin number.
|
||||
* @return true for success or false if invalid pin number.
|
||||
*/
|
||||
bool PinIO::begin(uint8_t pin)
|
||||
{
|
||||
if (pin >= NUM_DIGITAL_PINS) {
|
||||
return false;
|
||||
}
|
||||
uint8_t port = digitalPinToPort(pin);
|
||||
pinReg_ = portInputRegister(port);
|
||||
bit_ = digitalPinToBitMask(pin);
|
||||
mask_ = ~bit_;
|
||||
portReg_ = pinReg_ + 2;
|
||||
return true;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/** Configure the pin.
|
||||
*
|
||||
* @param[in] mode: INPUT or OUTPUT.
|
||||
* @param[in] level If mode is OUTPUT, set level high/low.
|
||||
* If mode is INPUT, enable or disable the pin's 20K pullup.
|
||||
*
|
||||
* This function may be used with interrupts enabled or disabled.
|
||||
* The previous interrupt state will be restored.
|
||||
*/
|
||||
void PinIO::config(uint8_t mode, bool level)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
|
||||
modeI(mode);
|
||||
writeI(level);
|
||||
}
|
||||
}
|
||||
#endif // __AVR__
|
||||
/** @} */
|
||||
194
lib/MySensors/hal/architecture/AVR/drivers/DigitalIO/PinIO.h
Normal file
194
lib/MySensors/hal/architecture/AVR/drivers/DigitalIO/PinIO.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Digital AVR port I/O with runtime pin number.
|
||||
*
|
||||
* @defgroup runtimeDigital Runtime Pin I/O
|
||||
* @details Two Wire Interface library.
|
||||
* @{
|
||||
*/
|
||||
#ifndef PinIO_h
|
||||
#define PinIO_h
|
||||
#if defined(__AVR__) || defined(DOXYGEN) // AVR only
|
||||
#include <Arduino.h>
|
||||
#include <util/atomic.h>
|
||||
#include <avr/io.h>
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @class PinIO
|
||||
* @brief AVR port I/O with runtime pin numbers.
|
||||
*/
|
||||
class PinIO
|
||||
{
|
||||
public:
|
||||
/** Create a PinIO object with no assigned pin. */
|
||||
// cppcheck-suppress uninitMemberVar
|
||||
PinIO() : bit_(0), mask_(0XFF) {}
|
||||
explicit PinIO(uint8_t pin);
|
||||
bool begin(uint8_t pin);
|
||||
void config(uint8_t mode, bool data);
|
||||
//----------------------------------------------------------------------------
|
||||
/** @return Pin's level */
|
||||
inline __attribute__((always_inline))
|
||||
bool read()
|
||||
{
|
||||
return *pinReg_ & bit_;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** toggle a pin
|
||||
*
|
||||
* If the pin is in output mode toggle the pin's level.
|
||||
* If the pin is in input mode toggle the state of the 20K pullup.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void toggle()
|
||||
{
|
||||
*pinReg_ = bit_;
|
||||
}
|
||||
//============================================================================
|
||||
/**
|
||||
* Set pin high if output mode or enable 20K pullup if input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void highI()
|
||||
{
|
||||
writeI(1);
|
||||
}
|
||||
/**
|
||||
* Set pin low if output mode or disable 20K pullup if input mode.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void lowI()
|
||||
{
|
||||
writeI(0);
|
||||
}
|
||||
/** Set pin mode.
|
||||
*
|
||||
* @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
|
||||
*
|
||||
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
|
||||
* and disabled if the mode is INPUT.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void modeI(uint8_t mode)
|
||||
{
|
||||
volatile uint8_t* ddrReg = pinReg_ + 1;
|
||||
*ddrReg = mode == OUTPUT ? *ddrReg | bit_ : *ddrReg & mask_;
|
||||
if (mode != OUTPUT) {
|
||||
writeI(mode == INPUT_PULLUP);
|
||||
}
|
||||
}
|
||||
|
||||
/** Write pin.
|
||||
*
|
||||
* @param[in] level If output mode set pin high if true else low.
|
||||
* If input mode enable 20K pullup if true else disable pullup.
|
||||
*
|
||||
* This function must be called with interrupts disabled.
|
||||
* This function will not change the interrupt state.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void writeI(bool level)
|
||||
{
|
||||
*portReg_ = level ? *portReg_ | bit_ : *portReg_ & mask_;
|
||||
}
|
||||
//============================================================================
|
||||
/**
|
||||
* Set pin level high if output mode or enable 20K pullup if input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void high()
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
highI();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pin level low if output mode or disable 20K pullup if input mode.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void low()
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
lowI();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set pin mode.
|
||||
*
|
||||
* @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
|
||||
*
|
||||
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
|
||||
* and disabled if the mode is INPUT.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void mode(uint8_t mode)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
modeI(mode);
|
||||
}
|
||||
}
|
||||
|
||||
/** Write pin.
|
||||
*
|
||||
* @param[in] level If output mode set pin high if true else low.
|
||||
* If input mode enable 20K pullup if true else disable pullup.
|
||||
*
|
||||
* This function will enable interrupts. This function should not be
|
||||
* called in an ISR or where interrupts are disabled.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void write(bool level)
|
||||
{
|
||||
ATOMIC_BLOCK(ATOMIC_FORCEON) {
|
||||
writeI(level);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
private:
|
||||
uint8_t bit_;
|
||||
uint8_t mask_;
|
||||
volatile uint8_t* pinReg_;
|
||||
volatile uint8_t* portReg_;
|
||||
};
|
||||
#endif // __AVR__
|
||||
#endif // PinIO_h
|
||||
/** @} */
|
||||
@@ -0,0 +1,252 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(__AVR__) || defined(DOXYGEN) // AVR only
|
||||
/**
|
||||
* @file
|
||||
* @brief AVR Software I2C library
|
||||
*
|
||||
* @defgroup softI2C Software I2C
|
||||
* @details Software Two Wire Interface library.
|
||||
* @{
|
||||
*/
|
||||
#include "SoftI2cMaster.h"
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Start an I2C transfer with possible continuation.
|
||||
*
|
||||
* @param[in] addrRW I2C slave address plus R/W bit.
|
||||
* The I2C slave address is in the high seven bits
|
||||
* and is ORed with on of the following:
|
||||
* - I2C_READ for a read transfer.
|
||||
* - I2C_WRITE for a write transfer.
|
||||
* .
|
||||
* @param[in,out] buf Source or destination for transfer.
|
||||
* @param[in] nbytes Number of bytes to transfer (may be zero).
|
||||
* @param[in] option Option for ending the transfer, one of:
|
||||
* - I2C_STOP end the transfer with an I2C stop
|
||||
* condition.
|
||||
* - I2C_REP_START end the transfer with an I2C
|
||||
* repeated start condition.
|
||||
* - I2C_CONTINUE allow additional transferContinue()
|
||||
* calls.
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool I2cMasterBase::transfer(uint8_t addrRW,
|
||||
void *buf, size_t nbytes, uint8_t option)
|
||||
{
|
||||
if (_state != STATE_REP_START) {
|
||||
start();
|
||||
}
|
||||
if (!write(addrRW)) {
|
||||
_state = (addrRW & I2C_READ) ? STATE_RX_ADDR_NACK : STATE_TX_ADDR_NACK;
|
||||
return false;
|
||||
}
|
||||
_state = (addrRW & I2C_READ) ? STATE_RX_DATA : STATE_TX_DATA;
|
||||
return transferContinue(buf, nbytes, option);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Continue an I2C transfer.
|
||||
*
|
||||
* @param[in,out] buf Source or destination for transfer.
|
||||
* @param[in] nbytes Number of bytes to transfer (may be zero).
|
||||
* @param[in] option Option for ending the transfer, one of:
|
||||
* - I2C_STOP end the transfer with an I2C stop
|
||||
* condition.
|
||||
* - I2C_REP_START end the transfer with an I2C
|
||||
* repeated start condition.
|
||||
* - I2C_CONTINUE allow additional transferContinue()
|
||||
* calls.
|
||||
* .
|
||||
* @return true for success else false.
|
||||
*/
|
||||
bool I2cMasterBase::transferContinue(void *buf, size_t nbytes, uint8_t option)
|
||||
{
|
||||
uint8_t* p = reinterpret_cast<uint8_t*>(buf);
|
||||
if (_state == STATE_RX_DATA) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
p[i] = read(i == (nbytes - 1) && option != I2C_CONTINUE);
|
||||
}
|
||||
} else if (_state == STATE_TX_DATA) {
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
if (!write(p[i])) {
|
||||
_state = STATE_TX_DATA_NACK;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (option == I2C_STOP) {
|
||||
stop();
|
||||
_state = STATE_STOP;
|
||||
} else if (option == I2C_REP_START) {
|
||||
start();
|
||||
_state = STATE_STOP;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
//==============================================================================
|
||||
// WARNING don't change SoftI2cMaster unless you verify the change with a scope
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Constructor, initialize SCL/SDA pins and set the bus high.
|
||||
*
|
||||
* @param[in] sdaPin The software SDA pin number.
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
SoftI2cMaster::SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin)
|
||||
{
|
||||
begin(sclPin, sdaPin);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* Initialize SCL/SDA pins and set the bus high.
|
||||
*
|
||||
* @param[in] sdaPin The software SDA pin number.
|
||||
*
|
||||
* @param[in] sclPin The software SCL pin number.
|
||||
*/
|
||||
void SoftI2cMaster::begin(uint8_t sclPin, uint8_t sdaPin)
|
||||
{
|
||||
uint8_t port;
|
||||
|
||||
// Get bit mask and address of scl registers.
|
||||
_sclBit = digitalPinToBitMask(sclPin);
|
||||
port = digitalPinToPort(sclPin);
|
||||
_sclDDR = portModeRegister(port);
|
||||
volatile uint8_t* sclOutReg = portOutputRegister(port);
|
||||
|
||||
// Get bit mask and address of sda registers.
|
||||
_sdaBit = digitalPinToBitMask(sdaPin);
|
||||
port = digitalPinToPort(sdaPin);
|
||||
_sdaDDR = portModeRegister(port);
|
||||
_sdaInReg = portInputRegister(port);
|
||||
volatile uint8_t* sdaOutReg = portOutputRegister(port);
|
||||
|
||||
// Clear PORT bit for scl and sda.
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
*sclOutReg &= ~_sclBit;
|
||||
*sdaOutReg &= ~_sdaBit;
|
||||
SREG = s;
|
||||
|
||||
// Set scl and sda high.
|
||||
writeScl(HIGH);
|
||||
writeSda(HIGH);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* Read a byte and send ACK if more reads follow else NACK to terminate read.
|
||||
*
|
||||
* @param[in] last Set true to terminate the read else false.
|
||||
*
|
||||
* @return The byte read from the I2C bus.
|
||||
*/
|
||||
uint8_t SoftI2cMaster::read(uint8_t last)
|
||||
{
|
||||
uint8_t b = 0;
|
||||
|
||||
// Set sda to high Z mode for read.
|
||||
writeSda(HIGH);
|
||||
// Read a byte.
|
||||
for (uint8_t i = 0; i < 8; i++) {
|
||||
// Don't change this loop unless you verify the change with a scope.
|
||||
b <<= 1;
|
||||
sclDelay(16);
|
||||
writeScl(HIGH);
|
||||
sclDelay(12);
|
||||
if (readSda()) {
|
||||
b |= 1;
|
||||
}
|
||||
writeScl(LOW);
|
||||
}
|
||||
// send ACK or NACK
|
||||
writeSda(last);
|
||||
sclDelay(12);
|
||||
writeScl(HIGH);
|
||||
sclDelay(18);
|
||||
writeScl(LOW);
|
||||
writeSda(LOW);
|
||||
return b;
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* Issue a start condition. */
|
||||
void SoftI2cMaster::start()
|
||||
{
|
||||
if (!readSda()) {
|
||||
writeSda(HIGH);
|
||||
writeScl(HIGH);
|
||||
sclDelay(20);
|
||||
}
|
||||
writeSda(LOW);
|
||||
sclDelay(20);
|
||||
writeScl(LOW);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/* Issue a stop condition. */
|
||||
void SoftI2cMaster::stop(void)
|
||||
{
|
||||
writeSda(LOW);
|
||||
sclDelay(20);
|
||||
writeScl(HIGH);
|
||||
sclDelay(20);
|
||||
writeSda(HIGH);
|
||||
sclDelay(20);
|
||||
}
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
* Write a byte.
|
||||
*
|
||||
* @param[in] data The byte to send.
|
||||
*
|
||||
* @return The value true, 1, if the slave returned an ACK or false for NACK.
|
||||
*/
|
||||
bool SoftI2cMaster::write(uint8_t data)
|
||||
{
|
||||
// write byte
|
||||
for (uint8_t m = 0X80; m != 0; m >>= 1) {
|
||||
// don't change this loop unless you verify the change with a scope
|
||||
writeSda(m & data);
|
||||
sclDelay(8);
|
||||
writeScl(HIGH);
|
||||
sclDelay(18);
|
||||
writeScl(LOW);
|
||||
}
|
||||
sclDelay(8);
|
||||
// Go to sda high Z mode for input.
|
||||
writeSda(HIGH);
|
||||
writeScl(HIGH);
|
||||
sclDelay(16);
|
||||
|
||||
// Get ACK or NACK.
|
||||
uint8_t rtn = readSda();
|
||||
|
||||
// pull scl low.
|
||||
writeScl(LOW);
|
||||
|
||||
// Pull sda low.
|
||||
writeSda(LOW);
|
||||
return rtn == 0;
|
||||
}
|
||||
#endif // __AVR__
|
||||
/** @} */
|
||||
|
||||
@@ -0,0 +1,314 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef SOFT_I2C_MASTER_H
|
||||
#define SOFT_I2C_MASTER_H
|
||||
/**
|
||||
* @file
|
||||
* @brief AVR Software I2C library
|
||||
*
|
||||
* @defgroup softI2C Software I2C
|
||||
* @details Software Two Wire Interface library.
|
||||
* @{
|
||||
*/
|
||||
#if defined(__AVR__) || defined(DOXYGEN) // AVR only
|
||||
#include <Arduino.h>
|
||||
#include <util/delay_basic.h>
|
||||
#include "DigitalPin.h"
|
||||
#include "I2cConstants.h"
|
||||
//------------------------------------------------------------------------------
|
||||
// State codes.
|
||||
|
||||
/** Stop condition transmitted. */
|
||||
const uint8_t STATE_STOP = 0;
|
||||
|
||||
/** Repeated start condition transmitted. */
|
||||
const uint8_t STATE_REP_START = 1;
|
||||
|
||||
/** Read data transfer active. */
|
||||
const uint8_t STATE_RX_DATA = 2;
|
||||
|
||||
/** Write data transfer active. */
|
||||
const uint8_t STATE_TX_DATA = 3;
|
||||
|
||||
/** Slave address plus read bit transmitted, NACK received. */
|
||||
const uint8_t STATE_RX_ADDR_NACK = 4;
|
||||
|
||||
/** Slave address plus write bit transmitted, NACK received. */
|
||||
const uint8_t STATE_TX_ADDR_NACK = 5;
|
||||
/** Data byte transmitted, NACK received. */
|
||||
const uint8_t STATE_TX_DATA_NACK = 6;
|
||||
//==============================================================================
|
||||
/**
|
||||
* @class I2cMasterBase
|
||||
* @brief Base class for FastI2cMaster, SoftI2cMaster
|
||||
*/
|
||||
class I2cMasterBase
|
||||
{
|
||||
public:
|
||||
I2cMasterBase() : _state(STATE_STOP) {}
|
||||
/** Read a byte
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*
|
||||
* @param[in] last send a NACK to terminate read if last is true else
|
||||
* send an ACK to continue the read.
|
||||
*
|
||||
* @return byte read from I2C bus
|
||||
*/
|
||||
virtual uint8_t read(uint8_t last) = 0;
|
||||
|
||||
/** Issue a start condition
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*/
|
||||
virtual void start() = 0;
|
||||
/** Issue a stop condition.
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*/
|
||||
virtual void stop() = 0;
|
||||
|
||||
bool transfer(uint8_t addressRW, void *buf,
|
||||
size_t nbyte, uint8_t option = I2C_STOP);
|
||||
|
||||
bool transferContinue(void *buf, size_t nbyte, uint8_t option = I2C_STOP);
|
||||
/** Write a byte
|
||||
*
|
||||
* @note This function should only be used by experts. Data should be
|
||||
* accessed by calling transfer() and transferContinue()
|
||||
*
|
||||
* @param[in] data byte to write
|
||||
* @return true for ACK or false for NACK */
|
||||
virtual bool write(uint8_t data) = 0;
|
||||
|
||||
private:
|
||||
uint8_t _state;
|
||||
};
|
||||
//==============================================================================
|
||||
/**
|
||||
* @class SoftI2cMaster
|
||||
* @brief AVR Software I2C master class
|
||||
*/
|
||||
class SoftI2cMaster : public I2cMasterBase
|
||||
{
|
||||
public:
|
||||
SoftI2cMaster() {}
|
||||
SoftI2cMaster(uint8_t sclPin, uint8_t sdaPin);
|
||||
void begin(uint8_t sclPin, uint8_t sdaPin);
|
||||
uint8_t read(uint8_t last);
|
||||
void start();
|
||||
void stop(void);
|
||||
bool write(uint8_t b);
|
||||
|
||||
private:
|
||||
uint8_t _sclBit;
|
||||
uint8_t _sdaBit;
|
||||
volatile uint8_t* _sclDDR;
|
||||
volatile uint8_t* _sdaDDR;
|
||||
volatile uint8_t* _sdaInReg;
|
||||
//----------------------------------------------------------------------------
|
||||
bool readSda()
|
||||
{
|
||||
return *_sdaInReg & _sdaBit;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void sclDelay(uint8_t n)
|
||||
{
|
||||
_delay_loop_1(n);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void writeScl(bool value)
|
||||
{
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
if (value == LOW) {
|
||||
// Pull scl low.
|
||||
*_sclDDR |= _sclBit;
|
||||
} else {
|
||||
// Put scl in high Z input mode.
|
||||
*_sclDDR &= ~_sclBit;
|
||||
}
|
||||
SREG = s;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void writeSda(bool value)
|
||||
{
|
||||
uint8_t s = SREG;
|
||||
noInterrupts();
|
||||
if (value == LOW) {
|
||||
// Pull sda low.
|
||||
*_sdaDDR |= _sdaBit;
|
||||
} else {
|
||||
// Put sda in high Z input mode.
|
||||
*_sdaDDR &= ~_sdaBit;
|
||||
}
|
||||
SREG = s;
|
||||
}
|
||||
};
|
||||
//==============================================================================
|
||||
// Template based fast software I2C
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @class FastI2cMaster
|
||||
* @brief AVR Fast software I2C master class.
|
||||
*/
|
||||
template<uint8_t sclPin, uint8_t sdaPin>
|
||||
class FastI2cMaster : public I2cMasterBase
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
FastI2cMaster()
|
||||
{
|
||||
begin();
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize I2C bus pins. */
|
||||
void begin()
|
||||
{
|
||||
fastDigitalWrite(sclPin, LOW);
|
||||
fastDigitalWrite(sdaPin, LOW);
|
||||
|
||||
sclWrite(HIGH);
|
||||
sdaWrite(HIGH);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
uint8_t read(uint8_t last)
|
||||
{
|
||||
uint8_t data = 0;
|
||||
sdaWrite(HIGH);
|
||||
|
||||
readBit(7, &data);
|
||||
readBit(6, &data);
|
||||
readBit(5, &data);
|
||||
readBit(4, &data);
|
||||
readBit(3, &data);
|
||||
readBit(2, &data);
|
||||
readBit(1, &data);
|
||||
readBit(0, &data);
|
||||
|
||||
// send ACK or NACK
|
||||
sdaWrite(last);
|
||||
sclDelay(4);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(6);
|
||||
sclWrite(LOW);
|
||||
sdaWrite(LOW);
|
||||
return data;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void start()
|
||||
{
|
||||
if (!fastDigitalRead(sdaPin)) {
|
||||
// It's a repeat start.
|
||||
sdaWrite(HIGH);
|
||||
sclDelay(8);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(8);
|
||||
}
|
||||
sdaWrite(LOW);
|
||||
sclDelay(8);
|
||||
sclWrite(LOW);
|
||||
sclDelay(8);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void stop(void)
|
||||
{
|
||||
sdaWrite(LOW);
|
||||
sclDelay(8);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(8);
|
||||
sdaWrite(HIGH);
|
||||
sclDelay(8);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
bool write(uint8_t data)
|
||||
{
|
||||
// write byte
|
||||
writeBit(7, data);
|
||||
writeBit(6, data);
|
||||
writeBit(5, data);
|
||||
writeBit(4, data);
|
||||
writeBit(3, data);
|
||||
writeBit(2, data);
|
||||
writeBit(1, data);
|
||||
writeBit(0, data);
|
||||
|
||||
// get ACK or NACK
|
||||
sdaWrite(HIGH);
|
||||
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
bool rtn = fastDigitalRead(sdaPin);
|
||||
sclWrite(LOW);
|
||||
sdaWrite(LOW);
|
||||
return rtn == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sclWrite(bool value)
|
||||
{
|
||||
fastDdrWrite(sclPin, !value);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sdaWrite(bool value)
|
||||
{
|
||||
fastDdrWrite(sdaPin, !value);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void readBit(uint8_t bit, uint8_t* data)
|
||||
{
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
if (fastDigitalRead(sdaPin)) {
|
||||
*data |= 1 << bit;
|
||||
}
|
||||
sclWrite(LOW);
|
||||
if (bit) {
|
||||
sclDelay(6);
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
void sclDelay(uint8_t n)
|
||||
{
|
||||
_delay_loop_1(n);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void writeBit(uint8_t bit, uint8_t data)
|
||||
{
|
||||
uint8_t mask = 1 << bit;
|
||||
sdaWrite(data & mask);
|
||||
sclWrite(HIGH);
|
||||
sclDelay(5);
|
||||
sclWrite(LOW);
|
||||
sclDelay(5);
|
||||
}
|
||||
};
|
||||
#endif // __AVR__
|
||||
#endif // SOFT_I2C_MASTER_H
|
||||
/** @} */
|
||||
|
||||
180
lib/MySensors/hal/architecture/AVR/drivers/DigitalIO/SoftSPI.h
Normal file
180
lib/MySensors/hal/architecture/AVR/drivers/DigitalIO/SoftSPI.h
Normal file
@@ -0,0 +1,180 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @file
|
||||
* @brief Software SPI.
|
||||
*
|
||||
* @defgroup softSPI Software SPI
|
||||
* @details Software SPI Template Class.
|
||||
* @{
|
||||
*/
|
||||
|
||||
#ifndef SoftSPI_h
|
||||
#define SoftSPI_h
|
||||
#include "DigitalPin.h"
|
||||
//------------------------------------------------------------------------------
|
||||
/** Nop for timing. */
|
||||
#define nop asm volatile ("nop\n\t")
|
||||
//------------------------------------------------------------------------------
|
||||
/** Pin Mode for MISO is input.*/
|
||||
#define MISO_MODE INPUT
|
||||
/** Pullups disabled for MISO are disabled. */
|
||||
#define MISO_LEVEL false
|
||||
/** Pin Mode for MOSI is output.*/
|
||||
#define MOSI_MODE OUTPUT
|
||||
/** Pin Mode for SCK is output. */
|
||||
#define SCK_MODE OUTPUT
|
||||
//------------------------------------------------------------------------------
|
||||
/**
|
||||
* @class SoftSPI
|
||||
* @brief Fast software SPI.
|
||||
*/
|
||||
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin, uint8_t Mode = 0>
|
||||
class SoftSPI
|
||||
{
|
||||
public:
|
||||
//----------------------------------------------------------------------------
|
||||
/** Initialize SoftSPI pins. */
|
||||
void begin()
|
||||
{
|
||||
fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL);
|
||||
fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode));
|
||||
fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode));
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI receive byte.
|
||||
* @return Data byte received.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint8_t receive()
|
||||
{
|
||||
uint8_t data = 0;
|
||||
receiveBit(7, &data);
|
||||
receiveBit(6, &data);
|
||||
receiveBit(5, &data);
|
||||
receiveBit(4, &data);
|
||||
receiveBit(3, &data);
|
||||
receiveBit(2, &data);
|
||||
receiveBit(1, &data);
|
||||
receiveBit(0, &data);
|
||||
return data;
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI send byte.
|
||||
* @param[in] data Data byte to send.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
void send(uint8_t data)
|
||||
{
|
||||
sendBit(7, data);
|
||||
sendBit(6, data);
|
||||
sendBit(5, data);
|
||||
sendBit(4, data);
|
||||
sendBit(3, data);
|
||||
sendBit(2, data);
|
||||
sendBit(1, data);
|
||||
sendBit(0, data);
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
/** Soft SPI transfer byte.
|
||||
* @param[in] txData Data byte to send.
|
||||
* @return Data byte received.
|
||||
*/
|
||||
inline __attribute__((always_inline))
|
||||
uint8_t transfer(uint8_t txData)
|
||||
{
|
||||
uint8_t rxData = 0;
|
||||
transferBit(7, &rxData, txData);
|
||||
transferBit(6, &rxData, txData);
|
||||
transferBit(5, &rxData, txData);
|
||||
transferBit(4, &rxData, txData);
|
||||
transferBit(3, &rxData, txData);
|
||||
transferBit(2, &rxData, txData);
|
||||
transferBit(1, &rxData, txData);
|
||||
transferBit(0, &rxData, txData);
|
||||
return rxData;
|
||||
}
|
||||
|
||||
private:
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
bool MODE_CPHA(uint8_t mode)
|
||||
{
|
||||
return (mode & 1) != 0;
|
||||
}
|
||||
inline __attribute__((always_inline))
|
||||
bool MODE_CPOL(uint8_t mode)
|
||||
{
|
||||
return (mode & 2) != 0;
|
||||
}
|
||||
inline __attribute__((always_inline))
|
||||
void receiveBit(uint8_t bit, uint8_t* data)
|
||||
{
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
nop;
|
||||
nop;
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
if (fastDigitalRead(MisoPin)) {
|
||||
*data |= 1 << bit;
|
||||
}
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void sendBit(uint8_t bit, uint8_t data)
|
||||
{
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
fastDigitalWrite(MosiPin, data & (1 << bit));
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
nop;
|
||||
nop;
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
inline __attribute__((always_inline))
|
||||
void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData)
|
||||
{
|
||||
if (MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
|
||||
}
|
||||
fastDigitalWrite(MosiPin, txData & (1 << bit));
|
||||
fastDigitalWrite(SckPin,
|
||||
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
|
||||
if (fastDigitalRead(MisoPin)) {
|
||||
*rxData |= 1 << bit;
|
||||
}
|
||||
if (!MODE_CPHA(Mode)) {
|
||||
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
|
||||
}
|
||||
}
|
||||
//----------------------------------------------------------------------------
|
||||
};
|
||||
#endif // SoftSPI_h
|
||||
/** @} */
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef AvrDevelopersGpioPinMap_h
|
||||
#define AvrDevelopersGpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(B, 0), // D0
|
||||
GPIO_PIN(B, 1), // D1
|
||||
GPIO_PIN(B, 2), // D2
|
||||
GPIO_PIN(B, 3), // D3
|
||||
GPIO_PIN(B, 4), // D4
|
||||
GPIO_PIN(B, 5), // D5
|
||||
GPIO_PIN(B, 6), // D6
|
||||
GPIO_PIN(B, 7), // D7
|
||||
GPIO_PIN(D, 0), // D8
|
||||
GPIO_PIN(D, 1), // D9
|
||||
GPIO_PIN(D, 2), // D10
|
||||
GPIO_PIN(D, 3), // D11
|
||||
GPIO_PIN(D, 4), // D12
|
||||
GPIO_PIN(D, 5), // D13
|
||||
GPIO_PIN(D, 6), // D14
|
||||
GPIO_PIN(D, 7), // D15
|
||||
GPIO_PIN(C, 0), // D16
|
||||
GPIO_PIN(C, 1), // D17
|
||||
GPIO_PIN(C, 2), // D18
|
||||
GPIO_PIN(C, 3), // D19
|
||||
GPIO_PIN(C, 4), // D20
|
||||
GPIO_PIN(C, 5), // D21
|
||||
GPIO_PIN(C, 6), // D22
|
||||
GPIO_PIN(C, 7), // D23
|
||||
GPIO_PIN(A, 7), // D24
|
||||
GPIO_PIN(A, 6), // D25
|
||||
GPIO_PIN(A, 5), // D26
|
||||
GPIO_PIN(A, 4), // D27
|
||||
GPIO_PIN(A, 3), // D28
|
||||
GPIO_PIN(A, 2), // D29
|
||||
GPIO_PIN(A, 1), // D30
|
||||
GPIO_PIN(A, 0) // D31
|
||||
};
|
||||
#endif // AvrDevelopersGpioPinMap_h
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef BobuinoGpioPinMap_h
|
||||
#define BobuinoGpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(B, 0), // D0
|
||||
GPIO_PIN(B, 1), // D1
|
||||
GPIO_PIN(B, 2), // D2
|
||||
GPIO_PIN(B, 3), // D3
|
||||
GPIO_PIN(B, 4), // D4
|
||||
GPIO_PIN(B, 5), // D5
|
||||
GPIO_PIN(B, 6), // D6
|
||||
GPIO_PIN(B, 7), // D7
|
||||
GPIO_PIN(D, 0), // D8
|
||||
GPIO_PIN(D, 1), // D9
|
||||
GPIO_PIN(D, 2), // D10
|
||||
GPIO_PIN(D, 3), // D11
|
||||
GPIO_PIN(D, 4), // D12
|
||||
GPIO_PIN(D, 5), // D13
|
||||
GPIO_PIN(D, 6), // D14
|
||||
GPIO_PIN(D, 7), // D15
|
||||
GPIO_PIN(C, 0), // D16
|
||||
GPIO_PIN(C, 1), // D17
|
||||
GPIO_PIN(C, 2), // D18
|
||||
GPIO_PIN(C, 3), // D19
|
||||
GPIO_PIN(C, 4), // D20
|
||||
GPIO_PIN(C, 5), // D21
|
||||
GPIO_PIN(C, 6), // D22
|
||||
GPIO_PIN(C, 7), // D23
|
||||
GPIO_PIN(A, 0), // D24
|
||||
GPIO_PIN(A, 1), // D25
|
||||
GPIO_PIN(A, 2), // D26
|
||||
GPIO_PIN(A, 3), // D27
|
||||
GPIO_PIN(A, 4), // D28
|
||||
GPIO_PIN(A, 5), // D29
|
||||
GPIO_PIN(A, 6), // D30
|
||||
GPIO_PIN(A, 7) // D31
|
||||
};
|
||||
#endif // BobuinoGpioPinMap_h
|
||||
@@ -0,0 +1,64 @@
|
||||
/* Arduino DigitalIO Library
|
||||
* Copyright (C) 2013 by William Greiman
|
||||
*
|
||||
* This file is part of the Arduino DigitalIO Library
|
||||
*
|
||||
* This Library is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with the Arduino DigitalIO Library. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef GpioPinMap_h
|
||||
#define GpioPinMap_h
|
||||
#if defined(__AVR_ATmega168__)\
|
||||
||defined(__AVR_ATmega168P__)\
|
||||
||defined(__AVR_ATmega328P__)
|
||||
// 168 and 328 Arduinos
|
||||
#include "UnoGpioPinMap.h"
|
||||
#elif defined(__AVR_ATmega1280__)\
|
||||
|| defined(__AVR_ATmega2560__)
|
||||
// Mega ADK
|
||||
#include "MegaGpioPinMap.h"
|
||||
#elif defined(__AVR_ATmega32U4__)
|
||||
#ifdef CORE_TEENSY
|
||||
#include "Teensy2GpioPinMap.h"
|
||||
#else // CORE_TEENSY
|
||||
// Leonardo or Yun
|
||||
#include "LeonardoGpioPinMap.h"
|
||||
#endif // CORE_TEENSY
|
||||
#elif defined(__AVR_AT90USB646__)\
|
||||
|| defined(__AVR_AT90USB1286__)
|
||||
// Teensy++ 1.0 & 2.0
|
||||
#include "Teensy2ppGpioPinMap.h"
|
||||
#elif defined(__AVR_ATmega1284P__)\
|
||||
|| defined(__AVR_ATmega1284__)\
|
||||
|| defined(__AVR_ATmega644P__)\
|
||||
|| defined(__AVR_ATmega644__)\
|
||||
|| defined(__AVR_ATmega64__)\
|
||||
|| defined(__AVR_ATmega32__)\
|
||||
|| defined(__AVR_ATmega324__)\
|
||||
|| defined(__AVR_ATmega16__)
|
||||
#ifdef ARDUINO_1284P_AVR_DEVELOPERS
|
||||
#include "AvrDevelopersGpioPinMap.h"
|
||||
#elif defined(ARDUINO_1284P_BOBUINO)
|
||||
#include "BobuinoGpioPinMap.h"
|
||||
#elif defined(ARDUINO_1284P_SLEEPINGBEAUTY)
|
||||
#include "SleepingBeautyGpioPinMap.h"
|
||||
#elif defined(ARDUINO_1284P_STANDARD)
|
||||
#include "Standard1284GpioPinMap.h"
|
||||
#else // ARDUINO_1284P_SLEEPINGBEAUTY
|
||||
#error Undefined variant 1284, 644, 324
|
||||
#endif // ARDUINO_1284P_SLEEPINGBEAUTY
|
||||
#else // 1284P, 1284, 644
|
||||
#error Unknown board type.
|
||||
#endif // end all boards
|
||||
#endif // GpioPinMap_h
|
||||
@@ -0,0 +1,35 @@
|
||||
#ifndef LeonardoGpioPinMap_h
|
||||
#define LeonardoGpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(D, 2), // D0
|
||||
GPIO_PIN(D, 3), // D1
|
||||
GPIO_PIN(D, 1), // D2
|
||||
GPIO_PIN(D, 0), // D3
|
||||
GPIO_PIN(D, 4), // D4
|
||||
GPIO_PIN(C, 6), // D5
|
||||
GPIO_PIN(D, 7), // D6
|
||||
GPIO_PIN(E, 6), // D7
|
||||
GPIO_PIN(B, 4), // D8
|
||||
GPIO_PIN(B, 5), // D9
|
||||
GPIO_PIN(B, 6), // D10
|
||||
GPIO_PIN(B, 7), // D11
|
||||
GPIO_PIN(D, 6), // D12
|
||||
GPIO_PIN(C, 7), // D13
|
||||
GPIO_PIN(B, 3), // D14
|
||||
GPIO_PIN(B, 1), // D15
|
||||
GPIO_PIN(B, 2), // D16
|
||||
GPIO_PIN(B, 0), // D17
|
||||
GPIO_PIN(F, 7), // D18
|
||||
GPIO_PIN(F, 6), // D19
|
||||
GPIO_PIN(F, 5), // D20
|
||||
GPIO_PIN(F, 4), // D21
|
||||
GPIO_PIN(F, 1), // D22
|
||||
GPIO_PIN(F, 0), // D23
|
||||
GPIO_PIN(D, 4), // D24
|
||||
GPIO_PIN(D, 7), // D25
|
||||
GPIO_PIN(B, 4), // D26
|
||||
GPIO_PIN(B, 5), // D27
|
||||
GPIO_PIN(B, 6), // D28
|
||||
GPIO_PIN(D, 6) // D29
|
||||
};
|
||||
#endif // LeonardoGpioPinMap_h
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef MegaGpioPinMap_h
|
||||
#define MegaGpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(E, 0), // D0
|
||||
GPIO_PIN(E, 1), // D1
|
||||
GPIO_PIN(E, 4), // D2
|
||||
GPIO_PIN(E, 5), // D3
|
||||
GPIO_PIN(G, 5), // D4
|
||||
GPIO_PIN(E, 3), // D5
|
||||
GPIO_PIN(H, 3), // D6
|
||||
GPIO_PIN(H, 4), // D7
|
||||
GPIO_PIN(H, 5), // D8
|
||||
GPIO_PIN(H, 6), // D9
|
||||
GPIO_PIN(B, 4), // D10
|
||||
GPIO_PIN(B, 5), // D11
|
||||
GPIO_PIN(B, 6), // D12
|
||||
GPIO_PIN(B, 7), // D13
|
||||
GPIO_PIN(J, 1), // D14
|
||||
GPIO_PIN(J, 0), // D15
|
||||
GPIO_PIN(H, 1), // D16
|
||||
GPIO_PIN(H, 0), // D17
|
||||
GPIO_PIN(D, 3), // D18
|
||||
GPIO_PIN(D, 2), // D19
|
||||
GPIO_PIN(D, 1), // D20
|
||||
GPIO_PIN(D, 0), // D21
|
||||
GPIO_PIN(A, 0), // D22
|
||||
GPIO_PIN(A, 1), // D23
|
||||
GPIO_PIN(A, 2), // D24
|
||||
GPIO_PIN(A, 3), // D25
|
||||
GPIO_PIN(A, 4), // D26
|
||||
GPIO_PIN(A, 5), // D27
|
||||
GPIO_PIN(A, 6), // D28
|
||||
GPIO_PIN(A, 7), // D29
|
||||
GPIO_PIN(C, 7), // D30
|
||||
GPIO_PIN(C, 6), // D31
|
||||
GPIO_PIN(C, 5), // D32
|
||||
GPIO_PIN(C, 4), // D33
|
||||
GPIO_PIN(C, 3), // D34
|
||||
GPIO_PIN(C, 2), // D35
|
||||
GPIO_PIN(C, 1), // D36
|
||||
GPIO_PIN(C, 0), // D37
|
||||
GPIO_PIN(D, 7), // D38
|
||||
GPIO_PIN(G, 2), // D39
|
||||
GPIO_PIN(G, 1), // D40
|
||||
GPIO_PIN(G, 0), // D41
|
||||
GPIO_PIN(L, 7), // D42
|
||||
GPIO_PIN(L, 6), // D43
|
||||
GPIO_PIN(L, 5), // D44
|
||||
GPIO_PIN(L, 4), // D45
|
||||
GPIO_PIN(L, 3), // D46
|
||||
GPIO_PIN(L, 2), // D47
|
||||
GPIO_PIN(L, 1), // D48
|
||||
GPIO_PIN(L, 0), // D49
|
||||
GPIO_PIN(B, 3), // D50
|
||||
GPIO_PIN(B, 2), // D51
|
||||
GPIO_PIN(B, 1), // D52
|
||||
GPIO_PIN(B, 0), // D53
|
||||
GPIO_PIN(F, 0), // D54
|
||||
GPIO_PIN(F, 1), // D55
|
||||
GPIO_PIN(F, 2), // D56
|
||||
GPIO_PIN(F, 3), // D57
|
||||
GPIO_PIN(F, 4), // D58
|
||||
GPIO_PIN(F, 5), // D59
|
||||
GPIO_PIN(F, 6), // D60
|
||||
GPIO_PIN(F, 7), // D61
|
||||
GPIO_PIN(K, 0), // D62
|
||||
GPIO_PIN(K, 1), // D63
|
||||
GPIO_PIN(K, 2), // D64
|
||||
GPIO_PIN(K, 3), // D65
|
||||
GPIO_PIN(K, 4), // D66
|
||||
GPIO_PIN(K, 5), // D67
|
||||
GPIO_PIN(K, 6), // D68
|
||||
GPIO_PIN(K, 7) // D69
|
||||
};
|
||||
#endif // MegaGpioPinMap_h
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef SleepingBeautyGpioPinMap_h
|
||||
#define SleepingBeautyGpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(D, 0), // D0
|
||||
GPIO_PIN(D, 1), // D1
|
||||
GPIO_PIN(D, 2), // D2
|
||||
GPIO_PIN(D, 3), // D3
|
||||
GPIO_PIN(B, 0), // D4
|
||||
GPIO_PIN(B, 1), // D5
|
||||
GPIO_PIN(B, 2), // D6
|
||||
GPIO_PIN(B, 3), // D7
|
||||
GPIO_PIN(D, 6), // D8
|
||||
GPIO_PIN(D, 5), // D9
|
||||
GPIO_PIN(B, 4), // D10
|
||||
GPIO_PIN(B, 5), // D11
|
||||
GPIO_PIN(B, 6), // D12
|
||||
GPIO_PIN(B, 7), // D13
|
||||
GPIO_PIN(C, 7), // D14
|
||||
GPIO_PIN(C, 6), // D15
|
||||
GPIO_PIN(A, 5), // D16
|
||||
GPIO_PIN(A, 4), // D17
|
||||
GPIO_PIN(A, 3), // D18
|
||||
GPIO_PIN(A, 2), // D19
|
||||
GPIO_PIN(A, 1), // D20
|
||||
GPIO_PIN(A, 0), // D21
|
||||
GPIO_PIN(D, 4), // D22
|
||||
GPIO_PIN(D, 7), // D23
|
||||
GPIO_PIN(C, 2), // D24
|
||||
GPIO_PIN(C, 3), // D25
|
||||
GPIO_PIN(C, 4), // D26
|
||||
GPIO_PIN(C, 5), // D27
|
||||
GPIO_PIN(C, 1), // D28
|
||||
GPIO_PIN(C, 0), // D29
|
||||
GPIO_PIN(A, 6), // D30
|
||||
GPIO_PIN(A, 7) // D31
|
||||
};
|
||||
#endif // SleepingBeautyGpioPinMap_h
|
||||
@@ -0,0 +1,37 @@
|
||||
#ifndef Standard1284GpioPinMap_h
|
||||
#define Standard1284GpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(B, 0), // D0
|
||||
GPIO_PIN(B, 1), // D1
|
||||
GPIO_PIN(B, 2), // D2
|
||||
GPIO_PIN(B, 3), // D3
|
||||
GPIO_PIN(B, 4), // D4
|
||||
GPIO_PIN(B, 5), // D5
|
||||
GPIO_PIN(B, 6), // D6
|
||||
GPIO_PIN(B, 7), // D7
|
||||
GPIO_PIN(D, 0), // D8
|
||||
GPIO_PIN(D, 1), // D9
|
||||
GPIO_PIN(D, 2), // D10
|
||||
GPIO_PIN(D, 3), // D11
|
||||
GPIO_PIN(D, 4), // D12
|
||||
GPIO_PIN(D, 5), // D13
|
||||
GPIO_PIN(D, 6), // D14
|
||||
GPIO_PIN(D, 7), // D15
|
||||
GPIO_PIN(C, 0), // D16
|
||||
GPIO_PIN(C, 1), // D17
|
||||
GPIO_PIN(C, 2), // D18
|
||||
GPIO_PIN(C, 3), // D19
|
||||
GPIO_PIN(C, 4), // D20
|
||||
GPIO_PIN(C, 5), // D21
|
||||
GPIO_PIN(C, 6), // D22
|
||||
GPIO_PIN(C, 7), // D23
|
||||
GPIO_PIN(A, 0), // D24
|
||||
GPIO_PIN(A, 1), // D25
|
||||
GPIO_PIN(A, 2), // D26
|
||||
GPIO_PIN(A, 3), // D27
|
||||
GPIO_PIN(A, 4), // D28
|
||||
GPIO_PIN(A, 5), // D29
|
||||
GPIO_PIN(A, 6), // D30
|
||||
GPIO_PIN(A, 7) // D31
|
||||
};
|
||||
#endif // Standard1284GpioPinMap_h
|
||||
@@ -0,0 +1,30 @@
|
||||
#ifndef Teensy2GpioPinMap_h
|
||||
#define Teensy2GpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(B, 0), // D0
|
||||
GPIO_PIN(B, 1), // D1
|
||||
GPIO_PIN(B, 2), // D2
|
||||
GPIO_PIN(B, 3), // D3
|
||||
GPIO_PIN(B, 7), // D4
|
||||
GPIO_PIN(D, 0), // D5
|
||||
GPIO_PIN(D, 1), // D6
|
||||
GPIO_PIN(D, 2), // D7
|
||||
GPIO_PIN(D, 3), // D8
|
||||
GPIO_PIN(C, 6), // D9
|
||||
GPIO_PIN(C, 7), // D10
|
||||
GPIO_PIN(D, 6), // D11
|
||||
GPIO_PIN(D, 7), // D12
|
||||
GPIO_PIN(B, 4), // D13
|
||||
GPIO_PIN(B, 5), // D14
|
||||
GPIO_PIN(B, 6), // D15
|
||||
GPIO_PIN(F, 7), // D16
|
||||
GPIO_PIN(F, 6), // D17
|
||||
GPIO_PIN(F, 5), // D18
|
||||
GPIO_PIN(F, 4), // D19
|
||||
GPIO_PIN(F, 1), // D20
|
||||
GPIO_PIN(F, 0), // D21
|
||||
GPIO_PIN(D, 4), // D22
|
||||
GPIO_PIN(D, 5), // D23
|
||||
GPIO_PIN(E, 6), // D24
|
||||
};
|
||||
#endif // Teensy2GpioPinMap_h
|
||||
@@ -0,0 +1,51 @@
|
||||
#ifndef Teensypp2GpioPinMap_h
|
||||
#define Teensypp2GpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(D, 0), // D0
|
||||
GPIO_PIN(D, 1), // D1
|
||||
GPIO_PIN(D, 2), // D2
|
||||
GPIO_PIN(D, 3), // D3
|
||||
GPIO_PIN(D, 4), // D4
|
||||
GPIO_PIN(D, 5), // D5
|
||||
GPIO_PIN(D, 6), // D6
|
||||
GPIO_PIN(D, 7), // D7
|
||||
GPIO_PIN(E, 0), // D8
|
||||
GPIO_PIN(E, 1), // D9
|
||||
GPIO_PIN(C, 0), // D10
|
||||
GPIO_PIN(C, 1), // D11
|
||||
GPIO_PIN(C, 2), // D12
|
||||
GPIO_PIN(C, 3), // D13
|
||||
GPIO_PIN(C, 4), // D14
|
||||
GPIO_PIN(C, 5), // D15
|
||||
GPIO_PIN(C, 6), // D16
|
||||
GPIO_PIN(C, 7), // D17
|
||||
GPIO_PIN(E, 6), // D18
|
||||
GPIO_PIN(E, 7), // D19
|
||||
GPIO_PIN(B, 0), // D20
|
||||
GPIO_PIN(B, 1), // D21
|
||||
GPIO_PIN(B, 2), // D22
|
||||
GPIO_PIN(B, 3), // D23
|
||||
GPIO_PIN(B, 4), // D24
|
||||
GPIO_PIN(B, 5), // D25
|
||||
GPIO_PIN(B, 6), // D26
|
||||
GPIO_PIN(B, 7), // D27
|
||||
GPIO_PIN(A, 0), // D28
|
||||
GPIO_PIN(A, 1), // D29
|
||||
GPIO_PIN(A, 2), // D30
|
||||
GPIO_PIN(A, 3), // D31
|
||||
GPIO_PIN(A, 4), // D32
|
||||
GPIO_PIN(A, 5), // D33
|
||||
GPIO_PIN(A, 6), // D34
|
||||
GPIO_PIN(A, 7), // D35
|
||||
GPIO_PIN(E, 4), // D36
|
||||
GPIO_PIN(E, 5), // D37
|
||||
GPIO_PIN(F, 0), // D38
|
||||
GPIO_PIN(F, 1), // D39
|
||||
GPIO_PIN(F, 2), // D40
|
||||
GPIO_PIN(F, 3), // D41
|
||||
GPIO_PIN(F, 4), // D42
|
||||
GPIO_PIN(F, 5), // D43
|
||||
GPIO_PIN(F, 6), // D44
|
||||
GPIO_PIN(F, 7), // D45
|
||||
};
|
||||
#endif // Teensypp2GpioPinMap_h
|
||||
@@ -0,0 +1,25 @@
|
||||
#ifndef UnoGpioPinMap_h
|
||||
#define UnoGpioPinMap_h
|
||||
static const GpioPinMap_t GpioPinMap[] = {
|
||||
GPIO_PIN(D, 0), // D0
|
||||
GPIO_PIN(D, 1), // D1
|
||||
GPIO_PIN(D, 2), // D2
|
||||
GPIO_PIN(D, 3), // D3
|
||||
GPIO_PIN(D, 4), // D4
|
||||
GPIO_PIN(D, 5), // D5
|
||||
GPIO_PIN(D, 6), // D6
|
||||
GPIO_PIN(D, 7), // D7
|
||||
GPIO_PIN(B, 0), // D8
|
||||
GPIO_PIN(B, 1), // D9
|
||||
GPIO_PIN(B, 2), // D10
|
||||
GPIO_PIN(B, 3), // D11
|
||||
GPIO_PIN(B, 4), // D12
|
||||
GPIO_PIN(B, 5), // D13
|
||||
GPIO_PIN(C, 0), // D14
|
||||
GPIO_PIN(C, 1), // D15
|
||||
GPIO_PIN(C, 2), // D16
|
||||
GPIO_PIN(C, 3), // D17
|
||||
GPIO_PIN(C, 4), // D18
|
||||
GPIO_PIN(C, 5) // D19
|
||||
};
|
||||
#endif // UnoGpioPinMap_h
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Optimized digital functions for AVR microcontrollers
|
||||
* based on http://code.google.com/p/digitalwritefast
|
||||
*/
|
||||
|
||||
#ifndef __digitalWriteFast_h_
|
||||
#define __digitalWriteFast_h_
|
||||
|
||||
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_DUEMILANOVE) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__) || defined(__AVR_ATmega328PB__) || defined (__AVR_ATmega168__)
|
||||
#if defined(__AVR_ATmega328PB__)
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : (((__pin) >= 14 && (__pin) <= 19) ? &PORTC : &PORTE)))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : (((__pin) >= 14 && (__pin) <= 19) ? &DDRC : &DDRE)))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : (((__pin) >= 14 && (__pin) <= 19) ? &PINC : &PINE)))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (((__pin) >= 14 && (__pin) <= 19) ? (__pin) - 14 : (((__pin) >= 20 && (__pin) <= 21) ? (__pin) - 18 : (__pin) - 22))))
|
||||
#else
|
||||
#define __digitalPinToPortReg(__pin) (((__pin) <= 7) ? &PORTD : (((__pin) >= 8 && (__pin) <= 13) ? &PORTB : &PORTC))
|
||||
#define __digitalPinToDDRReg(__pin) (((__pin) <= 7) ? &DDRD : (((__pin) >= 8 && (__pin) <= 13) ? &DDRB : &DDRC))
|
||||
#define __digitalPinToPINReg(__pin) (((__pin) <= 7) ? &PIND : (((__pin) >= 8 && (__pin) <= 13) ? &PINB : &PINC))
|
||||
#define __digitalPinToBit(__pin) (((__pin) <= 7) ? (__pin) : (((__pin) >= 8 && (__pin) <= 13) ? (__pin) - 8 : (__pin) - 14))
|
||||
#endif
|
||||
#define digitalWriteFast(__pin, __value) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__value)) { bitWrite(*__digitalPinToPortReg(__pin), (uint8_t)__digitalPinToBit(__pin), (__value)); } else { digitalWrite((__pin), (__value)); } } while (0)
|
||||
#define pinModeFast(__pin, __mode) do { if (__builtin_constant_p(__pin) && __builtin_constant_p(__mode) && (__mode!=INPUT_PULLUP)) { bitWrite(*__digitalPinToDDRReg(__pin), (uint8_t)__digitalPinToBit(__pin), (__mode)); } else { pinMode((__pin), (__mode)); } } while (0)
|
||||
#define digitalReadFast(__pin) ( (bool) (__builtin_constant_p(__pin) ) ? (( bitRead(*__digitalPinToPINReg(__pin), (uint8_t)__digitalPinToBit(__pin))) ) : digitalRead((__pin)) )
|
||||
#else
|
||||
// for all other archs use built-in pin access functions
|
||||
#define digitalWriteFast(__pin, __value) digitalWrite(__pin, __value)
|
||||
#define pinModeFast(__pin, __value) pinMode(__pin, __value)
|
||||
#define digitalReadFast(__pin) digitalRead(__pin)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
144
lib/MySensors/hal/architecture/ESP32/MyHwESP32.cpp
Normal file
144
lib/MySensors/hal/architecture/ESP32/MyHwESP32.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Arduino core for ESP32: https://github.com/espressif/arduino-esp32
|
||||
*
|
||||
* MySensors ESP32 implementation, Copyright (C) 2017-2018 Olivier Mauti <olivier@mysensors.org>
|
||||
*
|
||||
*/
|
||||
|
||||
#include "MyHwESP32.h"
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE, SERIAL_8N1);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
#endif
|
||||
return EEPROM.begin(MY_EEPROM_SIZE);
|
||||
}
|
||||
|
||||
void hwReadConfigBlock(void *buf, void *addr, size_t length)
|
||||
{
|
||||
uint8_t *dst = static_cast<uint8_t *>(buf);
|
||||
int offs = reinterpret_cast<int>(addr);
|
||||
while (length-- > 0) {
|
||||
*dst++ = EEPROM.read(offs++);
|
||||
}
|
||||
}
|
||||
|
||||
void hwWriteConfigBlock(void *buf, void *addr, size_t length)
|
||||
{
|
||||
uint8_t *src = static_cast<uint8_t *>(buf);
|
||||
int offs = reinterpret_cast<int>(addr);
|
||||
while (length-- > 0) {
|
||||
EEPROM.write(offs++, *src++);
|
||||
}
|
||||
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)
|
||||
{
|
||||
if (hwReadConfig(addr) != value) {
|
||||
hwWriteConfigBlock(&value, reinterpret_cast<void *>(addr), 1);
|
||||
}
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
uint64_t val = ESP.getEfuseMac();
|
||||
(void)memcpy((void *)uniqueID, (void *)&val, 8);
|
||||
(void)memset((void *)(uniqueID + 8), MY_HWID_PADDING_BYTE, 8); // padding
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t hwGetentropy(void *__buffer, size_t __length)
|
||||
{
|
||||
// cut length if > 256
|
||||
if (__length > 256) {
|
||||
__length = 256;
|
||||
}
|
||||
uint8_t *dst = (uint8_t *)__buffer;
|
||||
// get random numbers
|
||||
for (size_t i = 0; i < __length; i++) {
|
||||
dst[i] = (uint8_t)esp_random();
|
||||
}
|
||||
return __length;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
// in mV
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency(void)
|
||||
{
|
||||
// in 1/10Mhz
|
||||
return static_cast<uint16_t>(ESP.getCpuFreqMHz() * 10);
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
// CPU temperature in °C
|
||||
return static_cast<int8_t>((temperatureRead() - MY_ESP32_TEMPERATURE_OFFSET) /
|
||||
MY_ESP32_TEMPERATURE_GAIN);
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
return static_cast<uint16_t>(ESP.getFreeHeap());
|
||||
}
|
||||
107
lib/MySensors/hal/architecture/ESP32/MyHwESP32.h
Normal file
107
lib/MySensors/hal/architecture/ESP32/MyHwESP32.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Arduino core for ESP32: https://github.com/espressif/arduino-esp32
|
||||
*
|
||||
* MySensors ESP32 implementation, Copyright (C) 2017-2018 Olivier Mauti <olivier@mysensors.org>
|
||||
*
|
||||
* Radio wiring ESP32(Node32s): RF24, RFM69, RFM95:
|
||||
*
|
||||
* | IO | RF24 | RFM69 | RFM95 |
|
||||
* |------|------|-------|-------|
|
||||
* | MOSI | 23 | 23 | 23 |
|
||||
* | MISO | 19 | 19 | 19 |
|
||||
* | SCK | 18 | 18 | 18 |
|
||||
* | CSN | 5 | 5 | 5 |
|
||||
* | CE | 17 | - | - |
|
||||
* | RST | - | 17 | 17 |
|
||||
* | IRQ | 16* | 16 | 16 |
|
||||
* * = optional
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MyHwESP32_h
|
||||
#define MyHwESP32_h
|
||||
|
||||
#include <WiFi.h>
|
||||
#include "EEPROM.h"
|
||||
#include <SPI.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
|
||||
|
||||
#ifndef MY_ESP32_TEMPERATURE_OFFSET
|
||||
#define MY_ESP32_TEMPERATURE_OFFSET (0.0f)
|
||||
#endif
|
||||
|
||||
#ifndef MY_ESP32_TEMPERATURE_GAIN
|
||||
#define MY_ESP32_TEMPERATURE_GAIN (1.0f)
|
||||
#endif
|
||||
|
||||
#define MY_EEPROM_SIZE 1024
|
||||
|
||||
#define hwDigitalWrite(__pin, __value) digitalWrite(__pin, __value)
|
||||
#define hwDigitalRead(__pin) digitalRead(__pin)
|
||||
#define hwPinMode(__pin, __value) pinMode(__pin, __value)
|
||||
#define hwWatchdogReset()
|
||||
#define hwReboot() ESP.restart()
|
||||
#define hwMillis() millis()
|
||||
#define hwMicros() micros()
|
||||
#define hwRandomNumberInit() randomSeed(esp_random())
|
||||
#define hwGetSleepRemaining() (0ul)
|
||||
|
||||
bool hwInit(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);
|
||||
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
|
||||
|
||||
/**
|
||||
* Restore interrupt state.
|
||||
* Helper function for MY_CRITICAL_SECTION.
|
||||
*/
|
||||
static __inline__ void __psRestore(const uint32_t *__s)
|
||||
{
|
||||
XTOS_RESTORE_INTLEVEL(*__s);
|
||||
}
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION for ( uint32_t __psSaved __attribute__((__cleanup__(__psRestore))) = XTOS_DISABLE_ALL_INTERRUPTS, __ToDo = 1; __ToDo ; __ToDo = 0 )
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
|
||||
#endif
|
||||
57
lib/MySensors/hal/architecture/ESP32/MyMainESP32.cpp
Normal file
57
lib/MySensors/hal/architecture/ESP32/MyMainESP32.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_task_wdt.h"
|
||||
#include "Arduino.h"
|
||||
|
||||
TaskHandle_t loopTaskHandle = NULL;
|
||||
|
||||
#if CONFIG_AUTOSTART_ARDUINO
|
||||
|
||||
#if CONFIG_FREERTOS_UNICORE
|
||||
#define ARDUINO_RUNNING_CORE 0
|
||||
#else
|
||||
#define ARDUINO_RUNNING_CORE 1
|
||||
#endif
|
||||
|
||||
bool loopTaskWDTEnabled;
|
||||
|
||||
void loopTask(void *pvParameters)
|
||||
{
|
||||
_begin(); // Startup MySensors library
|
||||
for(;;) {
|
||||
if(loopTaskWDTEnabled) {
|
||||
esp_task_wdt_reset();
|
||||
}
|
||||
_process(); // Process incoming data
|
||||
loop();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void app_main()
|
||||
{
|
||||
loopTaskWDTEnabled = false;
|
||||
initArduino();
|
||||
xTaskCreatePinnedToCore(loopTask, "loopTask", 8192, NULL, 1, &loopTaskHandle, ARDUINO_RUNNING_CORE);
|
||||
}
|
||||
|
||||
#endif
|
||||
156
lib/MySensors/hal/architecture/ESP8266/MyHwESP8266.cpp
Normal file
156
lib/MySensors/hal/architecture/ESP8266/MyHwESP8266.cpp
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MyHwESP8266.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);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
#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
|
||||
(void)memset((uint8_t *)uniqueID, MY_HWID_PADDING_BYTE, 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;
|
||||
}
|
||||
|
||||
ssize_t hwGetentropy(void *__buffer, size_t __length)
|
||||
{
|
||||
// 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] = (uint8_t)RANDOM_REG32;
|
||||
}
|
||||
|
||||
return __length;
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t 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(void)
|
||||
{
|
||||
#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(void)
|
||||
{
|
||||
// in 1/10Mhz
|
||||
return ESP.getCpuFreqMHz()*10;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
return -127; // not available
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
return ESP.getFreeHeap();
|
||||
}
|
||||
82
lib/MySensors/hal/architecture/ESP8266/MyHwESP8266.h
Normal file
82
lib/MySensors/hal/architecture/ESP8266/MyHwESP8266.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MyHwESP8266_h
|
||||
#define MyHwESP8266_h
|
||||
|
||||
#include <SPI.h>
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <WiFiUdp.h>
|
||||
#include <EEPROM.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 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()
|
||||
// The use of randomSeed switch to pseudo random number. Keep hwRandomNumberInit empty
|
||||
#define hwRandomNumberInit()
|
||||
#define hwGetSleepRemaining() (0ul)
|
||||
|
||||
bool hwInit(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);
|
||||
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
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
348
lib/MySensors/hal/architecture/ESP8266/MyMainESP8266.cpp
Normal file
348
lib/MySensors/hal/architecture/ESP8266/MyMainESP8266.cpp
Normal file
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//This may be used to change user task stack size:
|
||||
//#define CONT_STACKSIZE 4096
|
||||
#include <Arduino.h>
|
||||
#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>
|
||||
#include "gdb_hooks.h"
|
||||
|
||||
#define LOOP_TASK_PRIORITY 1
|
||||
#define LOOP_QUEUE_SIZE 1
|
||||
#define OPTIMISTIC_YIELD_TIME_US 16000
|
||||
|
||||
extern "C" void call_user_start();
|
||||
extern void loop();
|
||||
extern void setup();
|
||||
extern void(*__init_array_start)(void);
|
||||
extern void(*__init_array_end)(void);
|
||||
|
||||
/* Not static, used in Esp.cpp */
|
||||
struct rst_info resetInfo;
|
||||
|
||||
/* Not static, used in core_esp8266_postmortem.c and other places.
|
||||
* Placed into noinit section because we assign value to this variable
|
||||
* before .bss is zero-filled, and need to preserve the value.
|
||||
*/
|
||||
cont_t* g_pcont __attribute__((section(".noinit")));
|
||||
|
||||
/* Event queue used by the main (arduino) task */
|
||||
static os_event_t s_loop_queue[LOOP_QUEUE_SIZE];
|
||||
|
||||
/* Used to implement optimistic_yield */
|
||||
static uint32_t s_micros_at_task_start;
|
||||
|
||||
/* For ets_intr_lock_nest / ets_intr_unlock_nest
|
||||
* Max nesting seen by SDK so far is 2.
|
||||
*/
|
||||
#define ETS_INTR_LOCK_NEST_MAX 7
|
||||
static uint16_t ets_intr_lock_stack[ETS_INTR_LOCK_NEST_MAX];
|
||||
static byte ets_intr_lock_stack_ptr = 0;
|
||||
|
||||
|
||||
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"
|
||||
|
||||
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 "C" bool can_yield()
|
||||
{
|
||||
return cont_can_yield(g_pcont);
|
||||
}
|
||||
|
||||
static inline void esp_yield_within_cont() __attribute__((always_inline));
|
||||
static void esp_yield_within_cont()
|
||||
{
|
||||
cont_yield(g_pcont);
|
||||
run_scheduled_recurrent_functions();
|
||||
}
|
||||
|
||||
extern "C" void esp_yield()
|
||||
{
|
||||
if (can_yield()) {
|
||||
esp_yield_within_cont();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void esp_schedule()
|
||||
{
|
||||
// always on CONT stack here
|
||||
ets_post(LOOP_TASK_PRIORITY, 0, 0);
|
||||
}
|
||||
|
||||
extern "C" void __yield()
|
||||
{
|
||||
if (can_yield()) {
|
||||
esp_schedule();
|
||||
esp_yield_within_cont();
|
||||
} else {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void yield(void) __attribute__((weak, alias("__yield")));
|
||||
|
||||
extern "C" void optimistic_yield(uint32_t interval_us)
|
||||
{
|
||||
if (can_yield() &&
|
||||
(system_get_time() - s_micros_at_task_start) > interval_us) {
|
||||
yield();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Replace ets_intr_(un)lock with nestable versions
|
||||
extern "C" void IRAM_ATTR ets_intr_lock()
|
||||
{
|
||||
if (ets_intr_lock_stack_ptr < ETS_INTR_LOCK_NEST_MAX) {
|
||||
ets_intr_lock_stack[ets_intr_lock_stack_ptr++] = xt_rsil(3);
|
||||
} else {
|
||||
xt_rsil(3);
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" void IRAM_ATTR ets_intr_unlock()
|
||||
{
|
||||
if (ets_intr_lock_stack_ptr > 0) {
|
||||
xt_wsr_ps(ets_intr_lock_stack[--ets_intr_lock_stack_ptr]);
|
||||
} else {
|
||||
xt_rsil(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Save / Restore the PS state across the rom ets_post call as the rom code
|
||||
// does not implement this correctly.
|
||||
extern "C" bool ets_post_rom(uint8 prio, ETSSignal sig, ETSParam par);
|
||||
|
||||
extern "C" bool IRAM_ATTR ets_post(uint8 prio, ETSSignal sig, ETSParam par)
|
||||
{
|
||||
uint32_t saved;
|
||||
asm volatile ("rsr %0,ps":"=a" (saved));
|
||||
bool rc = ets_post_rom(prio, sig, par);
|
||||
xt_wsr_ps(saved);
|
||||
return rc;
|
||||
}
|
||||
|
||||
extern "C" void __loop_end(void)
|
||||
{
|
||||
run_scheduled_functions();
|
||||
run_scheduled_recurrent_functions();
|
||||
}
|
||||
|
||||
extern "C" void loop_end(void) __attribute__((weak, alias("__loop_end")));
|
||||
|
||||
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;
|
||||
s_micros_at_task_start = system_get_time();
|
||||
cont_run(g_pcont, &loop_wrapper);
|
||||
if (cont_check(g_pcont) != 0) {
|
||||
panic();
|
||||
}
|
||||
}
|
||||
extern "C" {
|
||||
|
||||
struct object {
|
||||
long placeholder[10];
|
||||
};
|
||||
void __register_frame_info(const void *begin, struct object *ob);
|
||||
extern char __eh_frame[];
|
||||
}
|
||||
|
||||
static void do_global_ctors(void)
|
||||
{
|
||||
static struct object ob;
|
||||
__register_frame_info(__eh_frame, &ob);
|
||||
|
||||
void(**p)(void) = &__init_array_end;
|
||||
while (p != &__init_array_start) {
|
||||
(*--p)();
|
||||
}
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
extern void __unhandled_exception(const char *str);
|
||||
|
||||
static void __unhandled_exception_cpp()
|
||||
{
|
||||
#ifndef __EXCEPTIONS
|
||||
abort();
|
||||
#else
|
||||
static bool terminating;
|
||||
if (terminating) {
|
||||
abort();
|
||||
}
|
||||
terminating = true;
|
||||
/* Use a trick from vterminate.cc to get any std::exception what() */
|
||||
try {
|
||||
__throw_exception_again;
|
||||
} catch (const std::exception& e) {
|
||||
__unhandled_exception(e.what());
|
||||
} catch (...) {
|
||||
__unhandled_exception("");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void init_done()
|
||||
{
|
||||
system_set_os_print(1);
|
||||
gdb_init();
|
||||
std::set_terminate(__unhandled_exception_cpp);
|
||||
do_global_ctors();
|
||||
esp_schedule();
|
||||
}
|
||||
|
||||
/* This is the entry point of the application.
|
||||
* It gets called on the default stack, which grows down from the top
|
||||
* of DRAM area.
|
||||
* .bss has not been zeroed out yet, but .data and .rodata are in place.
|
||||
* Cache is not enabled, so only ROM and IRAM functions can be called.
|
||||
* Peripherals (except for SPI0 and UART0) are not initialized.
|
||||
* This function does not return.
|
||||
*/
|
||||
/*
|
||||
A bit of explanation for this entry point:
|
||||
|
||||
SYS is the SDK task/context used by the upperlying system to run its
|
||||
administrative tasks (at least WLAN and lwip's receive callbacks and
|
||||
Ticker). NONOS-SDK is designed to run user's non-threaded code in
|
||||
another specific task/context with its own stack in BSS.
|
||||
|
||||
Some clever fellows found that the SYS stack was a large and quite unused
|
||||
piece of ram that we could use for the user's stack instead of using user's
|
||||
main memory, thus saving around 4KB on ram/heap.
|
||||
|
||||
A problem arose later, which is that this stack can heavily be used by
|
||||
the SDK for some features. One of these features is WPS. We still don't
|
||||
know if other features are using this, or if this memory is going to be
|
||||
used in future SDK releases.
|
||||
|
||||
WPS beeing flawed by its poor security, or not beeing used by lots of
|
||||
users, it has been decided that we are still going to use that memory for
|
||||
user's stack and disable the use of WPS.
|
||||
|
||||
app_entry() jumps to app_entry_custom() defined as "weakref" calling
|
||||
itself a weak customizable function, allowing to use another one when
|
||||
this is required (see core_esp8266_app_entry_noextra4k.cpp, used by WPS).
|
||||
|
||||
(note: setting app_entry() itself as "weak" is not sufficient and always
|
||||
ends up with the other "noextra4k" one linked, maybe because it has a
|
||||
default ENTRY(app_entry) value in linker scripts).
|
||||
|
||||
References:
|
||||
https://github.com/esp8266/Arduino/pull/4553
|
||||
https://github.com/esp8266/Arduino/pull/4622
|
||||
https://github.com/esp8266/Arduino/issues/4779
|
||||
https://github.com/esp8266/Arduino/pull/4889
|
||||
|
||||
*/
|
||||
|
||||
extern "C" void app_entry_redefinable(void) __attribute__((weak));
|
||||
extern "C" void app_entry_redefinable(void)
|
||||
{
|
||||
/* Allocate continuation context on this SYS stack,
|
||||
and save pointer to it. */
|
||||
cont_t s_cont __attribute__((aligned(16)));
|
||||
g_pcont = &s_cont;
|
||||
|
||||
/* Call the entry point of the SDK code. */
|
||||
call_user_start();
|
||||
}
|
||||
|
||||
static void app_entry_custom(void) __attribute__((weakref("app_entry_redefinable")));
|
||||
|
||||
extern "C" void app_entry(void)
|
||||
{
|
||||
return app_entry_custom();
|
||||
}
|
||||
|
||||
extern "C" void preinit(void) __attribute__((weak));
|
||||
extern "C" void preinit(void)
|
||||
{
|
||||
/* do nothing by default */
|
||||
}
|
||||
|
||||
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(); // in core_esp8266_wiring.c, inits hw regs and sdk timer
|
||||
|
||||
initVariant();
|
||||
|
||||
cont_init(g_pcont);
|
||||
|
||||
preinit(); // Prior to C++ Dynamic Init (not related to above init() ). Meant to be user redefinable.
|
||||
|
||||
ets_task(loop_task,
|
||||
LOOP_TASK_PRIORITY, s_loop_queue,
|
||||
LOOP_QUEUE_SIZE);
|
||||
|
||||
system_init_done_cb(&init_done);
|
||||
}
|
||||
165
lib/MySensors/hal/architecture/Linux/MyHwLinuxGeneric.cpp
Normal file
165
lib/MySensors/hal/architecture/Linux/MyHwLinuxGeneric.cpp
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MyHwLinuxGeneric.h"
|
||||
|
||||
static SoftEeprom eeprom;
|
||||
static FILE *randomFp = NULL;
|
||||
|
||||
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
|
||||
|
||||
if (eeprom.init(conf.eeprom_file, conf.eeprom_size) != 0) {
|
||||
exit(1);
|
||||
}
|
||||
|
||||
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(const int addr)
|
||||
{
|
||||
return eeprom.readByte(addr);
|
||||
}
|
||||
|
||||
void hwWriteConfig(const int addr, uint8_t value)
|
||||
{
|
||||
eeprom.writeByte(addr, value);
|
||||
}
|
||||
|
||||
void hwRandomNumberInit(void)
|
||||
{
|
||||
uint32_t seed=0;
|
||||
|
||||
if (randomFp != NULL) {
|
||||
fclose(randomFp);
|
||||
}
|
||||
if (!(randomFp = fopen("/dev/urandom", "r"))) {
|
||||
logError("Cannot open '/dev/urandom'.\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
while (hwGetentropy(&seed, sizeof(seed)) != sizeof(seed));
|
||||
randomSeed(seed);
|
||||
}
|
||||
|
||||
ssize_t hwGetentropy(void *__buffer, size_t __length)
|
||||
{
|
||||
return(fread(__buffer, 1, __length, randomFp));
|
||||
}
|
||||
|
||||
uint32_t hwMillis(void)
|
||||
{
|
||||
return millis();
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
// not implemented yet
|
||||
(void)uniqueID;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not supported!
|
||||
int8_t hwSleep(uint32_t ms)
|
||||
{
|
||||
(void)ms;
|
||||
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
// Not supported!
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
// Not supported!
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t ms)
|
||||
{
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency(void)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
return -127; // not implemented yet
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
116
lib/MySensors/hal/architecture/Linux/MyHwLinuxGeneric.h
Normal file
116
lib/MySensors/hal/architecture/Linux/MyHwLinuxGeneric.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MyHwLinuxGeneric_h
|
||||
#define MyHwLinuxGeneric_h
|
||||
|
||||
#include <cstdlib>
|
||||
#include <pthread.h>
|
||||
#include "SerialPort.h"
|
||||
#include "StdInOutStream.h"
|
||||
#include <SPI.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <syscall.h>
|
||||
#include <unistd.h>
|
||||
#include "SoftEeprom.h"
|
||||
#include "log.h"
|
||||
#include "config.h"
|
||||
|
||||
#define CRYPTO_LITTLE_ENDIAN
|
||||
|
||||
#ifdef MY_LINUX_SERIAL_PORT
|
||||
#ifdef MY_LINUX_SERIAL_IS_PTY
|
||||
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT, true);
|
||||
#else
|
||||
SerialPort Serial = SerialPort(MY_LINUX_SERIAL_PORT, false);
|
||||
#endif
|
||||
#else
|
||||
StdInOutStream Serial = StdInOutStream();
|
||||
#endif
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE Serial
|
||||
#endif
|
||||
|
||||
// Define these as macros (do nothing)
|
||||
#define hwWatchdogReset()
|
||||
#define hwReboot()
|
||||
#define hwGetSleepRemaining() (0ul)
|
||||
|
||||
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(const int addr);
|
||||
inline void hwWriteConfig(const int addr, uint8_t value);
|
||||
inline void hwRandomNumberInit(void);
|
||||
ssize_t hwGetentropy(void *__buffer, size_t __length);
|
||||
#define MY_HW_HAS_GETENTROPY
|
||||
inline uint32_t hwMillis(void);
|
||||
|
||||
// SOFTSPI
|
||||
#ifdef MY_SOFTSPI
|
||||
#error Soft SPI is not available on this architecture!
|
||||
#endif
|
||||
#define hwSPI SPI //!< hwSPI
|
||||
|
||||
#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
|
||||
488
lib/MySensors/hal/architecture/Linux/MyMainLinuxGeneric.cpp
Normal file
488
lib/MySensors/hal/architecture/Linux/MyMainLinuxGeneric.cpp
Normal file
@@ -0,0 +1,488 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
#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 "config.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
|
||||
|
||||
logClose();
|
||||
|
||||
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" \
|
||||
" -c, --config-file Config file. [" MY_LINUX_CONFIG_FILE "]\n" \
|
||||
" -h, --help Display a short summary of all program options.\n" \
|
||||
" -q, --quiet Quiet mode, disable log messages written to the terminal.\n" \
|
||||
" --daemon Run as a daemon.\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");
|
||||
}
|
||||
|
||||
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_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(char *config_file = NULL)
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
printf("Generating key...");
|
||||
while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
|
||||
printf(" done.\n");
|
||||
|
||||
printf("To use the new key, update the value in %s witn:\n",
|
||||
config_file?config_file:MY_LINUX_CONFIG_FILE);
|
||||
print_soft_sign_hmac_key(key);
|
||||
|
||||
#if defined(MY_SIGNING_SIMPLE_PASSWD)
|
||||
printf("Note: The gateway was built with simplified signing using the password: %s\n" \
|
||||
" Any key set with soft_hmac_key option in the config file is ignored.\n\n",
|
||||
MY_SIGNING_SIMPLE_PASSWD);
|
||||
#elif !defined(MY_SIGNING_FEATURE)
|
||||
printf("Note: The gateway was not built with signing support.\n" \
|
||||
" Any key set with soft_hmac_key option in the config file is ignored.\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_soft_sign_hmac_key(char *key_str)
|
||||
{
|
||||
uint8_t key[32];
|
||||
|
||||
if (strlen(key_str) != 64) {
|
||||
logWarning("Invalid HMAC 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);
|
||||
}
|
||||
}
|
||||
|
||||
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_key=");
|
||||
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(char *config_file = NULL)
|
||||
{
|
||||
uint8_t key[9];
|
||||
|
||||
printf("Generating key...");
|
||||
while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
|
||||
printf(" done.\n");
|
||||
|
||||
printf("To use the new key, update the value in %s witn:\n",
|
||||
config_file?config_file:MY_LINUX_CONFIG_FILE);
|
||||
print_soft_sign_serial_key(key);
|
||||
|
||||
#if defined(MY_SIGNING_SIMPLE_PASSWD)
|
||||
printf("Note: The gateway was built with simplified signing using the password: %s\n" \
|
||||
" Any key set with soft_serial_key option in the config file is ignored.\n\n",
|
||||
MY_SIGNING_SIMPLE_PASSWD);
|
||||
#elif !defined(MY_SIGNING_FEATURE)
|
||||
printf("Note: The gateway was not built with signing support.\n" \
|
||||
" Any key set with soft_serial_key option in the config file is ignored.\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_soft_sign_serial_key(char *key_str)
|
||||
{
|
||||
uint8_t key[9];
|
||||
|
||||
if (strlen(key_str) != 18) {
|
||||
logWarning("Invalid soft serial 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);
|
||||
}
|
||||
}
|
||||
|
||||
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(char *config_file = NULL)
|
||||
{
|
||||
uint8_t key[16];
|
||||
|
||||
printf("Generating key...");
|
||||
while (hwGetentropy(&key, sizeof(key)) != sizeof(key));
|
||||
printf(" done.\n");
|
||||
|
||||
printf("To use the new key, update the value in %s witn:\n",
|
||||
config_file?config_file:MY_LINUX_CONFIG_FILE);
|
||||
print_aes_key(key);
|
||||
|
||||
#if defined(MY_ENCRYPTION_SIMPLE_PASSWD)
|
||||
printf("Note: The gateway was built with simplified encryption using the password: %s\n" \
|
||||
" Any key set with aes_key option in the config file is ignored.\n\n",
|
||||
MY_ENCRYPTION_SIMPLE_PASSWD);
|
||||
#elif !defined(MY_ENCRYPTION_FEATURE)
|
||||
printf("Note: The gateway was not built with encryption support.\n" \
|
||||
" Any key set with aes_key option in the config file is ignored.\n\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
void set_aes_key(char *key_str)
|
||||
{
|
||||
uint8_t key[16];
|
||||
|
||||
if (strlen(key_str) != 32) {
|
||||
logWarning("Invalid AES 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);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int opt, daemon = 0, quiet = 0;
|
||||
char *config_file = NULL;
|
||||
bool gen_soft_sign_hmac_key = false;
|
||||
bool gen_soft_sign_serial_key = false;
|
||||
bool gen_aes_key = false;
|
||||
|
||||
/* register the signal handler */
|
||||
signal(SIGINT, handle_sigint);
|
||||
signal(SIGTERM, handle_sigint);
|
||||
signal(SIGPIPE, handle_sigint);
|
||||
|
||||
hwRandomNumberInit();
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"config-file", required_argument, 0, 'c'},
|
||||
{"daemon", no_argument, 0, 'J'},
|
||||
{"help", no_argument, 0, 'h'},
|
||||
{"quiet", no_argument, 0, 'q'},
|
||||
{"gen-soft-hmac-key", no_argument, 0, 'A'},
|
||||
{"gen-soft-serial-key", no_argument, 0, 'B'},
|
||||
{"gen-aes-key", no_argument, 0, 'C'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
int long_index = 0;
|
||||
while ((opt = getopt_long(argc, argv,"chqABCJ", long_options, &long_index )) != -1) {
|
||||
switch (opt) {
|
||||
case 'c':
|
||||
config_file = strdup(optarg);
|
||||
break;
|
||||
case 'h':
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
case 'q':
|
||||
quiet = 1;
|
||||
break;
|
||||
case 'A':
|
||||
gen_soft_sign_hmac_key = true;
|
||||
break;
|
||||
case 'B':
|
||||
gen_soft_sign_serial_key = true;
|
||||
break;
|
||||
case 'C':
|
||||
gen_aes_key = true;
|
||||
break;
|
||||
case 'J':
|
||||
daemon = 1;
|
||||
break;
|
||||
default:
|
||||
print_usage();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
if (gen_soft_sign_hmac_key || gen_soft_sign_serial_key || gen_aes_key) {
|
||||
if (gen_soft_sign_hmac_key) {
|
||||
generate_soft_sign_hmac_key(config_file);
|
||||
}
|
||||
if (gen_soft_sign_serial_key) {
|
||||
generate_soft_sign_serial_key(config_file);
|
||||
}
|
||||
if (gen_aes_key) {
|
||||
generate_aes_key(config_file);
|
||||
}
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
if (daemon) {
|
||||
if (daemonize() != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
quiet = 1;
|
||||
}
|
||||
|
||||
if (config_parse(config_file?config_file:MY_LINUX_CONFIG_FILE) != 0) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
logSetQuiet(quiet);
|
||||
logSetLevel(conf.verbose);
|
||||
|
||||
if (conf.log_file) {
|
||||
if (logSetFile(conf.log_filepath) != 0) {
|
||||
logError("Failed to open log file.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.log_pipe) {
|
||||
if (logSetPipe(conf.log_pipe_file) != 0) {
|
||||
logError("Failed to open log pipe.\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (conf.syslog) {
|
||||
logSetSyslog(LOG_CONS, LOG_USER);
|
||||
}
|
||||
|
||||
logInfo("Starting gateway...\n");
|
||||
logInfo("Protocol version - %s\n", MYSENSORS_LIBRARY_VERSION);
|
||||
|
||||
_begin(); // Startup MySensors library
|
||||
|
||||
// EEPROM is initialized within _begin()
|
||||
// any operation on it must be done hereafter
|
||||
|
||||
#if defined(MY_SIGNING_FEATURE) && !defined(MY_SIGNING_SIMPLE_PASSWD)
|
||||
// Check if we need to update the signing keys in EEPROM
|
||||
if (conf.soft_hmac_key) {
|
||||
set_soft_sign_hmac_key(conf.soft_hmac_key);
|
||||
} else {
|
||||
logError("soft_hmac_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if (conf.soft_serial_key) {
|
||||
set_soft_sign_serial_key(conf.soft_serial_key);
|
||||
} else {
|
||||
logError("soft_serial_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
#if defined(MY_ENCRYPTION_FEATURE) && !defined(MY_ENCRYPTION_SIMPLE_PASSWD)
|
||||
// Check if we need to update the encryption key in EEPROM
|
||||
if (conf.aes_key) {
|
||||
set_aes_key(conf.aes_key);
|
||||
} else {
|
||||
logError("aes_key was not found in %s\n", config_file?config_file:MY_LINUX_CONFIG_FILE);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (config_file) {
|
||||
free(config_file);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) {
|
||||
loop(); // Call sketch loop
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
80
lib/MySensors/hal/architecture/Linux/drivers/BCM/BCM.cpp
Normal file
80
lib/MySensors/hal/architecture/Linux/drivers/BCM/BCM.cpp
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "BCM.h"
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
// Declare a single default instance
|
||||
BCMClass BCM = BCMClass();
|
||||
|
||||
uint8_t BCMClass::initialized = 0;
|
||||
|
||||
BCMClass::~BCMClass()
|
||||
{
|
||||
if (initialized) {
|
||||
bcm2835_close();
|
||||
initialized = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t BCMClass::init()
|
||||
{
|
||||
if (!bcm2835_init()) {
|
||||
logError("Failed to initialized bcm2835.\n");
|
||||
exit(1);
|
||||
}
|
||||
initialized = 1;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void BCMClass::pinMode(uint8_t gpio, uint8_t mode)
|
||||
{
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
bcm2835_gpio_fsel(gpio, mode);
|
||||
}
|
||||
|
||||
void BCMClass::digitalWrite(uint8_t gpio, uint8_t value)
|
||||
{
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
bcm2835_gpio_write(gpio, value);
|
||||
// Delay to allow any change in state to be reflected in the LEVn, register bit.
|
||||
delayMicroseconds(1);
|
||||
}
|
||||
|
||||
uint8_t BCMClass::digitalRead(uint8_t gpio)
|
||||
{
|
||||
if (!initialized) {
|
||||
init();
|
||||
}
|
||||
|
||||
return bcm2835_gpio_lev(gpio);
|
||||
}
|
||||
|
||||
uint8_t BCMClass::isInitialized()
|
||||
{
|
||||
return initialized;
|
||||
}
|
||||
92
lib/MySensors/hal/architecture/Linux/drivers/BCM/BCM.h
Normal file
92
lib/MySensors/hal/architecture/Linux/drivers/BCM/BCM.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef BCM_h
|
||||
#define BCM_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "bcm2835.h"
|
||||
|
||||
#define INPUT BCM2835_GPIO_FSEL_INPT
|
||||
#define OUTPUT BCM2835_GPIO_FSEL_OUTP
|
||||
|
||||
/**
|
||||
* @brief BCM class
|
||||
*/
|
||||
class BCMClass
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief BCMClass destructor.
|
||||
*/
|
||||
~BCMClass();
|
||||
/**
|
||||
* @brief Initializes BCM.
|
||||
*
|
||||
* @return 1 if successful, else exits the program.
|
||||
*/
|
||||
uint8_t init();
|
||||
/**
|
||||
* @brief Configures the specified pin to behave either as an input or an output.
|
||||
*
|
||||
* @param gpio The GPIO pin number.
|
||||
* @param mode INPUT or OUTPUT.
|
||||
*/
|
||||
void pinMode(uint8_t gpio, uint8_t mode);
|
||||
/**
|
||||
* @brief Write a high or a low value for the given pin.
|
||||
*
|
||||
* @param gpio The GPIO pin number.
|
||||
* @param value HIGH or LOW.
|
||||
*/
|
||||
void digitalWrite(uint8_t gpio, uint8_t value);
|
||||
/**
|
||||
* @brief Reads the value from a specified pin.
|
||||
*
|
||||
* @param gpio The GPIO pin number.
|
||||
* @return HIGH or LOW.
|
||||
*/
|
||||
uint8_t digitalRead(uint8_t gpio);
|
||||
/**
|
||||
* @brief Returns the same GPIO, no conversion is required.
|
||||
*
|
||||
* @param gpio The GPIO pin number.
|
||||
* @return The GPIO pin number.
|
||||
*/
|
||||
inline uint8_t digitalPinToInterrupt(uint8_t gpio);
|
||||
/**
|
||||
* @brief Checks if SPI was initialized.
|
||||
*
|
||||
* @return 1 if initialized, else 0.
|
||||
*/
|
||||
uint8_t isInitialized();
|
||||
|
||||
private:
|
||||
static uint8_t initialized; //!< @brief BCM initialized flag.
|
||||
};
|
||||
|
||||
uint8_t BCMClass::digitalPinToInterrupt(uint8_t gpio)
|
||||
{
|
||||
return gpio;
|
||||
}
|
||||
|
||||
extern BCMClass BCM;
|
||||
|
||||
#endif
|
||||
167
lib/MySensors/hal/architecture/Linux/drivers/BCM/RPi.cpp
Normal file
167
lib/MySensors/hal/architecture/Linux/drivers/BCM/RPi.cpp
Normal file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "RPi.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "log.h"
|
||||
|
||||
const static int phys_to_gpio_rev1[41] = {-1, -1, -1, 0, -1, 1, -1, 4, 14, -1, 15, 17, 18, 21, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1};
|
||||
const static int phys_to_gpio_rev2[41] = {-1, -1, -1, 2, -1, 3, -1, 4, 14, -1, 15, 17, 18, 27, -1, 22, 23, -1, 24, 10, -1, 9, 25, 11, 8, -1, 7, -1, -1, 5, -1, 6, 12, 13, -1, 19, 16, 26, 20, -1, 21};
|
||||
|
||||
// Declare a single default instance
|
||||
RPiClass RPi = RPiClass();
|
||||
|
||||
const int* RPiClass::phys_to_gpio = NULL;
|
||||
|
||||
void RPiClass::pinMode(uint8_t physPin, uint8_t mode)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin) != 0) {
|
||||
logError("pinMode: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
BCM.pinMode(gpioPin, mode);
|
||||
}
|
||||
|
||||
void RPiClass::digitalWrite(uint8_t physPin, uint8_t value)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin) != 0) {
|
||||
logError("digitalWrite: invalid pin: %d\n", physPin);
|
||||
return;
|
||||
}
|
||||
|
||||
BCM.digitalWrite(gpioPin, value);
|
||||
}
|
||||
|
||||
uint8_t RPiClass::digitalRead(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin) != 0) {
|
||||
logError("digitalRead: invalid pin: %d\n", physPin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return BCM.digitalRead(gpioPin);
|
||||
}
|
||||
|
||||
uint8_t RPiClass::digitalPinToInterrupt(uint8_t physPin)
|
||||
{
|
||||
uint8_t gpioPin;
|
||||
|
||||
if (physToGPIO(physPin, &gpioPin) != 0) {
|
||||
logError("digitalPinToInterrupt: invalid pin: %d\n", physPin);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return gpioPin;
|
||||
}
|
||||
|
||||
int RPiClass::rpiGpioLayout()
|
||||
{
|
||||
/*
|
||||
* Based on wiringPi Copyright (c) 2012 Gordon Henderson.
|
||||
*/
|
||||
FILE *fd;
|
||||
char line[120];
|
||||
char *c;
|
||||
|
||||
if ((fd = fopen("/proc/cpuinfo", "r")) == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (fgets(line, 120, fd) != NULL) {
|
||||
if (strncmp(line, "Revision", 8) == 0) {
|
||||
fclose(fd);
|
||||
// Chop trailing CR/NL
|
||||
for (c = &line[strlen(line) - 1]; (*c == '\n') || (*c == '\r'); --c) {
|
||||
*c = 0;
|
||||
}
|
||||
// Scan to the first character of the revision number
|
||||
for (c = line; *c; ++c) {
|
||||
if (*c == ':') {
|
||||
// Chop spaces
|
||||
++c;
|
||||
while (isspace(*c)) {
|
||||
++c;
|
||||
}
|
||||
|
||||
// Check hex digit at start
|
||||
if (!isxdigit(*c)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check bogus revision line (too small)
|
||||
if (strlen(c) < 4) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Isolate last 4 characters: (in-case of overvolting or new encoding scheme)
|
||||
c = c + strlen(c) - 4;
|
||||
|
||||
if ((strcmp(c, "0002") == 0) || (strcmp(c, "0003") == 0) ||
|
||||
(strcmp(c, "0004") == 0) || (strcmp(c, "0005") == 0) ||
|
||||
(strcmp(c, "0006") == 0) || (strcmp(c, "0007") == 0) ||
|
||||
(strcmp(c, "0008") == 0) || (strcmp(c, "0009") == 0) ||
|
||||
(strcmp(c, "000d") == 0) || (strcmp(c, "000e") == 0) ||
|
||||
(strcmp(c, "000f") == 0)) {
|
||||
return 1;
|
||||
} else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int RPiClass::physToGPIO(uint8_t physPin, uint8_t *gpio)
|
||||
{
|
||||
if (phys_to_gpio == NULL) {
|
||||
if (rpiGpioLayout() == 1) {
|
||||
// A, B, Rev 1, 1.1
|
||||
phys_to_gpio = &phys_to_gpio_rev1[0];
|
||||
} else {
|
||||
// A2, B2, A+, B+, CM, Pi2, Pi3, Zero
|
||||
phys_to_gpio = &phys_to_gpio_rev2[0];
|
||||
}
|
||||
}
|
||||
|
||||
if (gpio == NULL || physPin > 40) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int pin = *(phys_to_gpio+physPin);
|
||||
if (pin == -1) {
|
||||
return -1;
|
||||
} else {
|
||||
*gpio = pin;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
82
lib/MySensors/hal/architecture/Linux/drivers/BCM/RPi.h
Normal file
82
lib/MySensors/hal/architecture/Linux/drivers/BCM/RPi.h
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef RPi_h
|
||||
#define RPi_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include "BCM.h"
|
||||
|
||||
/**
|
||||
* @brief RPi class
|
||||
*/
|
||||
class RPiClass
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Configures the specified pin to behave either as an input or an output.
|
||||
*
|
||||
* @param physPin The physical number of the pin.
|
||||
* @param mode INPUT or OUTPUT.
|
||||
*/
|
||||
void pinMode(uint8_t physPin, uint8_t mode);
|
||||
/**
|
||||
* @brief Write a high or a low value for the given pin.
|
||||
*
|
||||
* @param physPin The physical number of the pin.
|
||||
* @param value HIGH or LOW.
|
||||
*/
|
||||
void digitalWrite(uint8_t physPin, uint8_t value);
|
||||
/**
|
||||
* @brief Reads the value from a specified pin.
|
||||
*
|
||||
* @param physPin The physical number of the pin.
|
||||
* @return HIGH or LOW.
|
||||
*/
|
||||
uint8_t digitalRead(uint8_t physPin);
|
||||
/**
|
||||
* @brief Translate the physical pin number to the GPIO number for use in interrupt.
|
||||
*
|
||||
* @param physPin The physical number of the pin.
|
||||
* @return The GPIO pin number.
|
||||
*/
|
||||
uint8_t digitalPinToInterrupt(uint8_t physPin);
|
||||
/**
|
||||
* @brief Translate the physical pin number to the GPIO number.
|
||||
*
|
||||
* @param physPin The physical number of the pin.
|
||||
* @param gpio Pointer to write the GPIO pin number when success.
|
||||
* @return -1 if FAILURE or 0 if SUCCESS.
|
||||
*/
|
||||
static int physToGPIO(uint8_t physPin, uint8_t *gpio);
|
||||
|
||||
private:
|
||||
static const int *phys_to_gpio; //!< @brief Pointer to array of GPIO pins numbers.
|
||||
/**
|
||||
* @brief Get the gpio layout.
|
||||
*
|
||||
* @return The gpio layout number.
|
||||
*/
|
||||
static int rpiGpioLayout(void);
|
||||
};
|
||||
|
||||
extern RPiClass RPi;
|
||||
|
||||
#endif
|
||||
110
lib/MySensors/hal/architecture/Linux/drivers/BCM/SPIBCM.cpp
Normal file
110
lib/MySensors/hal/architecture/Linux/drivers/BCM/SPIBCM.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
|
||||
*/
|
||||
|
||||
#include "SPIBCM.h"
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include "log.h"
|
||||
|
||||
static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
// Declare a single default instance
|
||||
SPIBCMClass SPIBCM = SPIBCMClass();
|
||||
|
||||
uint8_t SPIBCMClass::initialized = 0;
|
||||
|
||||
void SPIBCMClass::begin()
|
||||
{
|
||||
if (!initialized) {
|
||||
if (!BCM.isInitialized()) {
|
||||
BCM.init();
|
||||
}
|
||||
if (!bcm2835_spi_begin()) {
|
||||
logError("You need root privilege to use SPI.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
initialized++; // reference count
|
||||
}
|
||||
|
||||
void SPIBCMClass::end()
|
||||
{
|
||||
if (initialized) {
|
||||
initialized--;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
// End the SPI
|
||||
bcm2835_spi_end();
|
||||
}
|
||||
}
|
||||
|
||||
void SPIBCMClass::setBitOrder(uint8_t bit_order)
|
||||
{
|
||||
bcm2835_spi_setBitOrder(bit_order);
|
||||
}
|
||||
|
||||
void SPIBCMClass::setDataMode(uint8_t data_mode)
|
||||
{
|
||||
bcm2835_spi_setDataMode(data_mode);
|
||||
}
|
||||
|
||||
void SPIBCMClass::setClockDivider(uint16_t divider)
|
||||
{
|
||||
bcm2835_spi_setClockDivider(divider);
|
||||
}
|
||||
|
||||
void SPIBCMClass::chipSelect(int csn_pin)
|
||||
{
|
||||
if (csn_pin == RPI_GPIO_P1_26) {
|
||||
csn_pin = BCM2835_SPI_CS1;
|
||||
} else if (csn_pin == RPI_GPIO_P1_24) {
|
||||
csn_pin = BCM2835_SPI_CS0;
|
||||
} else {
|
||||
csn_pin = BCM2835_SPI_CS0;
|
||||
}
|
||||
bcm2835_spi_chipSelect(csn_pin);
|
||||
delayMicroseconds(5);
|
||||
}
|
||||
|
||||
void SPIBCMClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
setBitOrder(settings.border);
|
||||
setDataMode(settings.dmode);
|
||||
setClockDivider(settings.cdiv);
|
||||
}
|
||||
|
||||
void SPIBCMClass::endTransaction()
|
||||
{
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIBCMClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
|
||||
void SPIBCMClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
262
lib/MySensors/hal/architecture/Linux/drivers/BCM/SPIBCM.h
Normal file
262
lib/MySensors/hal/architecture/Linux/drivers/BCM/SPIBCM.h
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef SPIBCM_h
|
||||
#define SPIBCM_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include "bcm2835.h"
|
||||
#include "BCM.h"
|
||||
|
||||
#define SPI_HAS_TRANSACTION
|
||||
|
||||
#define SPI_CLOCK_BASE 256000000
|
||||
|
||||
// SPI Clock divider
|
||||
#define SPI_CLOCK_DIV1 BCM2835_SPI_CLOCK_DIVIDER_1
|
||||
#define SPI_CLOCK_DIV2 BCM2835_SPI_CLOCK_DIVIDER_2
|
||||
#define SPI_CLOCK_DIV4 BCM2835_SPI_CLOCK_DIVIDER_4
|
||||
#define SPI_CLOCK_DIV8 BCM2835_SPI_CLOCK_DIVIDER_8
|
||||
#define SPI_CLOCK_DIV16 BCM2835_SPI_CLOCK_DIVIDER_16
|
||||
#define SPI_CLOCK_DIV32 BCM2835_SPI_CLOCK_DIVIDER_32
|
||||
#define SPI_CLOCK_DIV64 BCM2835_SPI_CLOCK_DIVIDER_64
|
||||
#define SPI_CLOCK_DIV128 BCM2835_SPI_CLOCK_DIVIDER_128
|
||||
#define SPI_CLOCK_DIV256 BCM2835_SPI_CLOCK_DIVIDER_256
|
||||
#define SPI_CLOCK_DIV512 BCM2835_SPI_CLOCK_DIVIDER_512
|
||||
#define SPI_CLOCK_DIV1024 BCM2835_SPI_CLOCK_DIVIDER_1024
|
||||
#define SPI_CLOCK_DIV2048 BCM2835_SPI_CLOCK_DIVIDER_2048
|
||||
#define SPI_CLOCK_DIV4096 BCM2835_SPI_CLOCK_DIVIDER_4096
|
||||
#define SPI_CLOCK_DIV8192 BCM2835_SPI_CLOCK_DIVIDER_8192
|
||||
#define SPI_CLOCK_DIV16384 BCM2835_SPI_CLOCK_DIVIDER_16384
|
||||
#define SPI_CLOCK_DIV32768 BCM2835_SPI_CLOCK_DIVIDER_32768
|
||||
#define SPI_CLOCK_DIV65536 BCM2835_SPI_CLOCK_DIVIDER_65536
|
||||
|
||||
// SPI Data mode
|
||||
#define SPI_MODE0 BCM2835_SPI_MODE0
|
||||
#define SPI_MODE1 BCM2835_SPI_MODE1
|
||||
#define SPI_MODE2 BCM2835_SPI_MODE2
|
||||
#define SPI_MODE3 BCM2835_SPI_MODE3
|
||||
|
||||
#define LSBFIRST BCM2835_SPI_BIT_ORDER_LSBFIRST
|
||||
#define MSBFIRST BCM2835_SPI_BIT_ORDER_MSBFIRST
|
||||
|
||||
const uint8_t SS = 24;
|
||||
const uint8_t MOSI = 19;
|
||||
const uint8_t MISO = 21;
|
||||
const uint8_t SCK = 23;
|
||||
|
||||
/**
|
||||
* SPISettings class
|
||||
*/
|
||||
class SPISettings
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SPISettings constructor.
|
||||
*
|
||||
* Default clock speed is 8Mhz.
|
||||
*/
|
||||
SPISettings()
|
||||
{
|
||||
init(SPI_CLOCK_DIV32, MSBFIRST, SPI_MODE0);
|
||||
}
|
||||
/**
|
||||
* @brief SPISettings constructor.
|
||||
*
|
||||
* @param clock SPI clock speed in Hz.
|
||||
* @param bitOrder SPI bit order.
|
||||
* @param dataMode SPI data mode.
|
||||
*/
|
||||
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
|
||||
{
|
||||
uint16_t divider;
|
||||
|
||||
if (clock >= SPI_CLOCK_BASE) {
|
||||
divider = SPI_CLOCK_DIV1;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 2) {
|
||||
divider = SPI_CLOCK_DIV2;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 4) {
|
||||
divider = SPI_CLOCK_DIV4;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 8) {
|
||||
divider = SPI_CLOCK_DIV8;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 16) {
|
||||
divider = SPI_CLOCK_DIV16;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 32) {
|
||||
divider = SPI_CLOCK_DIV32;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 64) {
|
||||
divider = SPI_CLOCK_DIV64;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 128) {
|
||||
divider = SPI_CLOCK_DIV128;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 256) {
|
||||
divider = SPI_CLOCK_DIV256;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 512) {
|
||||
divider = SPI_CLOCK_DIV512;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 1024) {
|
||||
divider = SPI_CLOCK_DIV1024;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 2048) {
|
||||
divider = SPI_CLOCK_DIV2048;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 4096) {
|
||||
divider = SPI_CLOCK_DIV4096;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 8192) {
|
||||
divider = SPI_CLOCK_DIV8192;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 16384) {
|
||||
divider = SPI_CLOCK_DIV16384;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 32768) {
|
||||
divider = SPI_CLOCK_DIV32768;
|
||||
} else if (clock >= SPI_CLOCK_BASE / 65536) {
|
||||
divider = SPI_CLOCK_DIV65536;
|
||||
} else {
|
||||
// Default to 8Mhz
|
||||
divider = SPI_CLOCK_DIV32;
|
||||
}
|
||||
|
||||
init(divider, bitOrder, dataMode);
|
||||
}
|
||||
|
||||
uint16_t cdiv; //!< @brief SPI clock divider.
|
||||
uint8_t border; //!< @brief SPI bit order.
|
||||
uint8_t dmode; //!< @brief SPI data mode.
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Initialized class members.
|
||||
*
|
||||
* @param divider SPI clock divider.
|
||||
* @param bitOrder SPI bit order.
|
||||
* @param dataMode SPI data mode.
|
||||
*/
|
||||
void init(uint16_t divider, uint8_t bitOrder, uint8_t dataMode)
|
||||
{
|
||||
cdiv = divider;
|
||||
border = bitOrder;
|
||||
dmode = dataMode;
|
||||
}
|
||||
|
||||
friend class SPIBCMClass;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPIBCM class
|
||||
*/
|
||||
class SPIBCMClass
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Send and receive a byte.
|
||||
*
|
||||
* @param data to send.
|
||||
* @return byte received.
|
||||
*/
|
||||
inline static uint8_t transfer(uint8_t data);
|
||||
/**
|
||||
* @brief Send and receive a number of bytes.
|
||||
*
|
||||
* @param tbuf Sending buffer.
|
||||
* @param rbuf Receive buffer.
|
||||
* @param len Buffer length.
|
||||
*/
|
||||
inline static void transfernb(char* tbuf, char* rbuf, uint32_t len);
|
||||
/**
|
||||
* @brief Send and receive a number of bytes.
|
||||
*
|
||||
* @param buf Buffer to read from and write to.
|
||||
* @param len Buffer length.
|
||||
*/
|
||||
inline static void transfern(char* buf, uint32_t len);
|
||||
/**
|
||||
* @brief Start SPI operations.
|
||||
*/
|
||||
static void begin();
|
||||
/**
|
||||
* @brief End SPI operations.
|
||||
*/
|
||||
static void end();
|
||||
/**
|
||||
* @brief Sets the SPI bit order.
|
||||
*
|
||||
* @param bit_order The desired bit order.
|
||||
*/
|
||||
static void setBitOrder(uint8_t bit_order);
|
||||
/**
|
||||
* @brief Sets the SPI data mode.
|
||||
*
|
||||
* @param data_mode The desired data mode.
|
||||
*/
|
||||
static void setDataMode(uint8_t data_mode);
|
||||
/**
|
||||
* @brief Sets the SPI clock divider and therefore the SPI clock speed.
|
||||
*
|
||||
* @param divider The desired SPI clock divider.
|
||||
*/
|
||||
static void setClockDivider(uint16_t divider);
|
||||
/**
|
||||
* @brief Sets the chip select pin.
|
||||
*
|
||||
* @param csn_pin Specifies the CS pin.
|
||||
*/
|
||||
static void chipSelect(int csn_pin);
|
||||
/**
|
||||
* @brief Start SPI transaction.
|
||||
*
|
||||
* @param settings for SPI.
|
||||
*/
|
||||
static void beginTransaction(SPISettings settings);
|
||||
/**
|
||||
* @brief End SPI transaction.
|
||||
*/
|
||||
static void endTransaction();
|
||||
/**
|
||||
* @brief Not implemented.
|
||||
*
|
||||
* @param interruptNumber ignored parameter.
|
||||
*/
|
||||
static void usingInterrupt(uint8_t interruptNumber);
|
||||
/**
|
||||
* @brief Not implemented.
|
||||
*
|
||||
* @param interruptNumber ignored parameter.
|
||||
*/
|
||||
static void notUsingInterrupt(uint8_t interruptNumber);
|
||||
|
||||
private:
|
||||
static uint8_t initialized; //!< @brief SPI initialized flag.
|
||||
};
|
||||
|
||||
uint8_t SPIBCMClass::transfer(uint8_t data)
|
||||
{
|
||||
return bcm2835_spi_transfer(data);
|
||||
}
|
||||
|
||||
void SPIBCMClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
|
||||
{
|
||||
bcm2835_spi_transfernb( tbuf, rbuf, len);
|
||||
}
|
||||
|
||||
void SPIBCMClass::transfern(char* buf, uint32_t len)
|
||||
{
|
||||
transfernb(buf, buf, len);
|
||||
}
|
||||
|
||||
extern SPIBCMClass SPIBCM;
|
||||
|
||||
#endif
|
||||
213
lib/MySensors/hal/architecture/Linux/drivers/BCM/Wire.cpp
Normal file
213
lib/MySensors/hal/architecture/Linux/drivers/BCM/Wire.cpp
Normal file
@@ -0,0 +1,213 @@
|
||||
/*
|
||||
TwoWire.h - TWI/I2C library for Arduino & Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
||||
|
||||
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
|
||||
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
|
||||
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
|
||||
Modified October 2016 by Marcelo Aquino <marceloaqno@gmail.org> for Raspberry Pi
|
||||
*/
|
||||
|
||||
#include "Wire.h"
|
||||
#include <stdlib.h>
|
||||
#include <pthread.h>
|
||||
#include "bcm2835.h"
|
||||
#include "log.h"
|
||||
|
||||
static pthread_mutex_t i2cMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
uint8_t TwoWire::rxBuffer[BUFFER_LENGTH];
|
||||
uint8_t TwoWire::rxBufferIndex = 0;
|
||||
uint8_t TwoWire::rxBufferLength = 0;
|
||||
|
||||
uint8_t TwoWire::txAddress = 0;
|
||||
uint8_t TwoWire::txBuffer[BUFFER_LENGTH];
|
||||
uint8_t TwoWire::txBufferIndex = 0;
|
||||
uint8_t TwoWire::txBufferLength = 0;
|
||||
|
||||
uint8_t TwoWire::transmitting = 0;
|
||||
|
||||
void TwoWire::begin()
|
||||
{
|
||||
if (!bcm2835_i2c_begin()) {
|
||||
logError("You need root privilege to use I2C.\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
void TwoWire::begin(uint8_t address)
|
||||
{
|
||||
begin();
|
||||
bcm2835_i2c_setSlaveAddress(address);
|
||||
}
|
||||
|
||||
void TwoWire::begin(int address)
|
||||
{
|
||||
begin(static_cast<uint8_t>(address));
|
||||
}
|
||||
|
||||
void TwoWire::end()
|
||||
{
|
||||
bcm2835_i2c_end();
|
||||
}
|
||||
|
||||
void TwoWire::setClock(uint32_t clock)
|
||||
{
|
||||
bcm2835_i2c_set_baudrate(clock);
|
||||
}
|
||||
|
||||
void TwoWire::beginTransmission(uint8_t address)
|
||||
{
|
||||
pthread_mutex_lock(&i2cMutex);
|
||||
// indicate that we are transmitting
|
||||
transmitting = 1;
|
||||
// set address of targeted slave
|
||||
txAddress = address;
|
||||
// reset tx buffer iterator vars
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
}
|
||||
|
||||
void TwoWire::beginTransmission(int address)
|
||||
{
|
||||
beginTransmission(static_cast<uint8_t>(address));
|
||||
}
|
||||
|
||||
uint8_t TwoWire::endTransmission(void)
|
||||
{
|
||||
// transmit buffer
|
||||
bcm2835_i2c_setSlaveAddress(txAddress);
|
||||
uint8_t ret = bcm2835_i2c_write(reinterpret_cast<const char *>(txBuffer), txBufferLength);
|
||||
|
||||
// reset tx buffer iterator vars
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
// indicate that we are done transmitting
|
||||
transmitting = 0;
|
||||
|
||||
pthread_mutex_unlock(&i2cMutex);
|
||||
|
||||
if (ret == BCM2835_I2C_REASON_OK) {
|
||||
return 0; // success
|
||||
} else if (ret == BCM2835_I2C_REASON_ERROR_NACK) {
|
||||
return 3; // error: data send, nack received
|
||||
}
|
||||
return 4; // other error
|
||||
}
|
||||
|
||||
size_t TwoWire::requestFrom(uint8_t address, size_t quantity)
|
||||
{
|
||||
// clamp to buffer length
|
||||
if (quantity > BUFFER_LENGTH) {
|
||||
quantity = BUFFER_LENGTH;
|
||||
}
|
||||
|
||||
rxBufferIndex = 0;
|
||||
rxBufferLength = 0;
|
||||
|
||||
bcm2835_i2c_setSlaveAddress(address);
|
||||
uint8_t ret = bcm2835_i2c_read(reinterpret_cast<char *>(rxBuffer), quantity);
|
||||
if (ret == BCM2835_I2C_REASON_OK) {
|
||||
rxBufferLength = quantity;
|
||||
}
|
||||
|
||||
return rxBufferLength;
|
||||
}
|
||||
|
||||
uint8_t TwoWire::requestFrom(uint8_t address, uint8_t quantity)
|
||||
{
|
||||
return requestFrom(address, static_cast<size_t>(quantity));
|
||||
}
|
||||
|
||||
uint8_t TwoWire::requestFrom(int address, int quantity)
|
||||
{
|
||||
return requestFrom(static_cast<uint8_t>(address), static_cast<size_t>(quantity));
|
||||
}
|
||||
|
||||
size_t TwoWire::write(uint8_t data)
|
||||
{
|
||||
if (transmitting) {
|
||||
// in master transmitter mode
|
||||
// don't bother if buffer is full
|
||||
if (txBufferLength >= BUFFER_LENGTH) {
|
||||
setWriteError();
|
||||
return 0;
|
||||
}
|
||||
// put byte in tx buffer
|
||||
txBuffer[txBufferIndex] = data;
|
||||
++txBufferIndex;
|
||||
// update amount in buffer
|
||||
txBufferLength = txBufferIndex;
|
||||
|
||||
return 1;
|
||||
} else {
|
||||
return write(&data, 1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t TwoWire::write(const uint8_t *data, size_t quantity)
|
||||
{
|
||||
if (transmitting) {
|
||||
// in master transmitter mode
|
||||
for (size_t i = 0; i < quantity; ++i) {
|
||||
write(data[i]);
|
||||
}
|
||||
} else {
|
||||
uint8_t rc = bcm2835_i2c_write(reinterpret_cast<const char *>(data), quantity);
|
||||
if (rc != BCM2835_I2C_REASON_OK) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return quantity;
|
||||
}
|
||||
|
||||
int TwoWire::available()
|
||||
{
|
||||
return rxBufferLength - rxBufferIndex;
|
||||
}
|
||||
|
||||
int TwoWire::read()
|
||||
{
|
||||
int value = -1;
|
||||
|
||||
if (rxBufferIndex < rxBufferLength) {
|
||||
value = rxBuffer[rxBufferIndex];
|
||||
++rxBufferIndex;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
int TwoWire::peek()
|
||||
{
|
||||
if (rxBufferIndex < rxBufferLength) {
|
||||
return rxBuffer[rxBufferIndex];
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void TwoWire::flush()
|
||||
{
|
||||
rxBufferIndex = 0;
|
||||
rxBufferLength = 0;
|
||||
txBufferIndex = 0;
|
||||
txBufferLength = 0;
|
||||
}
|
||||
|
||||
TwoWire Wire = TwoWire();
|
||||
94
lib/MySensors/hal/architecture/Linux/drivers/BCM/Wire.h
Normal file
94
lib/MySensors/hal/architecture/Linux/drivers/BCM/Wire.h
Normal file
@@ -0,0 +1,94 @@
|
||||
/*
|
||||
TwoWire.h - TWI/I2C library for Arduino & Wiring
|
||||
Copyright (c) 2006 Nicholas Zambetti. 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
|
||||
|
||||
Modified 2012 by Todd Krein (todd@krein.org) to implement repeated starts
|
||||
Modified December 2014 by Ivan Grokhotkov (ivan@esp8266.com) - esp8266 support
|
||||
Modified April 2015 by Hrsto Gochkov (ficeto@ficeto.com) - alternative esp8266 support
|
||||
Modified October 2016 by Marcelo Aquino <marceloaqno@gmail.org> for Raspberry Pi
|
||||
*/
|
||||
|
||||
#ifndef Wire_h
|
||||
#define Wire_h
|
||||
|
||||
#if !DOXYGEN
|
||||
#include <stdint.h>
|
||||
#include "Stream.h"
|
||||
#include "BCM.h"
|
||||
|
||||
#define BUFFER_LENGTH 32
|
||||
|
||||
class TwoWire : public Stream
|
||||
{
|
||||
|
||||
private:
|
||||
static uint8_t rxBuffer[];
|
||||
static uint8_t rxBufferIndex;
|
||||
static uint8_t rxBufferLength;
|
||||
|
||||
static uint8_t txAddress;
|
||||
static uint8_t txBuffer[];
|
||||
static uint8_t txBufferIndex;
|
||||
static uint8_t txBufferLength;
|
||||
|
||||
static uint8_t transmitting;
|
||||
|
||||
public:
|
||||
void begin();
|
||||
void begin(uint8_t address);
|
||||
void begin(int address);
|
||||
void end();
|
||||
void setClock(uint32_t clock);
|
||||
|
||||
void beginTransmission(uint8_t address);
|
||||
void beginTransmission(int address);
|
||||
uint8_t endTransmission(void);
|
||||
|
||||
size_t requestFrom(uint8_t address, size_t size);
|
||||
uint8_t requestFrom(uint8_t address, uint8_t quantity);
|
||||
uint8_t requestFrom(int address, int quantity);
|
||||
|
||||
size_t write(uint8_t data);
|
||||
size_t write(const uint8_t *data, size_t quantity);
|
||||
int available();
|
||||
int read();
|
||||
int peek();
|
||||
void flush();
|
||||
|
||||
inline size_t write(unsigned long n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
inline size_t write(long n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
inline size_t write(unsigned int n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
inline size_t write(int n)
|
||||
{
|
||||
return write((uint8_t)n);
|
||||
}
|
||||
using Print::write;
|
||||
};
|
||||
|
||||
extern TwoWire Wire;
|
||||
|
||||
#endif
|
||||
#endif
|
||||
1948
lib/MySensors/hal/architecture/Linux/drivers/BCM/bcm2835.c
Normal file
1948
lib/MySensors/hal/architecture/Linux/drivers/BCM/bcm2835.c
Normal file
File diff suppressed because it is too large
Load Diff
1951
lib/MySensors/hal/architecture/Linux/drivers/BCM/bcm2835.h
Normal file
1951
lib/MySensors/hal/architecture/Linux/drivers/BCM/bcm2835.h
Normal file
File diff suppressed because it is too large
Load Diff
115
lib/MySensors/hal/architecture/Linux/drivers/core/Arduino.h
Normal file
115
lib/MySensors/hal/architecture/Linux/drivers/core/Arduino.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
#ifdef LINUX_ARCH_RASPBERRYPI
|
||||
#include "RPi.h"
|
||||
#define pinMode(pin, direction) RPi.pinMode(pin, direction)
|
||||
#define digitalWrite(pin, value) RPi.digitalWrite(pin, value)
|
||||
#define digitalRead(pin) RPi.digitalRead(pin)
|
||||
#define digitalPinToInterrupt(pin) RPi.digitalPinToInterrupt(pin)
|
||||
#else
|
||||
#include "GPIO.h"
|
||||
#define pinMode(pin, direction) GPIO.pinMode(pin, direction)
|
||||
#define digitalWrite(pin, value) GPIO.digitalWrite(pin, value)
|
||||
#define digitalRead(pin) GPIO.digitalRead(pin)
|
||||
#define digitalPinToInterrupt(pin) GPIO.digitalPinToInterrupt(pin)
|
||||
#endif
|
||||
|
||||
#include "interrupt.h"
|
||||
|
||||
#undef PSTR
|
||||
#define PSTR(x) (x)
|
||||
#undef F
|
||||
#define F(x) (x)
|
||||
#define PROGMEM __attribute__(( section(".progmem.data") ))
|
||||
#define vsnprintf_P(...) vsnprintf( __VA_ARGS__ )
|
||||
#define snprintf_P(...) snprintf( __VA_ARGS__ )
|
||||
#define memcpy_P memcpy
|
||||
#define pgm_read_byte(p) (*(p))
|
||||
#define pgm_read_dword(p) (*(p))
|
||||
#define pgm_read_byte_near(p) (*(p))
|
||||
|
||||
#define PI 3.1415926535897932384626433832795
|
||||
#define HALF_PI 1.5707963267948966192313216916398
|
||||
#define TWO_PI 6.283185307179586476925286766559
|
||||
#define DEG_TO_RAD 0.017453292519943295769236907684886
|
||||
#define RAD_TO_DEG 57.295779513082320876798154814105
|
||||
#define EULER 2.718281828459045235360287471352
|
||||
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bitRead(value, bit) (((value) >> (bit)) & 0x01)
|
||||
#define bitSet(value, bit) ((value) |= (1UL << (bit)))
|
||||
#define bitClear(value, bit) ((value) &= ~(1UL << (bit)))
|
||||
#define bitWrite(value, bit, bitvalue) (bitvalue ? bitSet(value, bit) : bitClear(value, bit))
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
#define GET_MACRO(_0, _1, _2, NAME, ...) NAME
|
||||
#define random(...) GET_MACRO(_0, ##__VA_ARGS__, randMinMax, randMax, rand)(__VA_ARGS__)
|
||||
|
||||
#ifndef delay
|
||||
#define delay _delay_milliseconds
|
||||
#endif
|
||||
|
||||
#ifndef delayMicroseconds
|
||||
#define delayMicroseconds _delay_microseconds
|
||||
#endif
|
||||
|
||||
using std::string;
|
||||
using std::min;
|
||||
using std::max;
|
||||
using std::abs;
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef string String;
|
||||
typedef char __FlashStringHelper;
|
||||
|
||||
void yield(void);
|
||||
unsigned long millis(void);
|
||||
unsigned long micros(void);
|
||||
void _delay_milliseconds(unsigned int millis);
|
||||
void _delay_microseconds(unsigned int micro);
|
||||
void randomSeed(unsigned long seed);
|
||||
long randMax(long howbig);
|
||||
long randMinMax(long howsmall, long howbig);
|
||||
|
||||
#endif
|
||||
54
lib/MySensors/hal/architecture/Linux/drivers/core/Client.h
Normal file
54
lib/MySensors/hal/architecture/Linux/drivers/core/Client.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
Client.h - Base class that provides Client
|
||||
Copyright (c) 2011 Adrian McEwen. 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
|
||||
|
||||
Modified by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#ifndef client_h
|
||||
#define client_h
|
||||
|
||||
#include "Stream.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
#if !DOXYGEN
|
||||
class Client : public Stream
|
||||
{
|
||||
|
||||
public:
|
||||
virtual int connect(IPAddress ip, uint16_t port) = 0;
|
||||
virtual int connect(const char *host, uint16_t port) = 0;
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
virtual size_t write(const uint8_t *buf, size_t size) = 0;
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int read(uint8_t *buf, size_t size) = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
virtual void stop() = 0;
|
||||
virtual uint8_t connected() = 0;
|
||||
virtual operator bool() = 0;
|
||||
|
||||
protected:
|
||||
uint8_t* rawIPAddress(IPAddress& addr)
|
||||
{
|
||||
return addr.raw_address();
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#include "EthernetClient.h"
|
||||
#include <cstdio>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/sockios.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include <errno.h>
|
||||
#include "log.h"
|
||||
|
||||
EthernetClient::EthernetClient() : _sock(-1)
|
||||
{
|
||||
}
|
||||
|
||||
EthernetClient::EthernetClient(int sock) : _sock(sock)
|
||||
{
|
||||
}
|
||||
|
||||
int EthernetClient::connect(const char* host, uint16_t port)
|
||||
{
|
||||
struct addrinfo hints, *servinfo, *localinfo, *p;
|
||||
int rv;
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
char port_str[6];
|
||||
bool use_bind = (_srcip != 0);
|
||||
|
||||
close();
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
|
||||
sprintf(port_str, "%hu", port);
|
||||
if ((rv = getaddrinfo(host, port_str, &hints, &servinfo)) != 0) {
|
||||
logError("getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
if (use_bind) {
|
||||
if ((rv = getaddrinfo(_srcip.toString().c_str(), port_str, &hints, &localinfo)) != 0) {
|
||||
logError("getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
// loop through all the results and connect to the first we can
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
if ((_sock = socket(p->ai_family, p->ai_socktype,
|
||||
p->ai_protocol)) == -1) {
|
||||
logError("socket: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (use_bind) {
|
||||
if (::bind(_sock, localinfo->ai_addr, localinfo->ai_addrlen) == -1) {
|
||||
close();
|
||||
logError("bind: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (::connect(_sock, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close();
|
||||
logError("connect: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
logError("failed to connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr);
|
||||
inet_ntop(p->ai_family, addr, s, sizeof s);
|
||||
logDebug("connected to %s\n", s);
|
||||
|
||||
freeaddrinfo(servinfo); // all done with this structure
|
||||
if (use_bind) {
|
||||
freeaddrinfo(localinfo); // all done with this structure
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int EthernetClient::connect(IPAddress ip, uint16_t port)
|
||||
{
|
||||
return connect(ip.toString().c_str(), port);
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(uint8_t b)
|
||||
{
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(const uint8_t *buf, size_t size)
|
||||
{
|
||||
int bytes = 0;
|
||||
|
||||
if (_sock == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
int rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
if (rc == -1) {
|
||||
logError("send: %s\n", strerror(errno));
|
||||
close();
|
||||
break;
|
||||
}
|
||||
bytes += rc;
|
||||
size -= rc;
|
||||
}
|
||||
|
||||
return bytes;
|
||||
}
|
||||
|
||||
size_t EthernetClient::write(const char *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
size_t EthernetClient::write(const char *buffer, size_t size)
|
||||
{
|
||||
return write((const uint8_t *)buffer, size);
|
||||
}
|
||||
|
||||
int EthernetClient::available()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (_sock != -1) {
|
||||
ioctl(_sock, SIOCINQ, &count);
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int EthernetClient::read()
|
||||
{
|
||||
uint8_t b;
|
||||
if ( recv(_sock, &b, 1, MSG_DONTWAIT) > 0 ) {
|
||||
// recv worked
|
||||
return b;
|
||||
} else {
|
||||
// No data available
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int EthernetClient::read(uint8_t *buf, size_t bytes)
|
||||
{
|
||||
return recv(_sock, buf, bytes, MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
int EthernetClient::peek()
|
||||
{
|
||||
uint8_t b;
|
||||
|
||||
if (recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT) > 0) {
|
||||
return b;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void EthernetClient::flush()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
if (_sock != -1) {
|
||||
while (true) {
|
||||
ioctl(_sock, SIOCOUTQ, &count);
|
||||
if (count == 0) {
|
||||
return;
|
||||
}
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void EthernetClient::stop()
|
||||
{
|
||||
if (_sock == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// attempt to close the connection gracefully (send a FIN to other side)
|
||||
shutdown(_sock, SHUT_RDWR);
|
||||
|
||||
timeval startTime, curTime;
|
||||
gettimeofday(&startTime, NULL);
|
||||
|
||||
// wait up to a second for the connection to close
|
||||
do {
|
||||
uint8_t s = status();
|
||||
if (s == ETHERNETCLIENT_W5100_CLOSED) {
|
||||
break; // exit the loop
|
||||
}
|
||||
usleep(1000);
|
||||
gettimeofday(&curTime, NULL);
|
||||
} while (((curTime.tv_sec - startTime.tv_sec) * 1000000) + (curTime.tv_usec - startTime.tv_usec) <
|
||||
1000000);
|
||||
|
||||
// free up the socket descriptor
|
||||
::close(_sock);
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::status()
|
||||
{
|
||||
if (_sock == -1) {
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
}
|
||||
|
||||
struct tcp_info tcp_info;
|
||||
int tcp_info_length = sizeof(tcp_info);
|
||||
|
||||
if ( getsockopt( _sock, SOL_TCP, TCP_INFO, (void *)&tcp_info,
|
||||
(socklen_t *)&tcp_info_length ) == 0 ) {
|
||||
switch (tcp_info.tcpi_state) {
|
||||
case TCP_ESTABLISHED:
|
||||
return ETHERNETCLIENT_W5100_ESTABLISHED;
|
||||
case TCP_SYN_SENT:
|
||||
return ETHERNETCLIENT_W5100_SYNSENT;
|
||||
case TCP_SYN_RECV:
|
||||
return ETHERNETCLIENT_W5100_SYNRECV;
|
||||
case TCP_FIN_WAIT1:
|
||||
case TCP_FIN_WAIT2:
|
||||
return ETHERNETCLIENT_W5100_FIN_WAIT;
|
||||
case TCP_TIME_WAIT:
|
||||
return TCP_TIME_WAIT;
|
||||
case TCP_CLOSE:
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
case TCP_CLOSE_WAIT:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
case TCP_LAST_ACK:
|
||||
return ETHERNETCLIENT_W5100_LAST_ACK;
|
||||
case TCP_LISTEN:
|
||||
return ETHERNETCLIENT_W5100_LISTEN;
|
||||
case TCP_CLOSING:
|
||||
return ETHERNETCLIENT_W5100_CLOSING;
|
||||
}
|
||||
}
|
||||
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::connected()
|
||||
{
|
||||
return status() == ETHERNETCLIENT_W5100_ESTABLISHED || available();
|
||||
}
|
||||
|
||||
void EthernetClient::close()
|
||||
{
|
||||
if (_sock != -1) {
|
||||
::close(_sock);
|
||||
_sock = -1;
|
||||
}
|
||||
}
|
||||
|
||||
void EthernetClient::bind(IPAddress ip)
|
||||
{
|
||||
_srcip = ip;
|
||||
}
|
||||
|
||||
int EthernetClient::getSocketNumber()
|
||||
{
|
||||
return _sock;
|
||||
}
|
||||
|
||||
// the next function allows us to use the client returned by
|
||||
// EthernetServer::available() as the condition in an if-statement.
|
||||
|
||||
EthernetClient::operator bool()
|
||||
{
|
||||
return _sock != -1;
|
||||
}
|
||||
|
||||
bool EthernetClient::operator==(const EthernetClient& rhs)
|
||||
{
|
||||
return _sock == rhs._sock && _sock != -1 && rhs._sock != -1;
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#ifndef EthernetClient_h
|
||||
#define EthernetClient_h
|
||||
|
||||
#include "Client.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
// State codes from W5100 library
|
||||
#define ETHERNETCLIENT_W5100_CLOSED 0x00
|
||||
#define ETHERNETCLIENT_W5100_LISTEN 0x14
|
||||
#define ETHERNETCLIENT_W5100_SYNSENT 0x15
|
||||
#define ETHERNETCLIENT_W5100_SYNRECV 0x16
|
||||
#define ETHERNETCLIENT_W5100_ESTABLISHED 0x17
|
||||
#define ETHERNETCLIENT_W5100_FIN_WAIT 0x18
|
||||
#define ETHERNETCLIENT_W5100_CLOSING 0x1A
|
||||
#define ETHERNETCLIENT_W5100_TIME_WAIT 0x1B
|
||||
#define ETHERNETCLIENT_W5100_CLOSE_WAIT 0x1C
|
||||
#define ETHERNETCLIENT_W5100_LAST_ACK 0x1D
|
||||
|
||||
/**
|
||||
* EthernetClient class
|
||||
*/
|
||||
class EthernetClient : public Client
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief EthernetClient constructor.
|
||||
*/
|
||||
EthernetClient();
|
||||
/**
|
||||
* @brief EthernetClient constructor.
|
||||
*
|
||||
* @param sock Network socket.
|
||||
*/
|
||||
explicit EthernetClient(int sock);
|
||||
/**
|
||||
* @brief Initiate a connection with host:port.
|
||||
*
|
||||
* @param host name to resolve or a stringified dotted IP address.
|
||||
* @param port to connect to.
|
||||
* @return 1 if SUCCESS or -1 if FAILURE.
|
||||
*/
|
||||
virtual int connect(const char *host, uint16_t port);
|
||||
/**
|
||||
* @brief Initiate a connection with ip:port.
|
||||
*
|
||||
* @param ip to connect to.
|
||||
* @param port to connect to.
|
||||
* @return 1 if SUCCESS or -1 if FAILURE.
|
||||
*/
|
||||
virtual int connect(IPAddress ip, uint16_t port);
|
||||
/**
|
||||
* @brief Write a byte.
|
||||
*
|
||||
* @param b byte to write.
|
||||
* @return 0 if FAILURE or 1 if SUCCESS.
|
||||
*/
|
||||
virtual size_t write(uint8_t b);
|
||||
/**
|
||||
* @brief Write at most 'size' bytes.
|
||||
*
|
||||
* @param buf Buffer to read from.
|
||||
* @param size of the buffer.
|
||||
* @return 0 if FAILURE or the number of bytes sent.
|
||||
*/
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
/**
|
||||
* @brief Write a null-terminated string.
|
||||
*
|
||||
* @param str String to write.
|
||||
* @return 0 if FAILURE or number of characters sent.
|
||||
*/
|
||||
size_t write(const char *str);
|
||||
/**
|
||||
* @brief Write at most 'size' characters.
|
||||
*
|
||||
* @param buffer to read from.
|
||||
* @param size of the buffer.
|
||||
* @return 0 if FAILURE or the number of characters sent.
|
||||
*/
|
||||
size_t write(const char *buffer, size_t size);
|
||||
/**
|
||||
* @brief Returns the number of bytes available for reading.
|
||||
*
|
||||
* @return number of bytes available.
|
||||
*/
|
||||
virtual int available();
|
||||
/**
|
||||
* @brief Read a byte.
|
||||
*
|
||||
* @return -1 if no data, else the first byte available.
|
||||
*/
|
||||
virtual int read();
|
||||
/**
|
||||
* @brief Read a number of bytes and store in a buffer.
|
||||
*
|
||||
* @param buf buffer to write to.
|
||||
* @param bytes number of bytes to read.
|
||||
* @return -1 if no data or number of read bytes.
|
||||
*/
|
||||
virtual int read(uint8_t *buf, size_t bytes);
|
||||
/**
|
||||
* @brief Returns the next byte of the read queue without removing it from the queue.
|
||||
*
|
||||
* @return -1 if no data, else the first byte of incoming data available.
|
||||
*/
|
||||
virtual int peek();
|
||||
/**
|
||||
* @brief Waits until all outgoing bytes in buffer have been sent.
|
||||
*/
|
||||
virtual void flush();
|
||||
/**
|
||||
* @brief Close the connection gracefully.
|
||||
*
|
||||
* Send a FIN and wait 1s for a response. If no response close it forcefully.
|
||||
*/
|
||||
virtual void stop();
|
||||
/**
|
||||
* @brief Connection status.
|
||||
*
|
||||
* @return state according to W5100 library codes.
|
||||
*/
|
||||
uint8_t status();
|
||||
/**
|
||||
* @brief Whether or not the client is connected.
|
||||
*
|
||||
* Note that a client is considered connected if the connection has been closed but
|
||||
* there is still unread data.
|
||||
*
|
||||
* @return 1 if the client is connected, 0 if not.
|
||||
*/
|
||||
virtual uint8_t connected();
|
||||
/**
|
||||
* @brief Close the connection.
|
||||
*/
|
||||
void close();
|
||||
/**
|
||||
* @brief Bind the conection to the specified local ip.
|
||||
*/
|
||||
void bind(IPAddress ip);
|
||||
/**
|
||||
* @brief Get the internal socket file descriptor.
|
||||
*
|
||||
* @return an integer, that is the socket number.
|
||||
*/
|
||||
int getSocketNumber();
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
* Allow EthernetClient objects to be used where a bool is expected.
|
||||
*/
|
||||
virtual operator bool();
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator==(const bool value)
|
||||
{
|
||||
return bool() == value;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator!=(const bool value)
|
||||
{
|
||||
return bool() != value;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator==(const EthernetClient& rhs);
|
||||
/**
|
||||
* @brief Overloaded cast operators.
|
||||
*
|
||||
*/
|
||||
virtual bool operator!=(const EthernetClient& rhs)
|
||||
{
|
||||
return !this->operator==(rhs);
|
||||
};
|
||||
|
||||
friend class EthernetServer;
|
||||
|
||||
private:
|
||||
int _sock; //!< @brief Network socket file descriptor.
|
||||
IPAddress _srcip; //!< @brief Local ip to bind to.
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#include "EthernetServer.h"
|
||||
#include <cstdio>
|
||||
#include <sys/socket.h>
|
||||
#include <cstring>
|
||||
#include <sys/socket.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include "log.h"
|
||||
#include "EthernetClient.h"
|
||||
|
||||
EthernetServer::EthernetServer(uint16_t port, uint16_t max_clients) : port(port),
|
||||
max_clients(max_clients), sockfd(-1)
|
||||
{
|
||||
clients.reserve(max_clients);
|
||||
}
|
||||
|
||||
void EthernetServer::begin()
|
||||
{
|
||||
begin(IPAddress(0,0,0,0));
|
||||
}
|
||||
|
||||
void EthernetServer::begin(IPAddress address)
|
||||
{
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
int yes=1;
|
||||
int rv;
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
char portstr[6];
|
||||
|
||||
if (sockfd != -1) {
|
||||
close(sockfd);
|
||||
sockfd = -1;
|
||||
}
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
sprintf(portstr, "%d", port);
|
||||
if ((rv = getaddrinfo(address.toString().c_str(), portstr, &hints, &servinfo)) != 0) {
|
||||
logError("getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return;
|
||||
}
|
||||
|
||||
// loop through all the results and bind to the first we can
|
||||
for (p = servinfo; p != NULL; p = p->ai_next) {
|
||||
if ((sockfd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1) {
|
||||
logError("socket: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
|
||||
logError("setsockopt: %s\n", strerror(errno));
|
||||
freeaddrinfo(servinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close(sockfd);
|
||||
logError("bind: %s\n", strerror(errno));
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
logError("Failed to bind!\n");
|
||||
freeaddrinfo(servinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) {
|
||||
logError("listen: %s\n", strerror(errno));
|
||||
freeaddrinfo(servinfo);
|
||||
return;
|
||||
}
|
||||
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
fcntl(sockfd, F_SETFL, O_NONBLOCK);
|
||||
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
void *addr = &(ipv4->sin_addr);
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
logDebug("Listening for connections on %s:%s\n", ipstr, portstr);
|
||||
}
|
||||
|
||||
bool EthernetServer::hasClient()
|
||||
{
|
||||
// Check if any client has disconnected
|
||||
for (size_t i = 0; i < clients.size(); ++i) {
|
||||
EthernetClient client(clients[i]);
|
||||
if (!client.connected()) {
|
||||
// Checks if this disconnected client is also on the new clients list
|
||||
for (std::list<int>::iterator it = new_clients.begin(); it != new_clients.end(); ++it) {
|
||||
if (*it == clients[i]) {
|
||||
new_clients.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
client.stop();
|
||||
clients[i] = clients.back();
|
||||
clients.pop_back();
|
||||
logDebug("Ethernet client disconnected.\n");
|
||||
}
|
||||
}
|
||||
|
||||
_accept();
|
||||
|
||||
return !new_clients.empty();
|
||||
}
|
||||
|
||||
EthernetClient EthernetServer::available()
|
||||
{
|
||||
if (new_clients.empty()) {
|
||||
return EthernetClient();
|
||||
} else {
|
||||
int sock = new_clients.front();
|
||||
new_clients.pop_front();
|
||||
return EthernetClient(sock);
|
||||
}
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(uint8_t b)
|
||||
{
|
||||
return write(&b, 1);
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (size_t i = 0; i < clients.size(); ++i) {
|
||||
EthernetClient client(clients[i]);
|
||||
if (client.status() == ETHERNETCLIENT_W5100_ESTABLISHED) {
|
||||
n += client.write(buffer, size);
|
||||
}
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(const char *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return write((const uint8_t *)str, strlen(str));
|
||||
}
|
||||
|
||||
size_t EthernetServer::write(const char *buffer, size_t size)
|
||||
{
|
||||
return write((const uint8_t *)buffer, size);
|
||||
}
|
||||
|
||||
void EthernetServer::_accept()
|
||||
{
|
||||
int new_fd;
|
||||
socklen_t sin_size;
|
||||
struct sockaddr_storage client_addr;
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
|
||||
sin_size = sizeof client_addr;
|
||||
new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
|
||||
if (new_fd == -1) {
|
||||
if (errno != EAGAIN && errno != EWOULDBLOCK) {
|
||||
logError("accept: %s\n", strerror(errno));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (clients.size() == max_clients) {
|
||||
// no free slots, search for a dead client
|
||||
close(new_fd);
|
||||
logDebug("Max number of ethernet clients reached.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
new_clients.push_back(new_fd);
|
||||
clients.push_back(new_fd);
|
||||
|
||||
void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr);
|
||||
inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr);
|
||||
logDebug("New connection from %s\n", ipstr);
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on Arduino ethernet library, Copyright (c) 2010 Arduino LLC. All right reserved.
|
||||
*/
|
||||
|
||||
#ifndef EthernetServer_h
|
||||
#define EthernetServer_h
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include "Server.h"
|
||||
#include "IPAddress.h"
|
||||
|
||||
#ifdef ETHERNETSERVER_MAX_CLIENTS
|
||||
#define ETHERNETSERVER_BACKLOG ETHERNETSERVER_MAX_CLIENTS //!< Maximum length to which the queue of pending connections may grow.
|
||||
#else
|
||||
#define ETHERNETSERVER_MAX_CLIENTS 10 //!< Default value for max_clients.
|
||||
#define ETHERNETSERVER_BACKLOG 10 //!< Maximum length to which the queue of pending connections may grow.
|
||||
#endif
|
||||
|
||||
class EthernetClient;
|
||||
|
||||
/**
|
||||
* @brief EthernetServer class
|
||||
*/
|
||||
class EthernetServer : public Server
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief EthernetServer constructor.
|
||||
*
|
||||
* @param port number for the socket addresses.
|
||||
* @param max_clients The maximum number allowed for connected clients.
|
||||
*/
|
||||
EthernetServer(uint16_t port, uint16_t max_clients = ETHERNETSERVER_MAX_CLIENTS);
|
||||
/**
|
||||
* @brief Listen for inbound connection request.
|
||||
*
|
||||
*/
|
||||
virtual void begin();
|
||||
/**
|
||||
* @brief Listen on the specified ip for inbound connection request.
|
||||
*
|
||||
* @param addr IP address to bind to.
|
||||
*/
|
||||
void begin(IPAddress addr);
|
||||
/**
|
||||
* @brief Verifies if a new client has connected.
|
||||
*
|
||||
* @return @c true if a new client has connected, else @c false.
|
||||
*/
|
||||
bool hasClient();
|
||||
/**
|
||||
* @brief Get the new connected client.
|
||||
*
|
||||
* @return a EthernetClient object; if no new client has connected, this object will evaluate to false.
|
||||
*/
|
||||
EthernetClient available();
|
||||
/**
|
||||
* @brief Write a byte to all clients.
|
||||
*
|
||||
* @param b byte to send.
|
||||
* @return 0 if FAILURE or 1 if SUCCESS.
|
||||
*/
|
||||
virtual size_t write(uint8_t b);
|
||||
/**
|
||||
* @brief Write at most 'size' bytes to all clients.
|
||||
*
|
||||
* @param buffer to read from.
|
||||
* @param size of the buffer.
|
||||
* @return 0 if FAILURE else number of bytes sent.
|
||||
*/
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
/**
|
||||
* @brief Write a null-terminated string to all clients.
|
||||
*
|
||||
* @param str String to write.
|
||||
* @return 0 if FAILURE else number of characters sent.
|
||||
*/
|
||||
size_t write(const char *str);
|
||||
/**
|
||||
* @brief Write at most 'size' characters to all clients.
|
||||
*
|
||||
* @param buffer to read from.
|
||||
* @param size of the buffer.
|
||||
* @return 0 if FAILURE else the number of characters sent.
|
||||
*/
|
||||
size_t write(const char *buffer, size_t size);
|
||||
|
||||
private:
|
||||
uint16_t port; //!< @brief Port number for the network socket.
|
||||
std::list<int> new_clients; //!< Socket list of new connected clients.
|
||||
std::vector<int> clients; //!< @brief Socket list of connected clients.
|
||||
uint16_t max_clients; //!< @brief The maximum number of allowed clients.
|
||||
int sockfd; //!< @brief Network socket used to accept connections.
|
||||
|
||||
/**
|
||||
* @brief Accept new clients if the total of connected clients is below max_clients.
|
||||
*
|
||||
*/
|
||||
void _accept();
|
||||
};
|
||||
|
||||
#endif
|
||||
211
lib/MySensors/hal/architecture/Linux/drivers/core/GPIO.cpp
Normal file
211
lib/MySensors/hal/architecture/Linux/drivers/core/GPIO.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "GPIO.h"
|
||||
#include <dirent.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "log.h"
|
||||
|
||||
// Declare a single default instance
|
||||
GPIOClass GPIO = GPIOClass();
|
||||
|
||||
GPIOClass::GPIOClass()
|
||||
{
|
||||
FILE *f;
|
||||
DIR* dp;
|
||||
char file[64];
|
||||
|
||||
dp = opendir("/sys/class/gpio");
|
||||
if (dp == NULL) {
|
||||
logError("Could not open /sys/class/gpio directory");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
lastPinNum = 0;
|
||||
|
||||
while (true) {
|
||||
dirent *de = readdir(dp);
|
||||
if (de == NULL) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (strncmp("gpiochip", de->d_name, 8) == 0) {
|
||||
snprintf(file, sizeof(file), "/sys/class/gpio/%s/base", de->d_name);
|
||||
f = fopen(file, "r");
|
||||
int base;
|
||||
if (fscanf(f, "%d", &base) == EOF) {
|
||||
logError("Failed to open %s\n", file);
|
||||
base = 0;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
snprintf(file, sizeof(file), "/sys/class/gpio/%s/ngpio", de->d_name);
|
||||
f = fopen(file, "r");
|
||||
int ngpio;
|
||||
if (fscanf(f, "%d", &ngpio) == EOF) {
|
||||
logError("Failed to open %s\n", file);
|
||||
ngpio = 0;
|
||||
}
|
||||
fclose(f);
|
||||
|
||||
int max = ngpio + base - 1;
|
||||
if (lastPinNum < max) {
|
||||
lastPinNum = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
closedir(dp);
|
||||
|
||||
exportedPins = new uint8_t[lastPinNum + 1];
|
||||
|
||||
for (int i = 0; i < lastPinNum + 1; ++i) {
|
||||
exportedPins[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GPIOClass::GPIOClass(const GPIOClass& other)
|
||||
{
|
||||
lastPinNum = other.lastPinNum;
|
||||
|
||||
exportedPins = new uint8_t[lastPinNum + 1];
|
||||
for (int i = 0; i < lastPinNum + 1; ++i) {
|
||||
exportedPins[i] = other.exportedPins[i];
|
||||
}
|
||||
}
|
||||
|
||||
GPIOClass::~GPIOClass()
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
for (int i = 0; i < lastPinNum + 1; ++i) {
|
||||
if (exportedPins[i]) {
|
||||
f = fopen("/sys/class/gpio/unexport", "w");
|
||||
fprintf(f, "%d\n", i);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
delete [] exportedPins;
|
||||
}
|
||||
|
||||
void GPIOClass::pinMode(uint8_t pin, uint8_t mode)
|
||||
{
|
||||
FILE *f;
|
||||
|
||||
if (pin > lastPinNum) {
|
||||
return;
|
||||
}
|
||||
|
||||
f = fopen("/sys/class/gpio/export", "w");
|
||||
fprintf(f, "%d\n", pin);
|
||||
fclose(f);
|
||||
|
||||
int counter = 0;
|
||||
char file[128];
|
||||
sprintf(file, "/sys/class/gpio/gpio%d/direction", pin);
|
||||
|
||||
while ((f = fopen(file,"w")) == NULL) {
|
||||
// Wait 10 seconds for the file to be accessible if not open on first attempt
|
||||
sleep(1);
|
||||
counter++;
|
||||
if (counter > 10) {
|
||||
logError("Could not open /sys/class/gpio/gpio%u/direction", pin);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (mode == INPUT) {
|
||||
fprintf(f, "in\n");
|
||||
} else {
|
||||
fprintf(f, "out\n");
|
||||
}
|
||||
|
||||
exportedPins[pin] = 1;
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
void GPIOClass::digitalWrite(uint8_t pin, uint8_t value)
|
||||
{
|
||||
FILE *f;
|
||||
char file[128];
|
||||
|
||||
if (pin > lastPinNum) {
|
||||
return;
|
||||
}
|
||||
if (0 == exportedPins[pin]) {
|
||||
pinMode(pin, OUTPUT);
|
||||
}
|
||||
|
||||
sprintf(file, "/sys/class/gpio/gpio%d/value", pin);
|
||||
f = fopen(file, "w");
|
||||
|
||||
if (value == 0) {
|
||||
fprintf(f, "0\n");
|
||||
} else {
|
||||
fprintf(f, "1\n");
|
||||
}
|
||||
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
uint8_t GPIOClass::digitalRead(uint8_t pin)
|
||||
{
|
||||
FILE *f;
|
||||
char file[128];
|
||||
|
||||
if (pin > lastPinNum) {
|
||||
return 0;
|
||||
}
|
||||
if (0 == exportedPins[pin]) {
|
||||
pinMode(pin, INPUT);
|
||||
}
|
||||
|
||||
sprintf(file, "/sys/class/gpio/gpio%d/value", pin);
|
||||
f = fopen(file, "r");
|
||||
|
||||
int i;
|
||||
if (fscanf(f, "%d", &i) == EOF) {
|
||||
logError("digitalRead: failed to read pin %u\n", pin);
|
||||
i = 0;
|
||||
}
|
||||
fclose(f);
|
||||
return i;
|
||||
}
|
||||
|
||||
uint8_t GPIOClass::digitalPinToInterrupt(uint8_t pin)
|
||||
{
|
||||
return pin;
|
||||
}
|
||||
|
||||
GPIOClass& GPIOClass::operator=(const GPIOClass& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
lastPinNum = other.lastPinNum;
|
||||
|
||||
exportedPins = new uint8_t[lastPinNum + 1];
|
||||
for (int i = 0; i < lastPinNum + 1; ++i) {
|
||||
exportedPins[i] = other.exportedPins[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
91
lib/MySensors/hal/architecture/Linux/drivers/core/GPIO.h
Normal file
91
lib/MySensors/hal/architecture/Linux/drivers/core/GPIO.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef GPIO_h
|
||||
#define GPIO_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define INPUT 0
|
||||
#define OUTPUT 1
|
||||
|
||||
#define LOW 0
|
||||
#define HIGH 1
|
||||
|
||||
/**
|
||||
* @brief GPIO class
|
||||
*/
|
||||
class GPIOClass
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief GPIOClass constructor.
|
||||
*/
|
||||
GPIOClass();
|
||||
/**
|
||||
* @brief GPIOClass copy constructor.
|
||||
*/
|
||||
GPIOClass(const GPIOClass& other);
|
||||
/**
|
||||
* @brief GPIOClass destructor.
|
||||
*/
|
||||
~GPIOClass();
|
||||
/**
|
||||
* @brief Configures the specified pin to behave either as an input or an output.
|
||||
*
|
||||
* @param pin The number of the pin.
|
||||
* @param mode INPUT or OUTPUT.
|
||||
*/
|
||||
void pinMode(uint8_t pin, uint8_t mode);
|
||||
/**
|
||||
* @brief Write a high or a low value for the given pin.
|
||||
*
|
||||
* @param pin number.
|
||||
* @param value HIGH or LOW.
|
||||
*/
|
||||
void digitalWrite(uint8_t pin, uint8_t value);
|
||||
/**
|
||||
* @brief Reads the value from a specified pin.
|
||||
*
|
||||
* @param pin The number of the pin.
|
||||
* @return HIGH or LOW.
|
||||
*/
|
||||
uint8_t digitalRead(uint8_t pin);
|
||||
/**
|
||||
* @brief Arduino compatibility function, returns the same given pin.
|
||||
*
|
||||
* @param pin The number of the pin.
|
||||
* @return The same parameter pin number.
|
||||
*/
|
||||
uint8_t digitalPinToInterrupt(uint8_t pin);
|
||||
/**
|
||||
* @brief Overloaded assign operator.
|
||||
*
|
||||
*/
|
||||
GPIOClass& operator=(const GPIOClass& other);
|
||||
|
||||
private:
|
||||
int lastPinNum; //!< @brief Highest pin number supported.
|
||||
uint8_t *exportedPins; //!< @brief Array with information of which pins were exported.
|
||||
};
|
||||
|
||||
extern GPIOClass GPIO;
|
||||
|
||||
#endif
|
||||
110
lib/MySensors/hal/architecture/Linux/drivers/core/IPAddress.cpp
Normal file
110
lib/MySensors/hal/architecture/Linux/drivers/core/IPAddress.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* IPAddress.cpp - Base class that provides IPAddress
|
||||
* Copyright (c) 2011 Adrian McEwen. 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
|
||||
*
|
||||
*
|
||||
* Modified by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "IPAddress.h"
|
||||
|
||||
IPAddress::IPAddress()
|
||||
{
|
||||
_address.dword = 0;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet,
|
||||
uint8_t fourth_octet)
|
||||
{
|
||||
_address.bytes[0] = first_octet;
|
||||
_address.bytes[1] = second_octet;
|
||||
_address.bytes[2] = third_octet;
|
||||
_address.bytes[3] = fourth_octet;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(uint32_t address)
|
||||
{
|
||||
_address.dword = address;
|
||||
}
|
||||
|
||||
IPAddress::IPAddress(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
}
|
||||
|
||||
bool IPAddress::fromString(const char *address)
|
||||
{
|
||||
// TODO: add support for "a", "a.b", "a.b.c" formats
|
||||
|
||||
uint16_t acc = 0; // Accumulator
|
||||
uint8_t dots = 0;
|
||||
|
||||
while (*address) {
|
||||
char c = *address++;
|
||||
if (c >= '0' && c <= '9') {
|
||||
acc = acc * 10 + (c - '0');
|
||||
if (acc > 255) {
|
||||
// Value out of [0..255] range
|
||||
return false;
|
||||
}
|
||||
} else if (c == '.') {
|
||||
if (dots == 3) {
|
||||
// Too much dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
_address.bytes[dots++] = acc;
|
||||
acc = 0;
|
||||
} else {
|
||||
// Invalid char
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (dots != 3) {
|
||||
// Too few dots (there must be 3 dots)
|
||||
return false;
|
||||
}
|
||||
_address.bytes[3] = acc;
|
||||
return true;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(const uint8_t *address)
|
||||
{
|
||||
memcpy(_address.bytes, address, sizeof(_address.bytes));
|
||||
return *this;
|
||||
}
|
||||
|
||||
IPAddress& IPAddress::operator=(uint32_t address)
|
||||
{
|
||||
_address.dword = address;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool IPAddress::operator==(const uint8_t* addr) const
|
||||
{
|
||||
return memcmp(addr, _address.bytes, sizeof(_address.bytes)) == 0;
|
||||
}
|
||||
|
||||
std::string IPAddress::toString()
|
||||
{
|
||||
char szRet[16];
|
||||
sprintf(szRet,"%u.%u.%u.%u", _address.bytes[0], _address.bytes[1], _address.bytes[2],
|
||||
_address.bytes[3]);
|
||||
return std::string(szRet);
|
||||
}
|
||||
165
lib/MySensors/hal/architecture/Linux/drivers/core/IPAddress.h
Normal file
165
lib/MySensors/hal/architecture/Linux/drivers/core/IPAddress.h
Normal file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* IPAddress.h - Base class that provides IPAddress
|
||||
* Copyright (c) 2011 Adrian McEwen. 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
|
||||
*
|
||||
*
|
||||
* Modified by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#ifndef IPAddress_h
|
||||
#define IPAddress_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* @brief A class to make it easier to handle and pass around IP addresses
|
||||
*/
|
||||
class IPAddress
|
||||
{
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[4]; //!< IPv4 address as an array
|
||||
uint32_t dword; //!< IPv4 address in 32 bits format
|
||||
} _address;
|
||||
|
||||
/**
|
||||
* @brief Access the raw byte array containing the address.
|
||||
*
|
||||
* Because this returns a pointer to the internal structure rather than a copy of the address
|
||||
* this function should only be used when you know that the usage of the returned uint8_t* will
|
||||
* be transient and not stored.
|
||||
*
|
||||
* @return pointer to the internal structure.
|
||||
*/
|
||||
uint8_t* raw_address()
|
||||
{
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*/
|
||||
IPAddress();
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param first_octet first octet of the IPv4 address.
|
||||
* @param second_octet second octet of the IPv4 address.
|
||||
* @param third_octet third octet of the IPv4 address.
|
||||
* @param fourth_octet fourth octet of the IPv4 address.
|
||||
*/
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param address to be set from a 32 bits integer.
|
||||
*/
|
||||
explicit IPAddress(uint32_t address);
|
||||
/**
|
||||
* @brief IPAddress constructor.
|
||||
*
|
||||
* @param address to be set from a byte array.
|
||||
*/
|
||||
explicit IPAddress(const uint8_t *address);
|
||||
/**
|
||||
* @brief Set the IP from a array of characters.
|
||||
*
|
||||
* @param address to be set.
|
||||
*/
|
||||
bool fromString(const char *address);
|
||||
/**
|
||||
* @brief Set the IP from a string class type.
|
||||
*
|
||||
* @param address to be set.
|
||||
*/
|
||||
bool fromString(const std::string &address)
|
||||
{
|
||||
return fromString(address.c_str());
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
* Allow IPAddress objects to be used where a pointer to a four-byte uint8_t array is expected
|
||||
*/
|
||||
operator uint32_t() const
|
||||
{
|
||||
return _address.dword;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(const IPAddress& addr) const
|
||||
{
|
||||
return _address.dword == addr._address.dword;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(uint32_t addr) const
|
||||
{
|
||||
return _address.dword == addr;
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded cast operator
|
||||
*
|
||||
*/
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
/**
|
||||
* @brief Overloaded index operator.
|
||||
*
|
||||
* Allow getting and setting individual octets of the address.
|
||||
*
|
||||
*/
|
||||
uint8_t operator[](int index) const
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded index operator
|
||||
*
|
||||
*/
|
||||
uint8_t& operator[](int index)
|
||||
{
|
||||
return _address.bytes[index];
|
||||
}
|
||||
/**
|
||||
* @brief Overloaded copy operators.
|
||||
*
|
||||
* Allow initialisation of IPAddress objects from byte array.
|
||||
*/
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
/**
|
||||
* @brief Overloaded copy operator.
|
||||
*
|
||||
* Allow initialisation of IPAddress objects from a 32 bits integer.
|
||||
*/
|
||||
IPAddress& operator=(uint32_t address);
|
||||
/**
|
||||
* @brief Convert the IP address to a string.
|
||||
*
|
||||
* @return A stringified IP address
|
||||
*/
|
||||
std::string toString();
|
||||
|
||||
friend class Client;
|
||||
};
|
||||
|
||||
#endif
|
||||
272
lib/MySensors/hal/architecture/Linux/drivers/core/Print.cpp
Normal file
272
lib/MySensors/hal/architecture/Linux/drivers/core/Print.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/*
|
||||
Print.cpp - Base class that provides print() and println()
|
||||
Copyright (c) 2008 David A. Mellis. 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
|
||||
|
||||
Modified 23 November 2006 by David A. Mellis
|
||||
Modified December 2014 by Ivan Grokhotkov
|
||||
Modified May 2015 by Michael C. Miller - esp8266 progmem support
|
||||
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <cmath>
|
||||
#include "Print.h"
|
||||
|
||||
// Public Methods //////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
size_t n = 0;
|
||||
while(size--) {
|
||||
n += write(*buffer++);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 2, 3)))
|
||||
#endif
|
||||
Print::printf(const char *format, ...)
|
||||
{
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
char temp[64];
|
||||
char* buffer = temp;
|
||||
size_t len = vsnprintf(temp, sizeof(temp), format, arg);
|
||||
va_end(arg);
|
||||
if (len > sizeof(temp) - 1) {
|
||||
buffer = new char[len + 1];
|
||||
if (!buffer) {
|
||||
return 0;
|
||||
}
|
||||
va_start(arg, format);
|
||||
vsnprintf(buffer, len + 1, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
len = write((const uint8_t*) buffer, len);
|
||||
if (buffer != temp) {
|
||||
delete[] buffer;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
size_t Print::print(const std::string &s)
|
||||
{
|
||||
return write(s.c_str(), s.length());
|
||||
}
|
||||
|
||||
size_t Print::print(const char str[])
|
||||
{
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::print(char c)
|
||||
{
|
||||
return write(c);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned char b, int base)
|
||||
{
|
||||
return print((unsigned long) b, base);
|
||||
}
|
||||
|
||||
size_t Print::print(int n, int base)
|
||||
{
|
||||
return print((long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned int n, int base)
|
||||
{
|
||||
return print((unsigned long) n, base);
|
||||
}
|
||||
|
||||
size_t Print::print(long n, int base)
|
||||
{
|
||||
if(base == 0) {
|
||||
return write(n);
|
||||
} else if(base == 10) {
|
||||
if(n < 0) {
|
||||
int t = print('-');
|
||||
n = -n;
|
||||
return printNumber(n, 10) + t;
|
||||
}
|
||||
return printNumber(n, 10);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(unsigned long n, int base)
|
||||
{
|
||||
if(base == 0) {
|
||||
return write(n);
|
||||
} else {
|
||||
return printNumber(n, base);
|
||||
}
|
||||
}
|
||||
|
||||
size_t Print::print(double n, int digits)
|
||||
{
|
||||
return printFloat(n, digits);
|
||||
}
|
||||
|
||||
size_t Print::println(void)
|
||||
{
|
||||
return print("\r\n");
|
||||
}
|
||||
|
||||
size_t Print::println(const std::string &s)
|
||||
{
|
||||
size_t n = print(s);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(const char c[])
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(char c)
|
||||
{
|
||||
size_t n = print(c);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned char b, int base)
|
||||
{
|
||||
size_t n = print(b, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned int num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(unsigned long num, int base)
|
||||
{
|
||||
size_t n = print(num, base);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
size_t Print::println(double num, int digits)
|
||||
{
|
||||
size_t n = print(num, digits);
|
||||
n += println();
|
||||
return n;
|
||||
}
|
||||
|
||||
// Private Methods /////////////////////////////////////////////////////////////
|
||||
|
||||
size_t Print::printNumber(unsigned long n, uint8_t base)
|
||||
{
|
||||
char buf[8 * sizeof(long) + 1]; // Assumes 8-bit chars plus zero byte.
|
||||
char *str = &buf[sizeof(buf) - 1];
|
||||
|
||||
*str = '\0';
|
||||
|
||||
// prevent crash if called with base == 1
|
||||
if(base < 2) {
|
||||
base = 10;
|
||||
}
|
||||
|
||||
do {
|
||||
char c = n % base;
|
||||
n /= base;
|
||||
|
||||
*--str = c < 10 ? c + '0' : c + 'A' - 10;
|
||||
} while(n);
|
||||
|
||||
return write(str);
|
||||
}
|
||||
|
||||
size_t Print::printFloat(double number, uint8_t digits)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
if(std::isnan(number)) {
|
||||
return print("nan");
|
||||
}
|
||||
if(std::isinf(number)) {
|
||||
return print("inf");
|
||||
}
|
||||
if(number > 4294967040.0) {
|
||||
return print("ovf"); // constant determined empirically
|
||||
}
|
||||
if(number < -4294967040.0) {
|
||||
return print("ovf"); // constant determined empirically
|
||||
}
|
||||
|
||||
// Handle negative numbers
|
||||
if(number < 0.0) {
|
||||
n += print('-');
|
||||
number = -number;
|
||||
}
|
||||
|
||||
// Round correctly so that print(1.999, 2) prints as "2.00"
|
||||
double rounding = 0.5;
|
||||
for(uint8_t i = 0; i < digits; ++i) {
|
||||
rounding /= 10.0;
|
||||
}
|
||||
|
||||
number += rounding;
|
||||
|
||||
// Extract the integer part of the number and print it
|
||||
unsigned long int_part = (unsigned long) number;
|
||||
double remainder = number - (double) int_part;
|
||||
n += print(int_part);
|
||||
|
||||
// Print the decimal point, but only if there are digits beyond
|
||||
if(digits > 0) {
|
||||
n += print(".");
|
||||
}
|
||||
|
||||
// Extract digits from the remainder one at a time
|
||||
while(digits-- > 0) {
|
||||
remainder *= 10.0;
|
||||
int toPrint = int(remainder);
|
||||
n += print(toPrint);
|
||||
remainder -= toPrint;
|
||||
}
|
||||
|
||||
return n;
|
||||
}
|
||||
98
lib/MySensors/hal/architecture/Linux/drivers/core/Print.h
Normal file
98
lib/MySensors/hal/architecture/Linux/drivers/core/Print.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Print.h - Base class that provides print() and println()
|
||||
Copyright (c) 2008 David A. Mellis. 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
|
||||
|
||||
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#ifndef Print_h
|
||||
#define Print_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
|
||||
#if !DOXYGEN
|
||||
#define DEC 10
|
||||
#define HEX 16
|
||||
#define OCT 8
|
||||
#define BIN 2
|
||||
|
||||
class Print
|
||||
{
|
||||
private:
|
||||
int write_error;
|
||||
size_t printNumber(unsigned long n, uint8_t base);
|
||||
size_t printFloat(double number, uint8_t digits);
|
||||
|
||||
protected:
|
||||
void setWriteError(int err = 1)
|
||||
{
|
||||
write_error = err;
|
||||
}
|
||||
|
||||
public:
|
||||
Print() : write_error(0) {}
|
||||
|
||||
int getWriteError()
|
||||
{
|
||||
return write_error;
|
||||
}
|
||||
void clearWriteError()
|
||||
{
|
||||
setWriteError(0);
|
||||
}
|
||||
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
size_t write(const char *str)
|
||||
{
|
||||
if (str == NULL) {
|
||||
return 0;
|
||||
}
|
||||
return write((const uint8_t *) str, strlen(str));
|
||||
}
|
||||
virtual size_t write(const uint8_t *buffer, size_t size);
|
||||
size_t write(const char *buffer, size_t size)
|
||||
{
|
||||
return write((const uint8_t *) buffer, size);
|
||||
}
|
||||
|
||||
size_t printf(const char * format, ...) __attribute__ ((format (printf, 2, 3)));
|
||||
size_t print(const std::string &);
|
||||
size_t print(const char[]);
|
||||
size_t print(char);
|
||||
size_t print(unsigned char, int = DEC);
|
||||
size_t print(int, int = DEC);
|
||||
size_t print(unsigned int, int = DEC);
|
||||
size_t print(long, int = DEC);
|
||||
size_t print(unsigned long, int = DEC);
|
||||
size_t print(double, int = 2);
|
||||
|
||||
size_t println(const std::string &s);
|
||||
size_t println(const char[]);
|
||||
size_t println(char);
|
||||
size_t println(unsigned char, int = DEC);
|
||||
size_t println(int, int = DEC);
|
||||
size_t println(unsigned int, int = DEC);
|
||||
size_t println(long, int = DEC);
|
||||
size_t println(unsigned long, int = DEC);
|
||||
size_t println(double, int = 2);
|
||||
size_t println(void);
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif
|
||||
31
lib/MySensors/hal/architecture/Linux/drivers/core/SPI.h
Normal file
31
lib/MySensors/hal/architecture/Linux/drivers/core/SPI.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef _SPI_H_
|
||||
#define _SPI_H_
|
||||
|
||||
#ifdef LINUX_SPI_BCM
|
||||
#include "SPIBCM.h"
|
||||
#define SPI SPIBCM
|
||||
#elif LINUX_SPI_SPIDEV
|
||||
#include "SPIDEV.h"
|
||||
#define SPI SPIDEV
|
||||
#endif
|
||||
|
||||
#endif
|
||||
368
lib/MySensors/hal/architecture/Linux/drivers/core/SPIDEV.cpp
Normal file
368
lib/MySensors/hal/architecture/Linux/drivers/core/SPIDEV.cpp
Normal file
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
|
||||
*/
|
||||
|
||||
#include "SPIDEV.h"
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include "log.h"
|
||||
|
||||
static pthread_mutex_t spiMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutexattr_t attr;
|
||||
|
||||
// Declare a single default instance
|
||||
SPIDEVClass SPIDEV = SPIDEVClass();
|
||||
|
||||
uint8_t SPIDEVClass::initialized = 0;
|
||||
int SPIDEVClass::fd = -1;
|
||||
std::string SPIDEVClass::device = SPI_SPIDEV_DEVICE;
|
||||
uint8_t SPIDEVClass::mode = SPI_MODE0;
|
||||
uint32_t SPIDEVClass::speed = SPI_CLOCK_BASE;
|
||||
uint8_t SPIDEVClass::bit_order = MSBFIRST;
|
||||
struct spi_ioc_transfer SPIDEVClass::tr = {0,0,0,0,0,8,0,0,0,0}; // 8 bits_per_word, 0 cs_change
|
||||
|
||||
SPIDEVClass::SPIDEVClass()
|
||||
{
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&spiMutex, &attr);
|
||||
}
|
||||
|
||||
void SPIDEVClass::begin(int busNo)
|
||||
{
|
||||
if (!initialized) {
|
||||
/* set spidev accordingly to busNo like:
|
||||
* busNo = 23 -> /dev/spidev2.3
|
||||
*
|
||||
* a bit messy but simple
|
||||
* */
|
||||
device[11] += (busNo / 10) % 10;
|
||||
device[13] += busNo % 10;
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
initialized++; // reference count
|
||||
}
|
||||
|
||||
void SPIDEVClass::end()
|
||||
{
|
||||
if (initialized) {
|
||||
initialized--;
|
||||
}
|
||||
|
||||
if (!initialized) {
|
||||
if (!(fd < 0)) {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPIDEVClass::setBitOrder(uint8_t border)
|
||||
{
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
/*
|
||||
* bit order
|
||||
*/
|
||||
bit_order = border;
|
||||
int ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bit order.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bit order.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIDEVClass::setDataMode(uint8_t data_mode)
|
||||
{
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
/*
|
||||
* spi mode
|
||||
*/
|
||||
mode = data_mode;
|
||||
int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI mode.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI mode.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIDEVClass::setClockDivider(uint16_t divider)
|
||||
{
|
||||
if (divider == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
/*
|
||||
* max speed hz
|
||||
*/
|
||||
speed = SPI_CLOCK_BASE / divider;
|
||||
int ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI max speed hz.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI max speed hz.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIDEVClass::chipSelect(int csn_chip)
|
||||
{
|
||||
if (csn_chip >= 0 && csn_chip <= 9) {
|
||||
device[13] = '0' + (csn_chip % 10);
|
||||
|
||||
init();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SPIDEVClass::transfer(uint8_t data)
|
||||
{
|
||||
int ret;
|
||||
uint8_t tx[1] = {data};
|
||||
uint8_t rx[1] = {0};
|
||||
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
tr.tx_buf = (unsigned long)&tx[0];
|
||||
tr.rx_buf = (unsigned long)&rx[0];
|
||||
tr.len = 1;
|
||||
tr.speed_hz = speed;
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
|
||||
if (ret < 1) {
|
||||
logError("Can't send spi message.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
|
||||
return rx[0];
|
||||
}
|
||||
|
||||
void SPIDEVClass::transfernb(char* tbuf, char* rbuf, uint32_t len)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
tr.tx_buf = (unsigned long)tbuf;
|
||||
tr.rx_buf = (unsigned long)rbuf;
|
||||
tr.len = len;
|
||||
tr.speed_hz = speed;
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_MESSAGE(1), &tr);
|
||||
if (ret < 1) {
|
||||
logError("Can't send spi message.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIDEVClass::transfern(char* buf, uint32_t len)
|
||||
{
|
||||
transfernb(buf, buf, len);
|
||||
}
|
||||
|
||||
void SPIDEVClass::beginTransaction(SPISettings settings)
|
||||
{
|
||||
int ret;
|
||||
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
/*
|
||||
* spi mode
|
||||
*/
|
||||
if (settings.dmode != mode) {
|
||||
mode = settings.dmode;
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
|
||||
if (ret == -1) {
|
||||
logError("Can't set spi mode.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
|
||||
if (ret == -1) {
|
||||
logError("Can't set spi mode.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* speed
|
||||
*/
|
||||
if (settings.clock != speed) {
|
||||
speed = settings.clock;
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI max speed hz.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI max speed hz.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* bit order
|
||||
*/
|
||||
if (settings.border != bit_order) {
|
||||
bit_order = settings.border;
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bit order.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bit order.\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SPIDEVClass::endTransaction()
|
||||
{
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
|
||||
void SPIDEVClass::usingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
|
||||
void SPIDEVClass::notUsingInterrupt(uint8_t interruptNumber)
|
||||
{
|
||||
(void)interruptNumber;
|
||||
}
|
||||
|
||||
void SPIDEVClass::init()
|
||||
{
|
||||
pthread_mutex_lock(&spiMutex);
|
||||
|
||||
if (fd >= 0) {
|
||||
close(fd);
|
||||
}
|
||||
|
||||
fd = open(device.c_str(), O_RDWR);
|
||||
if (fd < 0) {
|
||||
logError("Can't open SPI device: %s\n", device.c_str());
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* spi mode
|
||||
*/
|
||||
int ret = ioctl(fd, SPI_IOC_WR_MODE, &mode);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI mode.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MODE, &mode);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI mode.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* bits per word
|
||||
*/
|
||||
uint8_t bits = 8; // 8 bits per word
|
||||
ret = ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bits per word.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_BITS_PER_WORD, &bits);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bits per word.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* max speed hz
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI max speed hz.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI max speed hz.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
/*
|
||||
* bit order
|
||||
*/
|
||||
ret = ioctl(fd, SPI_IOC_WR_LSB_FIRST, &bit_order);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bit order.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
ret = ioctl(fd, SPI_IOC_RD_LSB_FIRST, &bit_order);
|
||||
if (ret == -1) {
|
||||
logError("Can't set SPI bit order.\n");
|
||||
abort();
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&spiMutex);
|
||||
}
|
||||
212
lib/MySensors/hal/architecture/Linux/drivers/core/SPIDEV.h
Normal file
212
lib/MySensors/hal/architecture/Linux/drivers/core/SPIDEV.h
Normal file
@@ -0,0 +1,212 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on TMRh20 RF24 library, Copyright (c) 2015 Charles-Henri Hallard <tmrh20@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef SPIDEV_h
|
||||
#define SPIDEV_h
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#define SPI_HAS_TRANSACTION
|
||||
|
||||
#define MSBFIRST 0
|
||||
#define LSBFIRST SPI_LSB_FIRST
|
||||
|
||||
#define SPI_CLOCK_BASE 16000000 // 16Mhz
|
||||
|
||||
#define SPI_CLOCK_DIV1 1
|
||||
#define SPI_CLOCK_DIV2 2
|
||||
#define SPI_CLOCK_DIV4 4
|
||||
#define SPI_CLOCK_DIV8 8
|
||||
#define SPI_CLOCK_DIV16 16
|
||||
#define SPI_CLOCK_DIV32 32
|
||||
#define SPI_CLOCK_DIV64 64
|
||||
#define SPI_CLOCK_DIV128 128
|
||||
#define SPI_CLOCK_DIV256 256
|
||||
|
||||
// SPI Data mode
|
||||
#define SPI_MODE0 SPI_MODE_0
|
||||
#define SPI_MODE1 SPI_MODE_1
|
||||
#define SPI_MODE2 SPI_MODE_2
|
||||
#define SPI_MODE3 SPI_MODE_3
|
||||
|
||||
#ifndef SPI_SPIDEV_DEVICE
|
||||
#define SPI_SPIDEV_DEVICE "/dev/spidev0.0"
|
||||
#endif
|
||||
|
||||
// Default to Raspberry Pi
|
||||
const uint8_t SS = 24;
|
||||
const uint8_t MOSI = 19;
|
||||
const uint8_t MISO = 21;
|
||||
const uint8_t SCK = 23;
|
||||
|
||||
/**
|
||||
* SPISettings class
|
||||
*/
|
||||
class SPISettings
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SPISettings constructor.
|
||||
*/
|
||||
SPISettings()
|
||||
{
|
||||
init(SPI_CLOCK_BASE, MSBFIRST, SPI_MODE0);
|
||||
}
|
||||
/**
|
||||
* @brief SPISettings constructor.
|
||||
*
|
||||
* @param clock SPI clock speed in Hz.
|
||||
* @param bitOrder SPI bit order.
|
||||
* @param dataMode SPI data mode.
|
||||
*/
|
||||
SPISettings(uint32_t clock, uint8_t bitOrder, uint8_t dataMode)
|
||||
{
|
||||
init(clock, bitOrder, dataMode);
|
||||
}
|
||||
|
||||
uint32_t clock; //!< @brief SPI clock.
|
||||
uint8_t border; //!< @brief SPI bit order.
|
||||
uint8_t dmode; //!< @brief SPI data mode.
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Initialized class members.
|
||||
*
|
||||
* @param clk SPI clock.
|
||||
* @param bitOrder SPI bit order.
|
||||
* @param dataMode SPI data mode.
|
||||
*/
|
||||
void init(uint32_t clk, uint8_t bitOrder, uint8_t dataMode)
|
||||
{
|
||||
clock = clk;
|
||||
border = bitOrder;
|
||||
dmode = dataMode;
|
||||
}
|
||||
|
||||
friend class SPIDEVClass;
|
||||
};
|
||||
|
||||
/**
|
||||
* SPIDEV class
|
||||
*/
|
||||
class SPIDEVClass
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SPIDEVClass constructor.
|
||||
*/
|
||||
SPIDEVClass();
|
||||
/**
|
||||
* @brief Start SPI operations.
|
||||
*/
|
||||
static void begin(int busNo=0);
|
||||
/**
|
||||
* @brief End SPI operations.
|
||||
*/
|
||||
static void end();
|
||||
/**
|
||||
* @brief Sets the SPI bit order.
|
||||
*
|
||||
* @param bit_order The desired bit order.
|
||||
*/
|
||||
static void setBitOrder(uint8_t bit_order);
|
||||
/**
|
||||
* @brief Sets the SPI data mode.
|
||||
*
|
||||
* @param data_mode The desired data mode.
|
||||
*/
|
||||
static void setDataMode(uint8_t data_mode);
|
||||
/**
|
||||
* @brief Sets the SPI clock divider and therefore the SPI clock speed.
|
||||
*
|
||||
* @param divider The desired SPI clock divider.
|
||||
*/
|
||||
static void setClockDivider(uint16_t divider);
|
||||
/**
|
||||
* @brief Sets the chip select pin.
|
||||
*
|
||||
* @param csn_chip Specifies the CS chip.
|
||||
*/
|
||||
static void chipSelect(int csn_chip);
|
||||
/**
|
||||
* @brief Transfer a single byte
|
||||
*
|
||||
* @param data Byte to send
|
||||
* @return Data returned via spi
|
||||
*/
|
||||
static uint8_t transfer(uint8_t data);
|
||||
/**
|
||||
* @brief Transfer a buffer of data
|
||||
*
|
||||
* @param tbuf Transmit buffer
|
||||
* @param rbuf Receive buffer
|
||||
* @param len Length of the data
|
||||
*/
|
||||
static void transfernb(char* tbuf, char* rbuf, uint32_t len);
|
||||
/**
|
||||
* @brief Transfer a buffer of data without an rx buffer
|
||||
*
|
||||
* @param buf Pointer to a buffer of data
|
||||
* @param len Length of the data
|
||||
*/
|
||||
static void transfern(char* buf, uint32_t len);
|
||||
/**
|
||||
* @brief Start SPI transaction.
|
||||
*
|
||||
* @param settings for SPI.
|
||||
*/
|
||||
static void beginTransaction(SPISettings settings);
|
||||
/**
|
||||
* @brief End SPI transaction.
|
||||
*/
|
||||
static void endTransaction();
|
||||
/**
|
||||
* @brief Not implemented.
|
||||
*
|
||||
* @param interruptNumber ignored parameter.
|
||||
*/
|
||||
static void usingInterrupt(uint8_t interruptNumber);
|
||||
/**
|
||||
* @brief Not implemented.
|
||||
*
|
||||
* @param interruptNumber ignored parameter.
|
||||
*/
|
||||
static void notUsingInterrupt(uint8_t interruptNumber);
|
||||
|
||||
private:
|
||||
static uint8_t initialized; //!< @brief SPI initialized flag.
|
||||
static int fd; //!< @brief SPI device file descriptor.
|
||||
static std::string device; //!< @brief Default SPI device.
|
||||
static uint8_t mode; //!< @brief SPI mode.
|
||||
static uint32_t speed; //!< @brief SPI speed.
|
||||
static uint8_t bit_order; //!< @brief SPI bit order.
|
||||
static struct spi_ioc_transfer tr; //!< @brief Auxiliar struct for data transfer.
|
||||
|
||||
static void init();
|
||||
};
|
||||
|
||||
extern SPIDEVClass SPIDEV;
|
||||
|
||||
#endif
|
||||
285
lib/MySensors/hal/architecture/Linux/drivers/core/SerialPort.cpp
Normal file
285
lib/MySensors/hal/architecture/Linux/drivers/core/SerialPort.cpp
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <limits.h>
|
||||
#include <unistd.h>
|
||||
#include <termios.h>
|
||||
#include <grp.h>
|
||||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "log.h"
|
||||
#include "SerialPort.h"
|
||||
|
||||
SerialPort::SerialPort(const char *port, bool isPty) : serialPort(std::string(port)), isPty(isPty)
|
||||
{
|
||||
sd = -1;
|
||||
}
|
||||
|
||||
void SerialPort::begin(int bauds)
|
||||
{
|
||||
if (!open(bauds)) {
|
||||
logError("Failed to open serial port.\n");
|
||||
exit(1);
|
||||
}
|
||||
logDebug("Serial port %s (%d baud) created\n", serialPort.c_str(), bauds);
|
||||
}
|
||||
|
||||
bool SerialPort::open(int bauds)
|
||||
{
|
||||
speed_t speed;
|
||||
struct termios options;
|
||||
|
||||
if (isPty) {
|
||||
sd = posix_openpt(O_RDWR | O_NOCTTY | O_NDELAY);
|
||||
if (sd < 0) {
|
||||
logError("Couldn't open a PTY: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (grantpt(sd) != 0) {
|
||||
logError("Couldn't grant permission to the PTY: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (unlockpt(sd) != 0) {
|
||||
logError("Couldn't unlock the PTY: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
/* create a symlink with predictable name to the PTY device */
|
||||
unlink(serialPort.c_str()); // remove the symlink if it already exists
|
||||
if (symlink(ptsname(sd), serialPort.c_str()) != 0) {
|
||||
logError("Couldn't create a symlink '%s' to PTY! (%d) %s\n", serialPort.c_str(), errno,
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if ((sd = ::open(serialPort.c_str(), O_RDWR | O_NOCTTY | O_NDELAY)) == -1) {
|
||||
logError("Unable to open the serial port %s\n", serialPort.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
// nonblocking mode
|
||||
fcntl(sd, F_SETFL, FNDELAY);
|
||||
}
|
||||
|
||||
switch (bauds) {
|
||||
case 50:
|
||||
speed = B50 ;
|
||||
break ;
|
||||
case 75:
|
||||
speed = B75 ;
|
||||
break ;
|
||||
case 110:
|
||||
speed = B110 ;
|
||||
break ;
|
||||
case 134:
|
||||
speed = B134 ;
|
||||
break ;
|
||||
case 150:
|
||||
speed = B150 ;
|
||||
break ;
|
||||
case 200:
|
||||
speed = B200 ;
|
||||
break ;
|
||||
case 300:
|
||||
speed = B300 ;
|
||||
break ;
|
||||
case 600:
|
||||
speed = B600 ;
|
||||
break ;
|
||||
case 1200:
|
||||
speed = B1200 ;
|
||||
break ;
|
||||
case 1800:
|
||||
speed = B1800 ;
|
||||
break ;
|
||||
case 2400:
|
||||
speed = B2400 ;
|
||||
break ;
|
||||
case 9600:
|
||||
speed = B9600 ;
|
||||
break ;
|
||||
case 19200:
|
||||
speed = B19200 ;
|
||||
break ;
|
||||
case 38400:
|
||||
speed = B38400 ;
|
||||
break ;
|
||||
case 57600:
|
||||
speed = B57600 ;
|
||||
break ;
|
||||
case 115200:
|
||||
speed = B115200 ;
|
||||
break ;
|
||||
default:
|
||||
speed = B115200 ;
|
||||
break ;
|
||||
}
|
||||
|
||||
// Get the current options of the port
|
||||
if (tcgetattr(sd, &options) < 0) {
|
||||
logError("Couldn't get term attributes: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear all the options
|
||||
bzero(&options, sizeof(options));
|
||||
|
||||
// Set the baud rate
|
||||
cfsetispeed(&options, speed);
|
||||
cfsetospeed(&options, speed);
|
||||
|
||||
// Configure the device : 8 bits, no parity, no control
|
||||
options.c_cflag |= ( CLOCAL | CREAD | CS8);
|
||||
// Ignore framing errors, parity errors and BREAK condition on input.
|
||||
options.c_iflag |= ( IGNPAR | IGNBRK );
|
||||
|
||||
// Timer unused
|
||||
options.c_cc[VTIME]=0;
|
||||
// At least on character before satisfy reading
|
||||
options.c_cc[VMIN]=0;
|
||||
|
||||
// Set parameters
|
||||
if (tcsetattr(sd, TCSANOW, &options) < 0) {
|
||||
logError("Couldn't set term attributes: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
// flush
|
||||
if (tcflush(sd, TCIOFLUSH) < 0) {
|
||||
logError("Couldn't flush serial: %s\n", strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
usleep(10000);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SerialPort::setGroupPerm(const char *groupName)
|
||||
{
|
||||
const mode_t ttyPermissions = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
|
||||
|
||||
if (sd != -1 && groupName != NULL) {
|
||||
struct group *devGrp = getgrnam(groupName);
|
||||
if (devGrp == NULL) {
|
||||
logError("getgrnam: %s failed. (%d) %s\n", groupName, errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *dev;
|
||||
if (isPty) {
|
||||
dev = ptsname(sd);
|
||||
} else {
|
||||
dev = serialPort.c_str();
|
||||
}
|
||||
|
||||
int ret = chown(dev, -1, devGrp->gr_gid);
|
||||
if (ret == -1) {
|
||||
logError("Could not change PTY owner! (%d) %s\n", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
ret = chmod(dev, ttyPermissions);
|
||||
if (ret != 0) {
|
||||
logError("Could not change PTY permissions! (%d) %s\n", errno, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int SerialPort::available()
|
||||
{
|
||||
int nbytes = 0;
|
||||
|
||||
if (ioctl(sd, FIONREAD, &nbytes) < 0) {
|
||||
logError("Failed to get byte count on serial.\n");
|
||||
exit(-1);
|
||||
}
|
||||
return nbytes;
|
||||
}
|
||||
|
||||
int SerialPort::read()
|
||||
{
|
||||
unsigned char c;
|
||||
|
||||
int ret = ::read(sd, &c, 1);
|
||||
if (ret < 0) {
|
||||
logError("Serial - read failed: %s\n", strerror(errno));
|
||||
} else if (ret == 1) {
|
||||
return c;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t SerialPort::write(uint8_t b)
|
||||
{
|
||||
int ret = ::write(sd, &b, 1);
|
||||
if (ret < 0) {
|
||||
logError("Serial - write failed: %s\n", strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
size_t SerialPort::write(const uint8_t *buffer, size_t size)
|
||||
{
|
||||
int ret = ::write(sd, buffer, size);
|
||||
if (ret < 0) {
|
||||
logError("Serial - write failed: %s\n", strerror(errno));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int SerialPort::peek()
|
||||
{
|
||||
FILE * f = fdopen(sd, "r+");
|
||||
int c = getc(f);
|
||||
if (c == EOF) {
|
||||
return -1;
|
||||
}
|
||||
ungetc(c, f);
|
||||
return c;
|
||||
}
|
||||
|
||||
void SerialPort::flush()
|
||||
{
|
||||
// Waits until all output written to sd has been transmitted
|
||||
if (tcdrain(sd) < 0) {
|
||||
logError("Couldn't flush serial: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
void SerialPort::end()
|
||||
{
|
||||
close(sd);
|
||||
|
||||
if (isPty) {
|
||||
unlink(serialPort.c_str()); // remove the symlink
|
||||
}
|
||||
}
|
||||
114
lib/MySensors/hal/architecture/Linux/drivers/core/SerialPort.h
Normal file
114
lib/MySensors/hal/architecture/Linux/drivers/core/SerialPort.h
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef SerialPort_h
|
||||
#define SerialPort_h
|
||||
|
||||
#include <string>
|
||||
#include <stdbool.h>
|
||||
#include "Stream.h"
|
||||
|
||||
/**
|
||||
* SerialPort Class
|
||||
* Class that provides the functionality of arduino Serial library
|
||||
*/
|
||||
class SerialPort : public Stream
|
||||
{
|
||||
|
||||
private:
|
||||
int sd; //!< @brief file descriptor number.
|
||||
std::string serialPort; //!< @brief tty name.
|
||||
bool isPty; //!< @brief true if serial is pseudo terminal.
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SerialPort constructor.
|
||||
*/
|
||||
SerialPort(const char *port, bool isPty = false);
|
||||
/**
|
||||
* @brief Open the serial port and set the data rate in bits per second (baud).
|
||||
*
|
||||
* This function will terminate the program on an error.
|
||||
*
|
||||
* @param bauds bits per second.
|
||||
*/
|
||||
void begin(int bauds);
|
||||
/**
|
||||
* @brief Open the serial port and set the data rate in bits per second (baud).
|
||||
*
|
||||
* @param bauds bits per second.
|
||||
* @return @c true if no errors, else @c false.
|
||||
*/
|
||||
bool open(int bauds = 115200);
|
||||
/**
|
||||
* @brief Grant access to the specified system group for the serial device.
|
||||
*
|
||||
* @param groupName system group name.
|
||||
*/
|
||||
bool setGroupPerm(const char *groupName);
|
||||
/**
|
||||
* @brief Get the number of bytes available.
|
||||
*
|
||||
* Get the numberof bytes (characters) available for reading from
|
||||
* the serial port.
|
||||
*
|
||||
* @return number of bytes avalable to read.
|
||||
*/
|
||||
int available();
|
||||
/**
|
||||
* @brief Reads 1 byte of incoming serial data.
|
||||
*
|
||||
* @return first byte of incoming serial data available.
|
||||
*/
|
||||
int read();
|
||||
/**
|
||||
* @brief Writes a single byte to the serial port.
|
||||
*
|
||||
* @param b byte to write.
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
size_t write(uint8_t b);
|
||||
/**
|
||||
* @brief Writes binary data to the serial port.
|
||||
*
|
||||
* @param buffer to write.
|
||||
* @param size of the buffer.
|
||||
* @return number of bytes written.
|
||||
*/
|
||||
size_t write(const uint8_t *buffer, size_t size);
|
||||
/**
|
||||
* @brief
|
||||
*
|
||||
* Returns the next byte (character) of incoming serial data without removing it from
|
||||
* the internal serial buffer.
|
||||
*
|
||||
* @return -1 if no data else character in the buffer.
|
||||
*/
|
||||
int peek();
|
||||
/**
|
||||
* @brief Remove any data remaining on the serial buffer.
|
||||
*/
|
||||
void flush();
|
||||
/**
|
||||
* @brief Disables serial communication.
|
||||
*/
|
||||
void end();
|
||||
};
|
||||
|
||||
#endif
|
||||
33
lib/MySensors/hal/architecture/Linux/drivers/core/Server.h
Normal file
33
lib/MySensors/hal/architecture/Linux/drivers/core/Server.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
Server.h - Base class that provides Server
|
||||
Copyright (c) 2011 Adrian McEwen. 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
|
||||
*/
|
||||
|
||||
#ifndef server_h
|
||||
#define server_h
|
||||
|
||||
#include "Print.h"
|
||||
|
||||
#if !DOXYGEN
|
||||
class Server : public Print
|
||||
{
|
||||
public:
|
||||
virtual void begin() =0;
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
181
lib/MySensors/hal/architecture/Linux/drivers/core/SoftEeprom.cpp
Normal file
181
lib/MySensors/hal/architecture/Linux/drivers/core/SoftEeprom.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include "log.h"
|
||||
#include "SoftEeprom.h"
|
||||
|
||||
SoftEeprom::SoftEeprom() : _length(0), _fileName(NULL), _values(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
SoftEeprom::SoftEeprom(const SoftEeprom& other)
|
||||
{
|
||||
_fileName = strdup(other._fileName);
|
||||
|
||||
_length = other._length;
|
||||
_values = new uint8_t[_length];
|
||||
for (size_t i = 0; i < _length; ++i) {
|
||||
_values[i] = other._values[i];
|
||||
}
|
||||
}
|
||||
|
||||
SoftEeprom::~SoftEeprom()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
int SoftEeprom::init(const char *fileName, size_t length)
|
||||
{
|
||||
struct stat fileInfo;
|
||||
|
||||
destroy();
|
||||
|
||||
_fileName = strdup(fileName);
|
||||
if (_fileName == NULL) {
|
||||
logError("Error: %s\n", strerror(errno));
|
||||
return -1;
|
||||
}
|
||||
|
||||
_length = length;
|
||||
_values = new uint8_t[_length];
|
||||
|
||||
if (stat(_fileName, &fileInfo) != 0) {
|
||||
//File does not exist. Create it.
|
||||
logInfo("EEPROM file %s does not exist, creating new file.\n", _fileName);
|
||||
std::ofstream myFile(_fileName, std::ios::out | std::ios::binary);
|
||||
if (!myFile) {
|
||||
logError("Unable to create config file %s.\n", _fileName);
|
||||
return -1;
|
||||
}
|
||||
// Fill the eeprom with 1s
|
||||
for (size_t i = 0; i < _length; ++i) {
|
||||
_values[i] = 0xFF;
|
||||
}
|
||||
myFile.write((const char*)_values, _length);
|
||||
myFile.close();
|
||||
} else if (fileInfo.st_size < 0 || (size_t)fileInfo.st_size != _length) {
|
||||
logError("EEPROM file %s is not the correct size of %zu. Please remove the file and a new one will be created.\n",
|
||||
_fileName, _length);
|
||||
destroy();
|
||||
return -1;
|
||||
} else {
|
||||
//Read config into local memory.
|
||||
std::ifstream myFile(_fileName, std::ios::in | std::ios::binary);
|
||||
if (!myFile) {
|
||||
logError("Unable to open EEPROM file %s for reading.\n", _fileName);
|
||||
return -1;
|
||||
}
|
||||
myFile.read((char*)_values, _length);
|
||||
myFile.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SoftEeprom::destroy()
|
||||
{
|
||||
if (_values) {
|
||||
delete[] _values;
|
||||
_values = NULL;
|
||||
}
|
||||
if (_fileName) {
|
||||
free(_fileName);
|
||||
_fileName = NULL;
|
||||
}
|
||||
_length = 0;
|
||||
}
|
||||
|
||||
void SoftEeprom::readBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
|
||||
|
||||
if (!length) {
|
||||
logError("EEPROM being read without being initialized!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (offs + length <= _length) {
|
||||
memcpy(buf, _values+offs, length);
|
||||
}
|
||||
}
|
||||
|
||||
void SoftEeprom::writeBlock(void* buf, void* addr, size_t length)
|
||||
{
|
||||
unsigned long int offs = reinterpret_cast<unsigned long int>(addr);
|
||||
|
||||
if (!length) {
|
||||
logError("EEPROM being written without being initialized!\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (offs + length <= _length) {
|
||||
if (memcmp(_values+offs, buf, length) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
memcpy(_values+offs, buf, length);
|
||||
|
||||
std::ofstream myFile(_fileName, std::ios::out | std::ios::in | std::ios::binary);
|
||||
if (!myFile) {
|
||||
logError("Unable to write config to file %s.\n", _fileName);
|
||||
return;
|
||||
}
|
||||
myFile.seekp(offs);
|
||||
myFile.write((const char*)buf, length);
|
||||
myFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t SoftEeprom::readByte(int addr)
|
||||
{
|
||||
uint8_t value = 0xFF;
|
||||
readBlock(&value, reinterpret_cast<void*>(addr), 1);
|
||||
return value;
|
||||
}
|
||||
|
||||
void SoftEeprom::writeByte(int addr, uint8_t value)
|
||||
{
|
||||
uint8_t curr = readByte(addr);
|
||||
if (curr != value) {
|
||||
writeBlock(&value, reinterpret_cast<void*>(addr), 1);
|
||||
}
|
||||
}
|
||||
|
||||
SoftEeprom& SoftEeprom::operator=(const SoftEeprom& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
delete[] _values;
|
||||
free(_fileName);
|
||||
|
||||
_fileName = strdup(other._fileName);
|
||||
|
||||
_length = other._length;
|
||||
_values = new uint8_t[_length];
|
||||
for (size_t i = 0; i < _length; ++i) {
|
||||
_values[i] = other._values[i];
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
104
lib/MySensors/hal/architecture/Linux/drivers/core/SoftEeprom.h
Normal file
104
lib/MySensors/hal/architecture/Linux/drivers/core/SoftEeprom.h
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This a software emulation of EEPROM that uses a file for data storage.
|
||||
* A copy of the eeprom values are also held in memory for faster reading.
|
||||
*/
|
||||
|
||||
#ifndef SoftEeprom_h
|
||||
#define SoftEeprom_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* SoftEeprom class
|
||||
*/
|
||||
class SoftEeprom
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief SoftEeprom constructor.
|
||||
*/
|
||||
SoftEeprom();
|
||||
/**
|
||||
* @brief SoftEeprom copy constructor.
|
||||
*/
|
||||
SoftEeprom(const SoftEeprom& other);
|
||||
/**
|
||||
* @brief SoftEeprom destructor.
|
||||
*/
|
||||
~SoftEeprom();
|
||||
/**
|
||||
* @brief Initializes the eeprom class.
|
||||
*
|
||||
* @param fileName filepath where the data is saved.
|
||||
* @param length eeprom size in bytes.
|
||||
* @return 0 if SUCCESS or -1 if FAILURE.
|
||||
*/
|
||||
int init(const char *fileName, size_t length);
|
||||
/**
|
||||
* @brief Clear all allocated memory variables.
|
||||
*
|
||||
*/
|
||||
void destroy();
|
||||
/**
|
||||
* @brief Read a block of bytes from eeprom.
|
||||
*
|
||||
* @param buf buffer to copy to.
|
||||
* @param addr eeprom address to read from.
|
||||
* @param length number of bytes to read.
|
||||
*/
|
||||
void readBlock(void* buf, void* addr, size_t length);
|
||||
/**
|
||||
* @brief Write a block of bytes to eeprom.
|
||||
*
|
||||
* @param buf buffer to read from.
|
||||
* @param addr eeprom address to write to.
|
||||
* @param length number of bytes to write.
|
||||
*/
|
||||
void writeBlock(void* buf, void* addr, size_t length);
|
||||
/**
|
||||
* @brief Read a byte from eeprom.
|
||||
*
|
||||
* @param addr eeprom address to read from.
|
||||
* @return the read byte.
|
||||
*/
|
||||
uint8_t readByte(int addr);
|
||||
/**
|
||||
* @brief Write a byte to eeprom.
|
||||
*
|
||||
* @param addr eeprom address to write to.
|
||||
* @param value to write.
|
||||
*/
|
||||
void writeByte(int addr, uint8_t value);
|
||||
/**
|
||||
* @brief Overloaded assign operator.
|
||||
*
|
||||
*/
|
||||
SoftEeprom& operator=(const SoftEeprom& other);
|
||||
|
||||
private:
|
||||
size_t _length; //!< @brief Eeprom max size.
|
||||
char *_fileName; //!< @brief file where the eeprom values are stored.
|
||||
uint8_t *_values; //!< @brief copy of the eeprom values held in memory for a faster reading.
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "StdInOutStream.h"
|
||||
|
||||
void StdInOutStream::begin(int baud)
|
||||
{
|
||||
(void)baud;
|
||||
}
|
||||
|
||||
int StdInOutStream::available()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
int StdInOutStream::read()
|
||||
{
|
||||
return getchar();
|
||||
}
|
||||
|
||||
size_t StdInOutStream::write(uint8_t b)
|
||||
{
|
||||
return (size_t)::printf("%c", b);
|
||||
}
|
||||
|
||||
int StdInOutStream::peek()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
void StdInOutStream::flush()
|
||||
{
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void StdInOutStream::end()
|
||||
{
|
||||
flush();
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef StdInOutStream_h
|
||||
#define StdInOutStream_h
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "Stream.h"
|
||||
|
||||
/**
|
||||
* @brief A class that prints to stdout and reads from stdin
|
||||
*/
|
||||
class StdInOutStream : public Stream
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief This function does nothing.
|
||||
*
|
||||
* @param baud Ignored parameter.
|
||||
*/
|
||||
void begin(int baud);
|
||||
/**
|
||||
* @brief This function does nothing.
|
||||
*
|
||||
* @return always returns 1.
|
||||
*/
|
||||
int available();
|
||||
/**
|
||||
* @brief Reads 1 key pressed from the keyboard.
|
||||
*
|
||||
* @return key character pressed cast to an int.
|
||||
*/
|
||||
int read();
|
||||
/**
|
||||
* @brief Writes a single byte to stdout.
|
||||
*
|
||||
* @param b byte to write.
|
||||
* @return -1 if error else, number of bytes written.
|
||||
*/
|
||||
size_t write(uint8_t b);
|
||||
/**
|
||||
* @brief Not supported.
|
||||
*
|
||||
* @return always returns -1.
|
||||
*/
|
||||
int peek();
|
||||
/**
|
||||
* @brief Flush stdout.
|
||||
*/
|
||||
void flush();
|
||||
/**
|
||||
* @brief Nothing to do, flush stdout.
|
||||
*/
|
||||
void end();
|
||||
};
|
||||
|
||||
#endif
|
||||
292
lib/MySensors/hal/architecture/Linux/drivers/core/Stream.cpp
Normal file
292
lib/MySensors/hal/architecture/Linux/drivers/core/Stream.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
Stream.cpp - adds parsing methods to Stream class
|
||||
Copyright (c) 2008 David A. Mellis. 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
|
||||
|
||||
Created July 2011
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Stream.h>
|
||||
|
||||
#define PARSE_TIMEOUT 1000 // default number of milli-seconds to wait
|
||||
#define NO_SKIP_CHAR 1 // a magic char not found in a valid ASCII numeric field
|
||||
|
||||
// private method to read stream with timeout
|
||||
int Stream::timedRead()
|
||||
{
|
||||
_startMillis = millis();
|
||||
do {
|
||||
int c;
|
||||
c = read();
|
||||
if(c >= 0) {
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// private method to peek stream with timeout
|
||||
int Stream::timedPeek()
|
||||
{
|
||||
_startMillis = millis();
|
||||
do {
|
||||
int c;
|
||||
c = peek();
|
||||
if(c >= 0) {
|
||||
return c;
|
||||
}
|
||||
yield();
|
||||
} while(millis() - _startMillis < _timeout);
|
||||
return -1; // -1 indicates timeout
|
||||
}
|
||||
|
||||
// returns peek of the next digit in the stream or -1 if timeout
|
||||
// discards non-numeric characters
|
||||
int Stream::peekNextDigit()
|
||||
{
|
||||
while(1) {
|
||||
int c;
|
||||
c = timedPeek();
|
||||
if(c < 0) {
|
||||
return c; // timeout
|
||||
}
|
||||
if(c == '-') {
|
||||
return c;
|
||||
}
|
||||
if(c >= '0' && c <= '9') {
|
||||
return c;
|
||||
}
|
||||
read(); // discard non-numeric
|
||||
}
|
||||
}
|
||||
|
||||
// Public Methods
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
void Stream::setTimeout(unsigned long timeout) // sets the maximum number of milliseconds to wait
|
||||
{
|
||||
_timeout = timeout;
|
||||
}
|
||||
|
||||
// find returns true if the target string is found
|
||||
bool Stream::find(const char *target)
|
||||
{
|
||||
return findUntil(target, (char*) "");
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of given length is found
|
||||
// returns true if target string is found, false if timed out
|
||||
bool Stream::find(const char *target, size_t length)
|
||||
{
|
||||
return findUntil(target, length, NULL, 0);
|
||||
}
|
||||
|
||||
// as find but search ends if the terminator string is found
|
||||
bool Stream::findUntil(const char *target, const char *terminator)
|
||||
{
|
||||
return findUntil(target, strlen(target), terminator, strlen(terminator));
|
||||
}
|
||||
|
||||
// reads data from the stream until the target string of the given length is found
|
||||
// search terminated if the terminator string is found
|
||||
// returns true if target string is found, false if terminated or timed out
|
||||
bool Stream::findUntil(const char *target, size_t targetLen, const char *terminator,
|
||||
size_t termLen)
|
||||
{
|
||||
size_t index = 0; // maximum target string length is 64k bytes!
|
||||
size_t termIndex = 0;
|
||||
int c;
|
||||
|
||||
if(*target == 0) {
|
||||
return true; // return true if target is a null string
|
||||
}
|
||||
while((c = timedRead()) > 0) {
|
||||
|
||||
if(c != target[index]) {
|
||||
index = 0; // reset index if any char does not match
|
||||
}
|
||||
if(c == target[index]) {
|
||||
//////Serial.print("found "); Serial.write(c); Serial.print("index now"); Serial.println(index+1);
|
||||
if(++index >= targetLen) { // return true if all chars in the target match
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if(termLen > 0 && c == terminator[termIndex]) {
|
||||
if(++termIndex >= termLen) {
|
||||
return false; // return false if terminate string found before target string
|
||||
}
|
||||
} else {
|
||||
termIndex = 0;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// function is terminated by the first character that is not a digit.
|
||||
long Stream::parseInt()
|
||||
{
|
||||
return parseInt(NO_SKIP_CHAR); // terminate on first non-digit character (or timeout)
|
||||
}
|
||||
|
||||
// as above but a given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
long Stream::parseInt(char skipChar)
|
||||
{
|
||||
bool isNegative = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if(c == skipChar) {
|
||||
// ignore this charactor
|
||||
} else if(c == '-') {
|
||||
isNegative = true;
|
||||
} else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == skipChar);
|
||||
|
||||
if(isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
// as parseInt but returns a floating point value
|
||||
float Stream::parseFloat()
|
||||
{
|
||||
return parseFloat(NO_SKIP_CHAR);
|
||||
}
|
||||
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
float Stream::parseFloat(char skipChar)
|
||||
{
|
||||
bool isNegative = false;
|
||||
bool isFraction = false;
|
||||
long value = 0;
|
||||
int c;
|
||||
float fraction = 1.0;
|
||||
|
||||
c = peekNextDigit();
|
||||
// ignore non numeric leading characters
|
||||
if(c < 0) {
|
||||
return 0; // zero returned if timeout
|
||||
}
|
||||
|
||||
do {
|
||||
if(c == skipChar) {
|
||||
// ignore
|
||||
} else if(c == '-') {
|
||||
isNegative = true;
|
||||
} else if(c == '.') {
|
||||
isFraction = true;
|
||||
} else if(c >= '0' && c <= '9') { // is c a digit?
|
||||
value = value * 10 + c - '0';
|
||||
if(isFraction) {
|
||||
fraction *= 0.1;
|
||||
}
|
||||
}
|
||||
read(); // consume the character we got with peek
|
||||
c = timedPeek();
|
||||
} while((c >= '0' && c <= '9') || c == '.' || c == skipChar);
|
||||
|
||||
if(isNegative) {
|
||||
value = -value;
|
||||
}
|
||||
if(isFraction) {
|
||||
return value * fraction;
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
// read characters from stream into buffer
|
||||
// terminates if length characters have been read, or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer
|
||||
// the buffer is NOT null terminated.
|
||||
//
|
||||
size_t Stream::readBytes(char *buffer, size_t length)
|
||||
{
|
||||
size_t count = 0;
|
||||
while(count < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// as readBytes with terminator character
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t Stream::readBytesUntil(char terminator, char *buffer, size_t length)
|
||||
{
|
||||
if(length < 1) {
|
||||
return 0;
|
||||
}
|
||||
size_t index = 0;
|
||||
while(index < length) {
|
||||
int c = timedRead();
|
||||
if(c < 0 || c == terminator) {
|
||||
break;
|
||||
}
|
||||
*buffer++ = (char) c;
|
||||
index++;
|
||||
}
|
||||
return index; // return number of characters, not including null terminator
|
||||
}
|
||||
|
||||
std::string Stream::readString()
|
||||
{
|
||||
std::string ret;
|
||||
int c = timedRead();
|
||||
while(c >= 0) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Stream::readStringUntil(char terminator)
|
||||
{
|
||||
std::string ret;
|
||||
int c = timedRead();
|
||||
while(c >= 0 && c != terminator) {
|
||||
ret += (char) c;
|
||||
c = timedRead();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
138
lib/MySensors/hal/architecture/Linux/drivers/core/Stream.h
Normal file
138
lib/MySensors/hal/architecture/Linux/drivers/core/Stream.h
Normal file
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
Stream.h - base class for character-based streams.
|
||||
Copyright (c) 2010 David A. Mellis. 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
|
||||
|
||||
parsing functions based on TextFinder library by Michael Margolis
|
||||
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <string>
|
||||
#include "Print.h"
|
||||
|
||||
// compatability macros for testing
|
||||
/*
|
||||
#define getInt() parseInt()
|
||||
#define getInt(skipChar) parseInt(skipchar)
|
||||
#define getFloat() parseFloat()
|
||||
#define getFloat(skipChar) parseFloat(skipChar)
|
||||
#define getString( pre_string, post_string, buffer, length)
|
||||
readBytesBetween( pre_string, terminator, buffer, length)
|
||||
*/
|
||||
|
||||
#if !DOXYGEN
|
||||
class Stream: public Print
|
||||
{
|
||||
protected:
|
||||
unsigned long
|
||||
_timeout; // number of milliseconds to wait for the next char before aborting timed read
|
||||
unsigned long _startMillis; // used for timeout measurement
|
||||
int timedRead(); // private method to read stream with timeout
|
||||
int timedPeek(); // private method to peek stream with timeout
|
||||
int peekNextDigit(); // returns the next numeric digit in the stream or -1 if timeout
|
||||
|
||||
public:
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
|
||||
Stream()
|
||||
{
|
||||
_timeout = 1000;
|
||||
_startMillis = 0;
|
||||
}
|
||||
|
||||
// parsing methods
|
||||
|
||||
void setTimeout(unsigned long
|
||||
timeout); // sets maximum milliseconds to wait for stream data, default is 1 second
|
||||
|
||||
bool find(const char *target); // reads data from the stream until the target string is found
|
||||
bool find(uint8_t *target)
|
||||
{
|
||||
return find((char *) target);
|
||||
}
|
||||
// returns true if target string is found, false if timed out (see setTimeout)
|
||||
|
||||
bool find(const char *target, size_t
|
||||
length); // reads data from the stream until the target string of given length is found
|
||||
bool find(const uint8_t *target, size_t length)
|
||||
{
|
||||
return find((char *) target, length);
|
||||
}
|
||||
// returns true if target string is found, false if timed out
|
||||
|
||||
bool find(char target)
|
||||
{
|
||||
return find (&target, 1);
|
||||
}
|
||||
|
||||
bool findUntil(const char *target,
|
||||
const char *terminator); // as find but search ends if the terminator string is found
|
||||
bool findUntil(const uint8_t *target, const char *terminator)
|
||||
{
|
||||
return findUntil((char *) target, terminator);
|
||||
}
|
||||
|
||||
bool findUntil(const char *target, size_t targetLen, const char *terminate,
|
||||
size_t termLen); // as above but search ends if the terminate string is found
|
||||
bool findUntil(const uint8_t *target, size_t targetLen, const char *terminate, size_t termLen)
|
||||
{
|
||||
return findUntil((char *) target, targetLen, terminate, termLen);
|
||||
}
|
||||
|
||||
long parseInt(); // returns the first valid (long) integer value from the current position.
|
||||
// initial characters that are not digits (or the minus sign) are skipped
|
||||
// integer is terminated by the first character that is not a digit.
|
||||
|
||||
float parseFloat(); // float version of parseInt
|
||||
|
||||
virtual size_t readBytes(char *buffer, size_t length); // read chars from stream into buffer
|
||||
virtual size_t readBytes(uint8_t *buffer, size_t length)
|
||||
{
|
||||
return readBytes((char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read or timeout (see setTimeout)
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
size_t readBytesUntil(char terminator, char *buffer,
|
||||
size_t length); // as readBytes with terminator character
|
||||
size_t readBytesUntil(char terminator, uint8_t *buffer, size_t length)
|
||||
{
|
||||
return readBytesUntil(terminator, (char *) buffer, length);
|
||||
}
|
||||
// terminates if length characters have been read, timeout, or if the terminator character detected
|
||||
// returns the number of characters placed in the buffer (0 means no valid data found)
|
||||
|
||||
// Arduino String functions to be added here
|
||||
std::string readString();
|
||||
std::string readStringUntil(char terminator);
|
||||
|
||||
protected:
|
||||
long parseInt(char skipChar); // as above but the given skipChar is ignored
|
||||
// as above but the given skipChar is ignored
|
||||
// this allows format characters (typically commas) in values to be ignored
|
||||
|
||||
float parseFloat(char skipChar); // as above but the given skipChar is ignored
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -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-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.
|
||||
*/
|
||||
|
||||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include "Arduino.h"
|
||||
|
||||
// For millis()
|
||||
static unsigned long millis_at_start = 0;
|
||||
|
||||
void yield(void) {}
|
||||
|
||||
unsigned long millis(void)
|
||||
{
|
||||
timeval curTime;
|
||||
|
||||
if (millis_at_start == 0) {
|
||||
gettimeofday(&curTime, NULL);
|
||||
millis_at_start = curTime.tv_sec;
|
||||
}
|
||||
|
||||
gettimeofday(&curTime, NULL);
|
||||
return ((curTime.tv_sec - millis_at_start) * 1000) + (curTime.tv_usec / 1000);
|
||||
}
|
||||
|
||||
unsigned long micros()
|
||||
{
|
||||
timeval curTime;
|
||||
|
||||
if (millis_at_start == 0) {
|
||||
gettimeofday(&curTime, NULL);
|
||||
millis_at_start = curTime.tv_sec;
|
||||
}
|
||||
|
||||
gettimeofday(&curTime, NULL);
|
||||
return ((curTime.tv_sec - millis_at_start) * 1000000) + (curTime.tv_usec);
|
||||
}
|
||||
|
||||
void _delay_milliseconds(unsigned int millis)
|
||||
{
|
||||
struct timespec sleeper;
|
||||
|
||||
sleeper.tv_sec = (time_t)(millis / 1000);
|
||||
sleeper.tv_nsec = (long)(millis % 1000) * 1000000;
|
||||
nanosleep(&sleeper, NULL);
|
||||
}
|
||||
|
||||
void _delay_microseconds(unsigned int micro)
|
||||
{
|
||||
struct timespec sleeper;
|
||||
|
||||
sleeper.tv_sec = (time_t)(micro / 1000000);
|
||||
sleeper.tv_nsec = (long)(micro % 1000000) * 1000;
|
||||
nanosleep(&sleeper, NULL);
|
||||
}
|
||||
|
||||
void randomSeed(unsigned long seed)
|
||||
{
|
||||
if (seed != 0) {
|
||||
srand(seed);
|
||||
}
|
||||
}
|
||||
|
||||
long randMax(long howbig)
|
||||
{
|
||||
if (howbig == 0) {
|
||||
return 0;
|
||||
}
|
||||
return rand() % howbig;
|
||||
}
|
||||
|
||||
long randMinMax(long howsmall, long howbig)
|
||||
{
|
||||
if (howsmall >= howbig) {
|
||||
return howsmall;
|
||||
}
|
||||
long diff = howbig - howsmall;
|
||||
return randMax(diff) + howsmall;
|
||||
}
|
||||
304
lib/MySensors/hal/architecture/Linux/drivers/core/config.c
Normal file
304
lib/MySensors/hal/architecture/Linux/drivers/core/config.c
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on mosquitto project, Copyright (c) 2012 Roger Light <roger@atchoo.org>
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include "log.h"
|
||||
|
||||
static int _config_create(const char *config_file);
|
||||
static int _config_parse_int(char *token, const char *name, int *value);
|
||||
static int _config_parse_string(char *token, const char *name, char **value);
|
||||
|
||||
int config_parse(const char *config_file)
|
||||
{
|
||||
FILE *fptr;
|
||||
char buf[1024];
|
||||
struct stat fileInfo;
|
||||
|
||||
if (stat(config_file, &fileInfo) != 0) {
|
||||
//File does not exist. Create it.
|
||||
logInfo("Config file %s does not exist, creating new file.\n", config_file);
|
||||
_config_create(config_file);
|
||||
}
|
||||
|
||||
fptr = fopen(config_file, "rt");
|
||||
if (!fptr) {
|
||||
logError("Error opening config file \"%s\".\n", config_file);
|
||||
return -1;
|
||||
}
|
||||
|
||||
conf.verbose = 7;
|
||||
conf.log_pipe = 0;
|
||||
conf.log_pipe_file = NULL;
|
||||
conf.syslog = 0;
|
||||
conf.eeprom_file = NULL;
|
||||
conf.eeprom_size = 0;
|
||||
conf.soft_hmac_key = NULL;
|
||||
conf.soft_serial_key = NULL;
|
||||
conf.aes_key = NULL;
|
||||
|
||||
while (fgets(buf, 1024, fptr)) {
|
||||
if (buf[0] != '#' && buf[0] != 10 && buf[0] != 13) {
|
||||
while (buf[strlen(buf)-1] == 10 || buf[strlen(buf)-1] == 13) {
|
||||
buf[strlen(buf)-1] = 0;
|
||||
}
|
||||
|
||||
if (!strncmp(buf, "verbose=", 8)) {
|
||||
char *verbose = NULL;
|
||||
if (_config_parse_string(&(buf[8]), "verbose", &verbose)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
} else {
|
||||
if (!strncmp(verbose, "err", 3)) {
|
||||
conf.verbose = 3;
|
||||
} else if (!strncmp(verbose, "warn", 4)) {
|
||||
conf.verbose = 4;
|
||||
} else if (!strncmp(verbose, "notice", 6)) {
|
||||
conf.verbose = 5;
|
||||
} else if (!strncmp(verbose, "info", 4)) {
|
||||
conf.verbose = 6;
|
||||
} else if (!strncmp(verbose, "debug", 5)) {
|
||||
conf.verbose = 7;
|
||||
} else {
|
||||
logError("Invalid value for verbose in configuration.\n");
|
||||
fclose(fptr);
|
||||
free(verbose);
|
||||
return -1;
|
||||
}
|
||||
free(verbose);
|
||||
}
|
||||
} else if (!strncmp(buf, "log_file=", 9)) {
|
||||
if (_config_parse_int(&(buf[9]), "log_file", &conf.log_file)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
} else {
|
||||
if (conf.log_file != 0 && conf.log_file != 1) {
|
||||
logError("log_file must be 1 or 0 in configuration.\n");
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (!strncmp(buf, "log_filepath=", 13)) {
|
||||
if (_config_parse_string(&(buf[13]), "log_filepath", &conf.log_filepath)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strncmp(buf, "log_pipe=", 9)) {
|
||||
if (_config_parse_int(&(buf[9]), "log_pipe", &conf.log_pipe)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
} else {
|
||||
if (conf.log_pipe != 0 && conf.log_pipe != 1) {
|
||||
logError("log_pipe must be 1 or 0 in configuration.\n");
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (!strncmp(buf, "log_pipe_file=", 14)) {
|
||||
if (_config_parse_string(&(buf[14]), "log_pipe_file", &conf.log_pipe_file)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strncmp(buf, "syslog=", 7)) {
|
||||
if (_config_parse_int(&(buf[7]), "syslog", &conf.syslog)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
} else {
|
||||
if (conf.syslog != 0 && conf.syslog != 1) {
|
||||
logError("syslog must be 1 or 0 in configuration.\n");
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (!strncmp(buf, "eeprom_file=", 12)) {
|
||||
if (_config_parse_string(&(buf[12]), "eeprom_file", &conf.eeprom_file)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strncmp(buf, "eeprom_size=", 12)) {
|
||||
if (_config_parse_int(&(buf[12]), "eeprom_size", &conf.eeprom_size)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
} else {
|
||||
if (conf.eeprom_size <= 0) {
|
||||
logError("eeprom_size value must be greater than 0 in configuration.\n");
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} else if (!strncmp(buf, "soft_hmac_key=", 14)) {
|
||||
if (_config_parse_string(&(buf[14]), "soft_hmac_key", &conf.soft_hmac_key)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strncmp(buf, "soft_serial_key=", 16)) {
|
||||
if (_config_parse_string(&(buf[16]), "soft_serial_key", &conf.soft_serial_key)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
} else if (!strncmp(buf, "aes_key=", 8)) {
|
||||
if (_config_parse_string(&(buf[8]), "aes_key", &conf.aes_key)) {
|
||||
fclose(fptr);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
logWarning("Unknown config option \"%s\".\n", buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(fptr);
|
||||
|
||||
if (!conf.eeprom_file) {
|
||||
logError("No eeprom_file found in configuration.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conf.log_file && !conf.log_filepath) {
|
||||
logError("log_filepath must be set if you enable log_file in configuration.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (conf.log_pipe && !conf.log_pipe_file) {
|
||||
logError("log_pipe_file must be set if you enable log_pipe in configuration.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void config_cleanup(void)
|
||||
{
|
||||
if (conf.log_filepath) {
|
||||
free(conf.log_filepath);
|
||||
}
|
||||
if (conf.log_pipe_file) {
|
||||
free(conf.log_pipe_file);
|
||||
}
|
||||
if (conf.eeprom_file) {
|
||||
free(conf.eeprom_file);
|
||||
}
|
||||
if (conf.soft_hmac_key) {
|
||||
free(conf.soft_hmac_key);
|
||||
}
|
||||
if (conf.soft_serial_key) {
|
||||
free(conf.soft_serial_key);
|
||||
}
|
||||
if (conf.aes_key) {
|
||||
free(conf.aes_key);
|
||||
}
|
||||
}
|
||||
|
||||
int _config_create(const char *config_file)
|
||||
{
|
||||
FILE *myFile;
|
||||
int ret;
|
||||
|
||||
const char default_conf[] = "# Logging\n" \
|
||||
"# Verbosity: debug,info,notice,warn,err\n" \
|
||||
"verbose=debug\n" \
|
||||
"\n" \
|
||||
"# Enable logging to a file.\n" \
|
||||
"log_file=0\n" \
|
||||
"# Log file path.\n" \
|
||||
"log_filepath=/tmp/mysgw.log\n" \
|
||||
"\n" \
|
||||
"# Enable logging to a named pipe.\n" \
|
||||
"# Use this option to view your gateway's log messages\n" \
|
||||
"# from the log_pipe_file defined bellow.\n" \
|
||||
"# To do so, run the following command on another terminal:\n" \
|
||||
"# cat \"log_pipe_file\"\n" \
|
||||
"log_pipe=0\n" \
|
||||
"log_pipe_file=/tmp/mysgw.pipe\n" \
|
||||
"\n" \
|
||||
"# Enable logging to syslog.\n" \
|
||||
"syslog=0\n" \
|
||||
"\n" \
|
||||
"# EEPROM settings\n" \
|
||||
"eeprom_file=/etc/mysensors.eeprom\n" \
|
||||
"eeprom_size=1024\n" \
|
||||
"\n" \
|
||||
"# Software signing settings\n" \
|
||||
"# Note: The gateway must have been built with signing\n" \
|
||||
"# support to use the options below.\n" \
|
||||
"#\n" \
|
||||
"# To generate a HMAC key run mysgw with: --gen-soft-hmac-key\n" \
|
||||
"# copy the new key in the line below and uncomment it.\n" \
|
||||
"#soft_hmac_key=\n" \
|
||||
"# To generate a serial key run mysgw with: --gen-soft-serial-key\n" \
|
||||
"# copy the new key in the line below and uncomment it.\n" \
|
||||
"#soft_serial_key=\n" \
|
||||
"\n" \
|
||||
"# Encryption settings\n" \
|
||||
"# Note: The gateway must have been built with encryption\n" \
|
||||
"# support to use the options below.\n" \
|
||||
"#\n" \
|
||||
"# To generate a AES key run mysgw with: --gen-aes-key\n" \
|
||||
"# copy the new key in the line below and uncomment it.\n" \
|
||||
"#aes_key=\n";
|
||||
|
||||
myFile = fopen(config_file, "w");
|
||||
if (!myFile) {
|
||||
logError("Unable to create config file %s.\n", config_file);
|
||||
return -1;
|
||||
}
|
||||
ret = fputs(default_conf, myFile);
|
||||
fclose(myFile);
|
||||
|
||||
return (ret > 0);
|
||||
}
|
||||
|
||||
int _config_parse_int(char *token, const char *name, int *value)
|
||||
{
|
||||
if (token) {
|
||||
*value = atoi(token);
|
||||
} else {
|
||||
logError("Empty %s value in configuration.\n", name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _config_parse_string(char *token, const char *name, char **value)
|
||||
{
|
||||
if (token) {
|
||||
if (*value) {
|
||||
logError("Duplicate %s value in configuration.\n", name);
|
||||
return 1;
|
||||
}
|
||||
while (token[0] == ' ' || token[0] == '\t') {
|
||||
token++;
|
||||
}
|
||||
*value = strdup(token);
|
||||
if (!*value) {
|
||||
logError("Out of memory.\n");
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
logError("Empty %s value in configuration.\n", name);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
48
lib/MySensors/hal/architecture/Linux/drivers/core/config.h
Normal file
48
lib/MySensors/hal/architecture/Linux/drivers/core/config.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef CONFIG_H
|
||||
#define CONFIG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct config {
|
||||
int verbose;
|
||||
int log_file;
|
||||
char *log_filepath;
|
||||
int log_pipe;
|
||||
char *log_pipe_file;
|
||||
int syslog;
|
||||
char *eeprom_file;
|
||||
int eeprom_size;
|
||||
char *soft_hmac_key;
|
||||
char *soft_serial_key;
|
||||
char *aes_key;
|
||||
} conf;
|
||||
|
||||
int config_parse(const char *config_file);
|
||||
void config_cleanup(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
252
lib/MySensors/hal/architecture/Linux/drivers/core/interrupt.cpp
Normal file
252
lib/MySensors/hal/architecture/Linux/drivers/core/interrupt.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* Based on wiringPi Copyright (c) 2012 Gordon Henderson.
|
||||
*/
|
||||
|
||||
#include "interrupt.h"
|
||||
#include <pthread.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <poll.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <stropts.h>
|
||||
#include <errno.h>
|
||||
#include <sched.h>
|
||||
#include "log.h"
|
||||
|
||||
struct ThreadArgs {
|
||||
void (*func)();
|
||||
int gpioPin;
|
||||
};
|
||||
|
||||
volatile bool interruptsEnabled = true;
|
||||
static pthread_mutex_t intMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static pthread_t *threadIds[64] = {NULL};
|
||||
|
||||
// sysFds:
|
||||
// Map a file descriptor from the /sys/class/gpio/gpioX/value
|
||||
static int sysFds[64] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
};
|
||||
|
||||
/*
|
||||
* Part of wiringPi: Simple way to get your program running at high priority
|
||||
* with realtime schedulling.
|
||||
*/
|
||||
int piHiPri(const int pri)
|
||||
{
|
||||
struct sched_param sched ;
|
||||
|
||||
memset (&sched, 0, sizeof(sched)) ;
|
||||
|
||||
if (pri > sched_get_priority_max (SCHED_RR)) {
|
||||
sched.sched_priority = sched_get_priority_max (SCHED_RR) ;
|
||||
} else {
|
||||
sched.sched_priority = pri ;
|
||||
}
|
||||
|
||||
return sched_setscheduler (0, SCHED_RR, &sched) ;
|
||||
}
|
||||
|
||||
void *interruptHandler(void *args)
|
||||
{
|
||||
int fd;
|
||||
struct pollfd polls;
|
||||
char c;
|
||||
struct ThreadArgs *arguments = (struct ThreadArgs *)args;
|
||||
int gpioPin = arguments->gpioPin;
|
||||
void (*func)() = arguments->func;
|
||||
delete arguments;
|
||||
|
||||
(void)piHiPri(55); // Only effective if we run as root
|
||||
|
||||
if ((fd = sysFds[gpioPin]) == -1) {
|
||||
logError("Failed to attach interrupt for pin %d\n", gpioPin);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Setup poll structure
|
||||
polls.fd = fd;
|
||||
polls.events = POLLPRI | POLLERR;
|
||||
|
||||
while (1) {
|
||||
// Wait for it ...
|
||||
int ret = poll(&polls, 1, -1);
|
||||
if (ret < 0) {
|
||||
logError("Error waiting for interrupt: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
// Do a dummy read to clear the interrupt
|
||||
// A one character read appars to be enough.
|
||||
if (lseek (fd, 0, SEEK_SET) < 0) {
|
||||
logError("Interrupt handler error: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (read (fd, &c, 1) < 0) {
|
||||
logError("Interrupt handler error: %s\n", strerror(errno));
|
||||
break;
|
||||
}
|
||||
// Call user function.
|
||||
pthread_mutex_lock(&intMutex);
|
||||
if (interruptsEnabled) {
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
func();
|
||||
} else {
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void attachInterrupt(uint8_t gpioPin, void (*func)(), uint8_t mode)
|
||||
{
|
||||
FILE *fd;
|
||||
char fName[40];
|
||||
char c;
|
||||
int count, i;
|
||||
|
||||
if (threadIds[gpioPin] == NULL) {
|
||||
threadIds[gpioPin] = new pthread_t;
|
||||
} else {
|
||||
// Cancel the existing thread for that pin
|
||||
pthread_cancel(*threadIds[gpioPin]);
|
||||
// Wait a bit
|
||||
usleep(1000);
|
||||
}
|
||||
|
||||
// Export pin for interrupt
|
||||
if ((fd = fopen("/sys/class/gpio/export", "w")) == NULL) {
|
||||
logError("attachInterrupt: Unable to export pin %d for interrupt: %s\n", gpioPin, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fd, "%d\n", gpioPin);
|
||||
fclose(fd);
|
||||
|
||||
// Wait a bit the system to create /sys/class/gpio/gpio<GPIO number>
|
||||
usleep(1000);
|
||||
|
||||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/direction", gpioPin) ;
|
||||
if ((fd = fopen (fName, "w")) == NULL) {
|
||||
logError("attachInterrupt: Unable to open GPIO direction interface for pin %d: %s\n",
|
||||
gpioPin, strerror(errno));
|
||||
exit(1) ;
|
||||
}
|
||||
fprintf(fd, "in\n") ;
|
||||
fclose(fd) ;
|
||||
|
||||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/edge", gpioPin) ;
|
||||
if ((fd = fopen(fName, "w")) == NULL) {
|
||||
logError("attachInterrupt: Unable to open GPIO edge interface for pin %d: %s\n", gpioPin,
|
||||
strerror(errno));
|
||||
exit(1) ;
|
||||
}
|
||||
|
||||
switch (mode) {
|
||||
case CHANGE:
|
||||
fprintf(fd, "both\n");
|
||||
break;
|
||||
case FALLING:
|
||||
fprintf(fd, "falling\n");
|
||||
break;
|
||||
case RISING:
|
||||
fprintf(fd, "rising\n");
|
||||
break;
|
||||
case NONE:
|
||||
fprintf(fd, "none\n");
|
||||
break;
|
||||
default:
|
||||
logError("attachInterrupt: Invalid mode\n");
|
||||
fclose(fd);
|
||||
return;
|
||||
}
|
||||
fclose(fd);
|
||||
|
||||
if (sysFds[gpioPin] == -1) {
|
||||
snprintf(fName, sizeof(fName), "/sys/class/gpio/gpio%d/value", gpioPin);
|
||||
if ((sysFds[gpioPin] = open(fName, O_RDWR)) < 0) {
|
||||
logError("Error reading pin %d: %s\n", gpioPin, strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear any initial pending interrupt
|
||||
ioctl(sysFds[gpioPin], FIONREAD, &count);
|
||||
for (i = 0; i < count; ++i) {
|
||||
if (read(sysFds[gpioPin], &c, 1) == -1) {
|
||||
logError("attachInterrupt: failed to read pin status: %s\n", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
struct ThreadArgs *threadArgs = new struct ThreadArgs;
|
||||
threadArgs->func = func;
|
||||
threadArgs->gpioPin = gpioPin;
|
||||
|
||||
// Create a thread passing the pin and function
|
||||
pthread_create(threadIds[gpioPin], NULL, interruptHandler, (void *)threadArgs);
|
||||
}
|
||||
|
||||
void detachInterrupt(uint8_t gpioPin)
|
||||
{
|
||||
// Cancel the thread
|
||||
if (threadIds[gpioPin] != NULL) {
|
||||
pthread_cancel(*threadIds[gpioPin]);
|
||||
delete threadIds[gpioPin];
|
||||
threadIds[gpioPin] = NULL;
|
||||
}
|
||||
|
||||
// Close filehandle
|
||||
if (sysFds[gpioPin] != -1) {
|
||||
close(sysFds[gpioPin]);
|
||||
sysFds[gpioPin] = -1;
|
||||
}
|
||||
|
||||
FILE *fp = fopen("/sys/class/gpio/unexport", "w");
|
||||
if (fp == NULL) {
|
||||
logError("Unable to unexport pin %d for interrupt\n", gpioPin);
|
||||
exit(1);
|
||||
}
|
||||
fprintf(fp, "%d", gpioPin);
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
void interrupts()
|
||||
{
|
||||
pthread_mutex_lock(&intMutex);
|
||||
interruptsEnabled = true;
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
|
||||
void noInterrupts()
|
||||
{
|
||||
pthread_mutex_lock(&intMutex);
|
||||
interruptsEnabled = false;
|
||||
pthread_mutex_unlock(&intMutex);
|
||||
}
|
||||
@@ -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-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.
|
||||
*
|
||||
* Based on wiringPi Copyright (c) 2012 Gordon Henderson.
|
||||
*/
|
||||
|
||||
#ifndef interrupt_h
|
||||
#define interrupt_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define CHANGE 1
|
||||
#define FALLING 2
|
||||
#define RISING 3
|
||||
#define NONE 4
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void attachInterrupt(uint8_t gpioPin, void(*func)(), uint8_t mode);
|
||||
void detachInterrupt(uint8_t gpioPin);
|
||||
void interrupts();
|
||||
void noInterrupts();
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
278
lib/MySensors/hal/architecture/Linux/drivers/core/log.c
Normal file
278
lib/MySensors/hal/architecture/Linux/drivers/core/log.c
Normal file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "log.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
|
||||
static const char *_log_level_colors[] = {
|
||||
"\x1b[1;5;91m", "\x1b[1;91m", "\x1b[91m", "\x1b[31m", "\x1b[33m", "\x1b[34m", "\x1b[32m", "\x1b[36m"
|
||||
};
|
||||
static const char *_log_level_names[] = {
|
||||
"EMERGENCY", "ALERT", "CRITICAL", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"
|
||||
};
|
||||
static uint8_t _log_quiet = 0;
|
||||
static uint8_t _log_level = LOG_DEBUG;
|
||||
static uint8_t _log_syslog = 0;
|
||||
|
||||
static uint8_t _log_pipe = 0;
|
||||
static char *_log_pipe_file = NULL;
|
||||
static int _log_pipe_fd = -1;
|
||||
|
||||
static FILE *_log_file_fp = NULL;
|
||||
|
||||
void logSetQuiet(uint8_t enable)
|
||||
{
|
||||
_log_quiet = enable ? 1 : 0;
|
||||
}
|
||||
|
||||
void logSetLevel(int level)
|
||||
{
|
||||
if (level < LOG_EMERG || level > LOG_DEBUG) {
|
||||
return;
|
||||
}
|
||||
|
||||
_log_level = level;
|
||||
}
|
||||
|
||||
void logSetSyslog(int options, int facility)
|
||||
{
|
||||
openlog(NULL, options, facility);
|
||||
_log_syslog = 1;
|
||||
}
|
||||
|
||||
int logSetPipe(char *pipe_file)
|
||||
{
|
||||
if (pipe_file == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_log_pipe_file = strdup(pipe_file);
|
||||
if (_log_pipe_file == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ret = mkfifo(_log_pipe_file, 0666);
|
||||
if (ret == 0) {
|
||||
_log_pipe = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int logSetFile(char *file)
|
||||
{
|
||||
if (file == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
_log_file_fp = fopen(file, "a");
|
||||
if (_log_file_fp == NULL) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void logClose(void)
|
||||
{
|
||||
if (_log_syslog) {
|
||||
closelog();
|
||||
_log_syslog = 0;
|
||||
}
|
||||
|
||||
if (_log_pipe) {
|
||||
if (_log_pipe_fd > 0) {
|
||||
close(_log_pipe_fd);
|
||||
}
|
||||
/* remove the FIFO */
|
||||
unlink(_log_pipe_file);
|
||||
_log_pipe = 0;
|
||||
}
|
||||
if (_log_pipe_file != NULL) {
|
||||
free(_log_pipe_file);
|
||||
_log_pipe_file = NULL;
|
||||
}
|
||||
|
||||
if (_log_file_fp != NULL) {
|
||||
fclose(_log_file_fp);
|
||||
_log_file_fp = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void vlog(int level, const char *fmt, va_list args)
|
||||
{
|
||||
if (_log_level < level) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_log_quiet || _log_file_fp != NULL) {
|
||||
/* Get current time */
|
||||
time_t t = time(NULL);
|
||||
struct tm *lt = localtime(&t);
|
||||
|
||||
char date[16];
|
||||
date[strftime(date, sizeof(date), "%b %d %H:%M:%S", lt)] = '\0';
|
||||
|
||||
if (_log_file_fp != NULL) {
|
||||
fprintf(_log_file_fp, "%s %-5s ", date, _log_level_names[level]);
|
||||
vfprintf(_log_file_fp, fmt, args);
|
||||
fflush(_log_file_fp);
|
||||
}
|
||||
|
||||
if (!_log_quiet) {
|
||||
#ifdef LOG_DISABLE_COLOR
|
||||
(void)_log_level_colors;
|
||||
fprintf(stderr, "%s %-5s ", date, _log_level_names[level]);
|
||||
vfprintf(stderr, fmt, args);
|
||||
#else
|
||||
fprintf(stderr, "%s %s%-5s\x1b[0m ", date, _log_level_colors[level], _log_level_names[level]);
|
||||
vfprintf(stderr, fmt, args);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (_log_syslog) {
|
||||
vsyslog(level, fmt, args);
|
||||
}
|
||||
|
||||
if (_log_pipe) {
|
||||
if (_log_pipe_fd < 0) {
|
||||
_log_pipe_fd = open(_log_pipe_file, O_WRONLY | O_NONBLOCK);
|
||||
}
|
||||
if (_log_pipe_fd > 0) {
|
||||
if (vdprintf(_log_pipe_fd, fmt, args) < 0) {
|
||||
close(_log_pipe_fd);
|
||||
_log_pipe_fd = -1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logEmergency(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_EMERG, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logAlert(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_ALERT, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logCritical(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_CRIT, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logError(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_ERR, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logWarning(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_WARNING, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logNotice(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_NOTICE, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logInfo(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_INFO, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void
|
||||
#ifdef __GNUC__
|
||||
__attribute__((format(printf, 1, 2)))
|
||||
#endif
|
||||
logDebug(const char *fmt, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vlog(LOG_DEBUG, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
59
lib/MySensors/hal/architecture/Linux/drivers/core/log.h
Normal file
59
lib/MySensors/hal/architecture/Linux/drivers/core/log.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <syslog.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define vlogError(...) vlog(LOG_ERR, __VA_ARGS__)
|
||||
#define vlogWarning(...) vlog(LOG_WARNING, __VA_ARGS__)
|
||||
#define vlogNotice(...) vlog(LOG_NOTICE, __VA_ARGS__)
|
||||
#define vlogInfo(...) vlog(LOG_INFO, __VA_ARGS__)
|
||||
#define vlogDebug(...) vlog(LOG_DEBUG, __VA_ARGS__)
|
||||
|
||||
void logSetQuiet(uint8_t enable);
|
||||
void logSetLevel(int level);
|
||||
void logSetSyslog(int options, int facility);
|
||||
int logSetPipe(char *pipe_file);
|
||||
int logSetFile(char *file);
|
||||
void logClose(void);
|
||||
|
||||
void vlog(int level, const char *fmt, va_list args);
|
||||
void logEmergency(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logAlert(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logCritical(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logError(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logWarning(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logNotice(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logInfo(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
void logDebug(const char *fmt, ...) __attribute__((format(printf,1,2)));
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
158
lib/MySensors/hal/architecture/Linux/drivers/core/noniso.cpp
Normal file
158
lib/MySensors/hal/architecture/Linux/drivers/core/noniso.cpp
Normal file
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
noniso.cpp - replacements for non-ISO functions used by Arduino core
|
||||
Copyright © 2016 Ivan Grokhotkov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
Modified August 2016 by Marcelo Aquino <marceloaqno@gmail.org> for MySensors use
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
#include "stdlib_noniso.h"
|
||||
|
||||
char* utoa(unsigned value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
unsigned quotient = value;
|
||||
|
||||
do {
|
||||
const unsigned tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* itoa(int value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
int quotient = abs(value);
|
||||
|
||||
do {
|
||||
const int tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
// Apply negative sign
|
||||
if(value < 0) {
|
||||
*out++ = '-';
|
||||
}
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
int atoi(const char* s)
|
||||
{
|
||||
return (int) atol(s);
|
||||
}
|
||||
|
||||
long atol(const char* s)
|
||||
{
|
||||
char * tmp;
|
||||
return strtol(s, &tmp, 10);
|
||||
}
|
||||
|
||||
double atof(const char* s)
|
||||
{
|
||||
char * tmp;
|
||||
return strtod(s, &tmp);
|
||||
}
|
||||
|
||||
void reverse(char* begin, char* end)
|
||||
{
|
||||
char *is = begin;
|
||||
char *ie = end - 1;
|
||||
while(is < ie) {
|
||||
char tmp = *ie;
|
||||
*ie = *is;
|
||||
*is = tmp;
|
||||
++is;
|
||||
--ie;
|
||||
}
|
||||
}
|
||||
|
||||
char* ltoa(long value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
long quotient = abs(value);
|
||||
|
||||
do {
|
||||
const long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
// Apply negative sign
|
||||
if(value < 0) {
|
||||
*out++ = '-';
|
||||
}
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* ultoa(unsigned long value, char* result, int base)
|
||||
{
|
||||
if(base < 2 || base > 16) {
|
||||
*result = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* out = result;
|
||||
unsigned long quotient = value;
|
||||
|
||||
do {
|
||||
const unsigned long tmp = quotient / base;
|
||||
*out = "0123456789abcdef"[quotient - (tmp * base)];
|
||||
++out;
|
||||
quotient = tmp;
|
||||
} while(quotient);
|
||||
|
||||
reverse(result, out);
|
||||
*out = 0;
|
||||
return result;
|
||||
}
|
||||
|
||||
char* dtostrf (double val, signed char width, unsigned char prec, char *s)
|
||||
{
|
||||
sprintf(s,"%*.*f", width, prec, val);
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
stdlib_noniso.h - nonstandard (but usefull) conversion functions
|
||||
|
||||
Copyright (c) 2014 Ivan Grokhotkov. All rights reserved.
|
||||
This file is part of the esp8266 core for Arduino environment.
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#ifndef STDLIB_NONISO_H
|
||||
#define STDLIB_NONISO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
int atoi(const char *s);
|
||||
|
||||
long atol(const char* s);
|
||||
|
||||
double atof(const char* s);
|
||||
|
||||
char* itoa (int val, char *s, int radix);
|
||||
|
||||
char* ltoa (long val, char *s, int radix);
|
||||
|
||||
char* utoa (unsigned int val, char *s, int radix);
|
||||
|
||||
char* ultoa (unsigned long val, char *s, int radix);
|
||||
|
||||
char* dtostrf (double val, signed char width, unsigned char prec, char *s);
|
||||
|
||||
void reverse(char* begin, char* end);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
71
lib/MySensors/hal/architecture/MyHwHAL.cpp
Normal file
71
lib/MySensors/hal/architecture/MyHwHAL.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MyHwHAL.h"
|
||||
|
||||
void hwDebugPrint(const char *fmt, ...)
|
||||
{
|
||||
#ifndef MY_DISABLED_SERIAL
|
||||
#if !defined(__linux__)
|
||||
char fmtBuffer[MY_SERIAL_OUTPUT_SIZE];
|
||||
#ifdef MY_GATEWAY_SERIAL
|
||||
// prepend debug message to be handled correctly by controller (C_INTERNAL, I_LOG_MESSAGE)
|
||||
snprintf_P(fmtBuffer, sizeof(fmtBuffer), PSTR("0;255;%" PRIu8 ";0;%" PRIu8 ";"), C_INTERNAL,
|
||||
I_LOG_MESSAGE);
|
||||
MY_DEBUGDEVICE.print(fmtBuffer);
|
||||
#endif
|
||||
// prepend timestamp
|
||||
MY_DEBUGDEVICE.print(hwMillis());
|
||||
MY_DEBUGDEVICE.print(" ");
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vsnprintf_P(fmtBuffer, sizeof(fmtBuffer), fmt, args);
|
||||
#ifdef MY_GATEWAY_SERIAL
|
||||
// Truncate message if this is gateway node
|
||||
fmtBuffer[sizeof(fmtBuffer) - 2] = '\n';
|
||||
fmtBuffer[sizeof(fmtBuffer) - 1] = '\0';
|
||||
#endif
|
||||
va_end(args);
|
||||
MY_DEBUGDEVICE.print(fmtBuffer);
|
||||
MY_DEBUGDEVICE.flush();
|
||||
#else
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
vlogDebug(fmt, args);
|
||||
va_end(args);
|
||||
#endif
|
||||
#else
|
||||
(void)fmt;
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(DEBUG_OUTPUT_ENABLED)
|
||||
static char hwDebugPrintStr[65];
|
||||
static void hwDebugBuf2Str(const uint8_t *buf, size_t sz)
|
||||
{
|
||||
if (sz > 32) {
|
||||
sz = 32; //clamp to 32 bytes
|
||||
}
|
||||
for (uint8_t i = 0; i < sz; i++) {
|
||||
hwDebugPrintStr[i * 2] = convertI2H(buf[i] >> 4);
|
||||
hwDebugPrintStr[(i * 2) + 1] = convertI2H(buf[i]);
|
||||
}
|
||||
hwDebugPrintStr[sz * 2] = '\0';
|
||||
}
|
||||
#endif
|
||||
187
lib/MySensors/hal/architecture/MyHwHAL.h
Normal file
187
lib/MySensors/hal/architecture/MyHwHAL.h
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file MyHwHAL.h
|
||||
*
|
||||
* MySensors hardware abstraction layer
|
||||
*/
|
||||
|
||||
#ifndef MyHwHAL_h
|
||||
#define MyHwHAL_h
|
||||
|
||||
/**
|
||||
* @def INVALID_INTERRUPT_NUM
|
||||
* @brief Invalid interrupt
|
||||
*/
|
||||
#define INVALID_INTERRUPT_NUM (0xFFu)
|
||||
|
||||
/**
|
||||
* @def MY_HWID_PADDING_BYTE
|
||||
* @brief HwID padding byte
|
||||
*/
|
||||
#define MY_HWID_PADDING_BYTE (0xAAu)
|
||||
|
||||
/**
|
||||
* @def IRQ_HANDLER_ATTR
|
||||
* @brief ESP8266/ESP32 IRQ handlers need to be stored in IRAM
|
||||
*/
|
||||
#if defined(ARDUINO_ARCH_ESP8266) || defined(ARDUINO_ARCH_ESP32)
|
||||
#define IRQ_HANDLER_ATTR ICACHE_RAM_ATTR
|
||||
#else
|
||||
#define IRQ_HANDLER_ATTR
|
||||
#endif
|
||||
|
||||
// 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 *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);
|
||||
*/
|
||||
|
||||
/**
|
||||
* @def MY_HW_HAS_GETENTROPY
|
||||
* @brief Define this, if hwGetentropy is implemented
|
||||
*
|
||||
* ssize_t hwGetentropy(void *__buffer, size_t __length);
|
||||
*/
|
||||
//#define MY_HW_HAS_GETENTROPY
|
||||
|
||||
/// @brief unique ID
|
||||
typedef uint8_t unique_id_t[16];
|
||||
|
||||
/**
|
||||
* Sleep for a defined time, using minimum power.
|
||||
* @param ms Time to sleep, in [ms].
|
||||
* @return MY_WAKE_UP_BY_TIMER.
|
||||
*/
|
||||
int8_t hwSleep(uint32_t 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 MY_WAKE_UP_BY_TIMER when woken by timer, or interrupt number when woken by interrupt.
|
||||
*/
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t 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 MY_WAKE_UP_BY_TIMER when woken by timer, or interrupt number when woken by interrupt.
|
||||
*/
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t ms);
|
||||
|
||||
/**
|
||||
* Retrieve unique hardware ID
|
||||
* @param uniqueID unique ID
|
||||
* @return True if unique ID successfully retrieved
|
||||
*/
|
||||
bool hwUniqueID(unique_id_t *uniqueID);
|
||||
|
||||
/**
|
||||
* CPU voltage
|
||||
* @return CPU voltage in mV
|
||||
*/
|
||||
uint16_t hwCPUVoltage(void);
|
||||
|
||||
/**
|
||||
* CPU frequency
|
||||
* @return CPU frequency in 1/10Mhz
|
||||
*/
|
||||
uint16_t hwCPUFrequency(void);
|
||||
|
||||
/**
|
||||
* CPU temperature (if available)
|
||||
* Adjust calibration parameters via MY_<ARCH>_TEMPERATURE_OFFSET and MY_<ARCH>_TEMPERATURE_GAIN
|
||||
* @return CPU temperature in °C, -127 if not available
|
||||
*/
|
||||
int8_t hwCPUTemperature(void);
|
||||
|
||||
/**
|
||||
* Report free memory (if function available)
|
||||
* @return free memory in bytes
|
||||
*/
|
||||
uint16_t hwFreeMem(void);
|
||||
|
||||
#if defined(DEBUG_OUTPUT_ENABLED)
|
||||
/**
|
||||
* Debug print
|
||||
* @param fmt
|
||||
*/
|
||||
void hwDebugPrint(const char *fmt, ...);
|
||||
/**
|
||||
* Convert buffer to hex string
|
||||
* @param buf
|
||||
* @param sz
|
||||
*/
|
||||
static void hwDebugBuf2Str(const uint8_t *buf, size_t sz) __attribute__((unused));
|
||||
#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
|
||||
#define MY_HW_HAS_GETENTROPY
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif // #ifdef MyHw_h
|
||||
533
lib/MySensors/hal/architecture/NRF5/MyHwNRF5.cpp
Normal file
533
lib/MySensors/hal/architecture/NRF5/MyHwNRF5.cpp
Normal 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;
|
||||
}
|
||||
208
lib/MySensors/hal/architecture/NRF5/MyHwNRF5.h
Normal file
208
lib/MySensors/hal/architecture/NRF5/MyHwNRF5.h
Normal 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
|
||||
39
lib/MySensors/hal/architecture/NRF5/MyMainNRF5.cpp
Normal file
39
lib/MySensors/hal/architecture/NRF5/MyMainNRF5.cpp
Normal 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;
|
||||
}
|
||||
165
lib/MySensors/hal/architecture/NRF5/drivers/Flash.cpp
Normal file
165
lib/MySensors/hal/architecture/NRF5/drivers/Flash.cpp
Normal 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) {
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
@@ -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
|
||||
70
lib/MySensors/hal/architecture/NRF5/drivers/nrf_temp.h
Normal file
70
lib/MySensors/hal/architecture/NRF5/drivers/nrf_temp.h
Normal 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
|
||||
186
lib/MySensors/hal/architecture/NRF5/drivers/wdt.h
Normal file
186
lib/MySensors/hal/architecture/NRF5/drivers/wdt.h
Normal 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_ */
|
||||
256
lib/MySensors/hal/architecture/SAMD/MyHwSAMD.cpp
Normal file
256
lib/MySensors/hal/architecture/SAMD/MyHwSAMD.cpp
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#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 *addr, size_t length)
|
||||
{
|
||||
uint8_t *dst = static_cast<uint8_t *>(buf);
|
||||
const int offs = reinterpret_cast<int>(addr);
|
||||
(void)eep.read(offs, dst, 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);
|
||||
// use update() instead of write() to reduce e2p wear off
|
||||
(void)eep.update(offs, src, length);
|
||||
}
|
||||
|
||||
uint8_t hwReadConfig(const int addr)
|
||||
{
|
||||
return eep.read(addr);
|
||||
}
|
||||
|
||||
void hwWriteConfig(const int addr, uint8_t value)
|
||||
{
|
||||
(void)eep.update(addr, value);
|
||||
}
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
SYSCTRL->VREF.reg |= SYSCTRL_VREF_TSEN; // Enable the temperature sensor
|
||||
while (ADC->STATUS.bit.SYNCBUSY ==
|
||||
1); // Wait for synchronization of registers between the clock domains
|
||||
|
||||
const uint8_t eepInit = eep.begin(MY_EXT_EEPROM_TWI_CLOCK, &Wire);
|
||||
#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(uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t 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;
|
||||
}
|
||||
|
||||
// Wait for synchronization of registers between the clock domains
|
||||
static __inline__ void syncADC() __attribute__((always_inline, unused));
|
||||
static void syncADC()
|
||||
{
|
||||
while (ADC->STATUS.bit.SYNCBUSY);
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
// Set ADC reference to internal 1v
|
||||
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val;
|
||||
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
|
||||
syncADC();
|
||||
// Set to 10 bits reading resolution
|
||||
ADC->CTRLB.reg = ADC_CTRLB_RESSEL_10BIT | ADC_CTRLB_PRESCALER_DIV256;
|
||||
syncADC();
|
||||
// Select MUXPOS as SCALEDIOVCC/4 channel, and MUXNEG as internal ground
|
||||
ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_SCALEDIOVCC_Val;
|
||||
ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val;
|
||||
syncADC();
|
||||
// enable ADC
|
||||
ADC->CTRLA.bit.ENABLE = 1;
|
||||
syncADC();
|
||||
// start conversion
|
||||
ADC->SWTRIG.bit.START = 1;
|
||||
// clear the Data Ready flag
|
||||
ADC->INTFLAG.bit.RESRDY = 1;
|
||||
syncADC();
|
||||
// start conversion again, since The first conversion after the reference is changed must not be used.
|
||||
ADC->SWTRIG.bit.START = 1;
|
||||
// waiting for conversion to complete
|
||||
while (!ADC->INTFLAG.bit.RESRDY);
|
||||
syncADC();
|
||||
const uint32_t valueRead = ADC->RESULT.reg;
|
||||
// disable ADC
|
||||
ADC->CTRLA.bit.ENABLE = 0;
|
||||
syncADC();
|
||||
// value is 1/4 scaled, multiply by 4
|
||||
return valueRead * 4;
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency(void)
|
||||
{
|
||||
// TODO: currently reporting compile time frequency (in 1/10MHz)
|
||||
return F_CPU / 100000UL;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
// taken from https://github.com/arduino/ArduinoCore-samd/pull/277
|
||||
// Set to 12 bits resolution
|
||||
ADC->CTRLB.reg = ADC_CTRLB_RESSEL_12BIT | ADC_CTRLB_PRESCALER_DIV256;
|
||||
syncADC();
|
||||
// Ensure we are sampling slowly
|
||||
ADC->SAMPCTRL.reg = ADC_SAMPCTRL_SAMPLEN(0x3f);
|
||||
syncADC();
|
||||
// Set ADC reference to internal 1v
|
||||
ADC->INPUTCTRL.bit.GAIN = ADC_INPUTCTRL_GAIN_1X_Val;
|
||||
ADC->REFCTRL.bit.REFSEL = ADC_REFCTRL_REFSEL_INT1V_Val;
|
||||
syncADC();
|
||||
// Select MUXPOS as temperature channel, and MUXNEG as internal ground
|
||||
ADC->INPUTCTRL.bit.MUXPOS = ADC_INPUTCTRL_MUXPOS_TEMP_Val;
|
||||
ADC->INPUTCTRL.bit.MUXNEG = ADC_INPUTCTRL_MUXNEG_GND_Val;
|
||||
syncADC();
|
||||
// Enable ADC
|
||||
ADC->CTRLA.bit.ENABLE = 1;
|
||||
syncADC();
|
||||
// Start ADC conversion
|
||||
ADC->SWTRIG.bit.START = 1;
|
||||
// Clear the Data Ready flag
|
||||
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||
syncADC();
|
||||
// Start conversion again, since The first conversion after the reference is changed must not be used.
|
||||
ADC->SWTRIG.bit.START = 1;
|
||||
// Wait until ADC conversion is done
|
||||
while (!(ADC->INTFLAG.bit.RESRDY));
|
||||
syncADC();
|
||||
// Get result
|
||||
// This is signed so that the math later is done signed
|
||||
const int32_t adcReading = ADC->RESULT.reg;
|
||||
// Clear result ready flag
|
||||
ADC->INTFLAG.reg = ADC_INTFLAG_RESRDY;
|
||||
syncADC();
|
||||
// Disable ADC
|
||||
ADC->CTRLA.bit.ENABLE = 0;
|
||||
syncADC();
|
||||
// Factory room temperature readings
|
||||
const uint8_t roomInteger = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_INT_ADDR &
|
||||
FUSES_ROOM_TEMP_VAL_INT_Msk)
|
||||
>> FUSES_ROOM_TEMP_VAL_INT_Pos;
|
||||
const uint8_t roomDecimal = (*(uint32_t *)FUSES_ROOM_TEMP_VAL_DEC_ADDR &
|
||||
FUSES_ROOM_TEMP_VAL_DEC_Msk)
|
||||
>> FUSES_ROOM_TEMP_VAL_DEC_Pos;
|
||||
const int32_t roomReading = ((*(uint32_t *)FUSES_ROOM_ADC_VAL_ADDR & FUSES_ROOM_ADC_VAL_Msk) >>
|
||||
FUSES_ROOM_ADC_VAL_Pos);
|
||||
const int32_t roomTemperature = 1000 * roomInteger + 100 * roomDecimal;
|
||||
// Factory hot temperature readings
|
||||
const uint8_t hotInteger = (*(uint32_t *)FUSES_HOT_TEMP_VAL_INT_ADDR & FUSES_HOT_TEMP_VAL_INT_Msk)
|
||||
>>
|
||||
FUSES_HOT_TEMP_VAL_INT_Pos;
|
||||
const uint8_t hotDecimal = (*(uint32_t *)FUSES_HOT_TEMP_VAL_DEC_ADDR & FUSES_HOT_TEMP_VAL_DEC_Msk)
|
||||
>>
|
||||
FUSES_HOT_TEMP_VAL_DEC_Pos;
|
||||
const int32_t hotReading = ((*(uint32_t *)FUSES_HOT_ADC_VAL_ADDR & FUSES_HOT_ADC_VAL_Msk) >>
|
||||
FUSES_HOT_ADC_VAL_Pos);
|
||||
const int32_t hotTemperature = 1000 * hotInteger + 100 * hotDecimal;
|
||||
// Linear interpolation of temperature using factory room temperature and hot temperature
|
||||
const int32_t temperature = roomTemperature + ((hotTemperature - roomTemperature) *
|
||||
(adcReading - roomReading)) / (hotReading - roomReading);
|
||||
return static_cast<int8_t>(((temperature / 1000) - MY_SAMD_TEMPERATURE_OFFSET) /
|
||||
MY_SAMD_TEMPERATURE_GAIN);
|
||||
}
|
||||
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
144
lib/MySensors/hal/architecture/SAMD/MyHwSAMD.h
Normal file
144
lib/MySensors/hal/architecture/SAMD/MyHwSAMD.h
Normal file
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
#ifndef MyHwSAMD_h
|
||||
#define MyHwSAMD_h
|
||||
|
||||
#include <SPI.h>
|
||||
#include <avr/dtostrf.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#include <Arduino.h>
|
||||
#endif
|
||||
|
||||
#define CRYPTO_LITTLE_ENDIAN
|
||||
|
||||
#ifndef MY_SERIALDEVICE
|
||||
#define MY_SERIALDEVICE SerialUSB
|
||||
#endif
|
||||
|
||||
#ifndef MY_DEBUGDEVICE
|
||||
#define MY_DEBUGDEVICE MY_SERIALDEVICE
|
||||
#endif
|
||||
|
||||
#ifndef MY_SAMD_TEMPERATURE_OFFSET
|
||||
#define MY_SAMD_TEMPERATURE_OFFSET (0.0f)
|
||||
#endif
|
||||
|
||||
#ifndef MY_SAMD_TEMPERATURE_GAIN
|
||||
#define MY_SAMD_TEMPERATURE_GAIN (1.0f)
|
||||
#endif
|
||||
|
||||
// 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)
|
||||
|
||||
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 MY_EXT_EEPROM_TWI_CLOCK (eep.twiClock100kHz) // can be set to 400kHz with precaution if other i2c devices on bus
|
||||
|
||||
#define snprintf_P(s, f, ...) snprintf((s), (f), __VA_ARGS__)
|
||||
#define vsnprintf_P(s, n, f, ...) vsnprintf((s), (n), (f), __VA_ARGS__)
|
||||
|
||||
// redefine 8 bit types of inttypes.h (as of SAMD board defs 1.8.1)
|
||||
#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 "d"
|
||||
#define PRIi8 "i"
|
||||
#define PRIo8 "o"
|
||||
#define PRIu8 "u"
|
||||
#define PRIx8 "x"
|
||||
#define PRIX8 "X"
|
||||
#define PRIdLEAST8 "d"
|
||||
#define PRIiLEAST8 "i"
|
||||
#define PRIoLEAST8 "o"
|
||||
#define PRIuLEAST8 "u"
|
||||
#define PRIxLEAST8 "x"
|
||||
#define PRIXLEAST8 "X"
|
||||
#define PRIdFAST8 "d"
|
||||
#define PRIiFAST8 "i"
|
||||
#define PRIoFAST8 "o"
|
||||
#define PRIuFAST8 "u"
|
||||
#define PRIxFAST8 "x"
|
||||
#define PRIXFAST8 "X"
|
||||
|
||||
// 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))
|
||||
#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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
#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
|
||||
43
lib/MySensors/hal/architecture/SAMD/MyMainSAMD.cpp
Normal file
43
lib/MySensors/hal/architecture/SAMD/MyMainSAMD.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
extern "C" void __libc_init_array(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
init();
|
||||
#if defined(USBCON)
|
||||
__libc_init_array();
|
||||
USBDevice.init();
|
||||
USBDevice.attach();
|
||||
#endif
|
||||
_begin(); // Startup MySensors library
|
||||
for(;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) {
|
||||
loop(); // Call sketch loop
|
||||
}
|
||||
if (serialEventRun) {
|
||||
serialEventRun();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
194
lib/MySensors/hal/architecture/STM32F1/MyHwSTM32F1.cpp
Normal file
194
lib/MySensors/hal/architecture/STM32F1/MyHwSTM32F1.cpp
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MyHwSTM32F1.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);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
#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(uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt1;
|
||||
(void)mode1;
|
||||
(void)interrupt2;
|
||||
(void)mode2;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
|
||||
void hwRandomNumberInit(void)
|
||||
{
|
||||
// use internal temperature sensor as noise source
|
||||
adc_reg_map *regs = ADC1->regs;
|
||||
regs->CR2 |= ADC_CR2_TSVREFE;
|
||||
regs->SMPR1 |= ADC_SMPR1_SMP16;
|
||||
|
||||
uint32_t seed = 0;
|
||||
uint16_t currentValue = 0;
|
||||
uint16_t newValue = 0;
|
||||
|
||||
for (uint8_t i = 0; i < 32; i++) {
|
||||
const uint32_t timeout = hwMillis() + 20;
|
||||
while (timeout >= hwMillis()) {
|
||||
newValue = adc_read(ADC1, 16);
|
||||
if (newValue != currentValue) {
|
||||
currentValue = newValue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
seed ^= ( (newValue + hwMillis()) & 7) << i;
|
||||
}
|
||||
randomSeed(seed);
|
||||
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
|
||||
}
|
||||
|
||||
bool hwUniqueID(unique_id_t *uniqueID)
|
||||
{
|
||||
(void)memcpy((uint8_t *)uniqueID, (uint32_t *)0x1FFFF7E0, 16); // FlashID + ChipID
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
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
|
||||
adc_calibrate(ADC1);
|
||||
|
||||
const uint16_t vdd = adc_read(ADC1, 17);
|
||||
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
|
||||
return (uint16_t)(1200u * 4096u / vdd);
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency(void)
|
||||
{
|
||||
return F_CPU/100000UL;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
adc_reg_map *regs = ADC1->regs;
|
||||
regs->CR2 |= ADC_CR2_TSVREFE; // enable VREFINT and Temperature sensor
|
||||
regs->SMPR1 |= ADC_SMPR1_SMP16 | ADC_SMPR1_SMP17;
|
||||
adc_calibrate(ADC1);
|
||||
|
||||
//const uint16_t adc_temp = adc_read(ADC1, 16);
|
||||
//const uint16_t vref = 1200 * 4096 / adc_read(ADC1, 17);
|
||||
// calibrated at 25°C, ADC output = 1430mV, avg slope = 4.3mV / °C, increasing temp ~ lower voltage
|
||||
const int8_t temp = static_cast<int8_t>((1430.0 - (adc_read(ADC1, 16) * 1200 / adc_read(ADC1,
|
||||
17))) / 4.3 + 25.0);
|
||||
regs->CR2 &= ~ADC_CR2_TSVREFE; // disable VREFINT and temp sensor
|
||||
return (temp - MY_STM32F1_TEMPERATURE_OFFSET) / MY_STM32F1_TEMPERATURE_GAIN;
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
//Not yet implemented
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
93
lib/MySensors/hal/architecture/STM32F1/MyHwSTM32F1.h
Normal file
93
lib/MySensors/hal/architecture/STM32F1/MyHwSTM32F1.h
Normal file
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MyHwSTM32F1_h
|
||||
#define MyHwSTM32F1_h
|
||||
|
||||
#include <libmaple/iwdg.h>
|
||||
#include <itoa.h>
|
||||
#include <EEPROM.h>
|
||||
#include <SPI.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
|
||||
|
||||
#ifndef MY_STM32F1_TEMPERATURE_OFFSET
|
||||
#define MY_STM32F1_TEMPERATURE_OFFSET (0.0f)
|
||||
#endif
|
||||
|
||||
#ifndef MY_STM32F1_TEMPERATURE_GAIN
|
||||
#define MY_STM32F1_TEMPERATURE_GAIN (1.0f)
|
||||
#endif
|
||||
|
||||
// SS default
|
||||
#ifndef SS
|
||||
#define SS PA4
|
||||
#endif
|
||||
|
||||
// mapping
|
||||
#define snprintf_P snprintf
|
||||
#define vsnprintf_P vsnprintf
|
||||
#define strncpy_P strncpy
|
||||
#define printf_P printf
|
||||
#define yield() // not defined
|
||||
|
||||
#ifndef digitalPinToInterrupt
|
||||
#define digitalPinToInterrupt(__pin) (__pin)
|
||||
#endif
|
||||
|
||||
#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()
|
||||
#define hwGetSleepRemaining() (0ul)
|
||||
|
||||
extern void serialEventRun(void) __attribute__((weak));
|
||||
bool hwInit(void);
|
||||
void hwRandomNumberInit(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);
|
||||
|
||||
// SOFTSPI
|
||||
#ifdef MY_SOFTSPI
|
||||
#error Soft SPI is not available on this architecture!
|
||||
#endif
|
||||
#define hwSPI SPI //!< hwSPI
|
||||
|
||||
|
||||
#ifndef DOXYGEN
|
||||
#define MY_CRITICAL_SECTION
|
||||
#endif /* DOXYGEN */
|
||||
|
||||
#endif
|
||||
41
lib/MySensors/hal/architecture/STM32F1/MyMainSTM32F1.cpp
Normal file
41
lib/MySensors/hal/architecture/STM32F1/MyMainSTM32F1.cpp
Normal file
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Initialize library and handle sketch functions like we want to
|
||||
int main(void)
|
||||
{
|
||||
_begin(); // Startup MySensors library
|
||||
for(;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) { // Call sketch loop
|
||||
loop();
|
||||
}
|
||||
if (serialEventRun) {
|
||||
serialEventRun();
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
174
lib/MySensors/hal/architecture/Teensy3/MyHwTeensy3.cpp
Normal file
174
lib/MySensors/hal/architecture/Teensy3/MyHwTeensy3.cpp
Normal file
@@ -0,0 +1,174 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "MyHwTeensy3.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();
|
||||
}
|
||||
*/
|
||||
|
||||
bool hwInit(void)
|
||||
{
|
||||
#if !defined(MY_DISABLED_SERIAL)
|
||||
MY_SERIALDEVICE.begin(MY_BAUD_RATE);
|
||||
#if defined(MY_GATEWAY_SERIAL)
|
||||
while (!MY_SERIALDEVICE) {}
|
||||
#endif
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
void hwWatchdogReset(void)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
}
|
||||
|
||||
void hwReboot(void)
|
||||
{
|
||||
SCB_AIRCR = 0x05FA0004;
|
||||
while (true);
|
||||
}
|
||||
|
||||
int8_t hwSleep(uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt, const uint8_t mode, uint32_t ms)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
(void)interrupt;
|
||||
(void)mode;
|
||||
(void)ms;
|
||||
return MY_SLEEP_NOT_POSSIBLE;
|
||||
}
|
||||
|
||||
int8_t hwSleep(const uint8_t interrupt1, const uint8_t mode1, const uint8_t interrupt2,
|
||||
const uint8_t mode2,
|
||||
uint32_t 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)
|
||||
{
|
||||
#if defined(__MKL26Z64__)
|
||||
(void)memcpy((uint8_t *)uniqueID, &SIM_UIDMH, 12);
|
||||
(void)memset((uint8_t *)uniqueID + 12, MY_HWID_PADDING_BYTE, 4);
|
||||
#else
|
||||
(void)memcpy((uint8_t *)uniqueID, &SIM_UIDH, 16);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t hwCPUVoltage(void)
|
||||
{
|
||||
analogReference(DEFAULT);
|
||||
analogReadResolution(12);
|
||||
analogReadAveraging(32);
|
||||
#if defined(__MK20DX128__) || defined(__MK20DX256__)
|
||||
// Teensy 3.0/3.1/3.2
|
||||
return (uint16_t)(1195u * 4096u / analogRead(39));
|
||||
#elif defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
// Teensy 3.6
|
||||
return (uint16_t)(1195u * 4096u / analogRead(71));
|
||||
#elif defined(__MKL26Z64__)
|
||||
// Teensy LC
|
||||
// not supported
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
#else
|
||||
// not supported
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t hwCPUFrequency(void)
|
||||
{
|
||||
// TODO: currently reporting compile time frequency (in 1/10MHz)
|
||||
return F_CPU / 100000UL;
|
||||
}
|
||||
|
||||
int8_t hwCPUTemperature(void)
|
||||
{
|
||||
return -127; // not implemented yet
|
||||
}
|
||||
|
||||
uint16_t hwFreeMem(void)
|
||||
{
|
||||
// TODO: Not supported!
|
||||
return FUNCTION_NOT_SUPPORTED;
|
||||
}
|
||||
|
||||
#if defined(MY_HW_HAS_GETENTROPY)
|
||||
ssize_t hwGetentropy(void *__buffer, const size_t __length)
|
||||
{
|
||||
SIM_SCGC6 |= SIM_SCGC6_RNGA; // enable RNG
|
||||
RNG_CR &= ~RNG_CR_SLP_MASK;
|
||||
RNG_CR |= RNG_CR_HA_MASK; //high assurance, not needed
|
||||
size_t pos = 0;
|
||||
while (pos < __length) {
|
||||
RNG_CR |= RNG_CR_GO_MASK;
|
||||
while (!(RNG_SR & RNG_SR_OREG_LVL(0xF)));
|
||||
const uint32_t rndVar = RNG_OR;
|
||||
const uint8_t bsize = (__length - pos) > sizeof(rndVar) ? sizeof(rndVar) : (__length - pos);
|
||||
(void)memcpy((uint8_t *)__buffer + pos, &rndVar, bsize);
|
||||
pos += bsize;
|
||||
}
|
||||
SIM_SCGC6 &= ~SIM_SCGC6_RNGA; // disable RNG
|
||||
return pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
void hwRandomNumberInit(void)
|
||||
{
|
||||
#if defined(MY_HW_HAS_GETENTROPY)
|
||||
// use HW RNG present on Teensy3.5/3.6
|
||||
// init RNG
|
||||
uint32_t seed = 0;
|
||||
hwGetentropy(&seed, sizeof(seed));
|
||||
randomSeed(seed);
|
||||
#else
|
||||
randomSeed(analogRead(MY_SIGNING_SOFT_RANDOMSEED_PIN));
|
||||
#endif
|
||||
}
|
||||
91
lib/MySensors/hal/architecture/Teensy3/MyHwTeensy3.h
Normal file
91
lib/MySensors/hal/architecture/Teensy3/MyHwTeensy3.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* Radio wiring Teensy3.x: RF24, RFM69, RFM95:
|
||||
* MISO 12
|
||||
* MOSI 11
|
||||
* SCK 13
|
||||
* CSN 10
|
||||
* CE 9 (RF24)
|
||||
* IRQ 8 (opt. RF24, RFM69, RFM95)
|
||||
*/
|
||||
|
||||
#ifndef MyHwTeensy3_h
|
||||
#define MyHwTeensy3_h
|
||||
|
||||
#include <SPI.h>
|
||||
#include "util/atomic.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
|
||||
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define RNG_CR_GO_MASK 0x1u
|
||||
#define RNG_CR_HA_MASK 0x2u
|
||||
#define RNG_CR_INTM_MASK 0x4u
|
||||
#define RNG_CR_CLRI_MASK 0x8u
|
||||
#define RNG_CR_SLP_MASK 0x10u
|
||||
#define RNG_SR_OREG_LVL_MASK 0xFF00u
|
||||
#define RNG_SR_OREG_LVL_SHIFT 8
|
||||
#define RNG_SR_OREG_LVL(x) (((uint32_t)(((uint32_t)(x))<<RNG_SR_OREG_LVL_SHIFT))&RNG_SR_OREG_LVL_MASK)
|
||||
#define SIM_SCGC6_RNGA ((uint32_t)0x00000200)
|
||||
#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) pinMode(__pin, __value)
|
||||
#define hwMillis() millis()
|
||||
#define hwGetSleepRemaining() (0ul)
|
||||
|
||||
void hwRandomNumberInit(void);
|
||||
bool hwInit(void);
|
||||
void hwWatchdogReset(void);
|
||||
void hwReboot(void);
|
||||
|
||||
// Teensy 3.x implements avr-libc EEPROM API
|
||||
#define hwReadConfig(__pos) eeprom_read_byte((const uint8_t *)__pos)
|
||||
#define hwWriteConfig(__pos, __val) eeprom_update_byte((uint8_t *)__pos, (uint8_t)__val)
|
||||
#define hwReadConfigBlock(__buf, __pos, __length) eeprom_read_block((void *)__buf, (const void *)__pos, (uint32_t)__length)
|
||||
#define hwWriteConfigBlock(__buf, __pos, __length) eeprom_update_block((const void *)__buf, (void *)__pos, (uint32_t)__length)
|
||||
|
||||
// SOFTSPI
|
||||
#ifdef MY_SOFTSPI
|
||||
#error Soft SPI is not available on this architecture!
|
||||
#endif
|
||||
#define hwSPI SPI //!< hwSPI
|
||||
|
||||
|
||||
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
|
||||
#define MY_HW_HAS_GETENTROPY
|
||||
#endif
|
||||
|
||||
#define MY_CRITICAL_SECTION ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
|
||||
|
||||
#endif
|
||||
31
lib/MySensors/hal/architecture/Teensy3/MyMainTeensy3.cpp
Normal file
31
lib/MySensors/hal/architecture/Teensy3/MyMainTeensy3.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
int main(void)
|
||||
{
|
||||
_begin(); // Startup MySensors library
|
||||
for(;;) {
|
||||
_process(); // Process incoming data
|
||||
if (loop) {
|
||||
loop(); // Call sketch loop
|
||||
}
|
||||
yield();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
57
lib/MySensors/hal/crypto/AVR/MyCryptoAVR.cpp
Normal file
57
lib/MySensors/hal/crypto/AVR/MyCryptoAVR.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "MyCryptoAVR.h"
|
||||
|
||||
// SHA256 implementation in ASM, see MyASM.S
|
||||
void SHA256(uint8_t *dest, const uint8_t *data, size_t dataLength)
|
||||
{
|
||||
sha256((sha256_hash_t *)dest, data, dataLength << 3); // data length in bits
|
||||
}
|
||||
|
||||
// SHA256HMAC
|
||||
void SHA256HMAC(uint8_t *dest, const uint8_t *key, size_t keyLength, const uint8_t *data,
|
||||
size_t dataLength)
|
||||
{
|
||||
hmac_sha256(dest, key, keyLength << 3, data, dataLength << 3);
|
||||
}
|
||||
|
||||
|
||||
// AES
|
||||
AES_ctx aes_ctx;
|
||||
|
||||
void AES128CBCInit(const uint8_t *key)
|
||||
{
|
||||
AES_init_ctx(&aes_ctx, key);
|
||||
}
|
||||
|
||||
void AES128CBCEncrypt(uint8_t *iv, uint8_t *buffer, const size_t dataLength)
|
||||
{
|
||||
AES_ctx_set_iv(&aes_ctx, iv);
|
||||
AES_CBC_encrypt_buffer(&aes_ctx, buffer, dataLength);
|
||||
}
|
||||
|
||||
void AES128CBCDecrypt(uint8_t *iv, uint8_t *buffer, const size_t dataLength)
|
||||
{
|
||||
AES_ctx_set_iv(&aes_ctx, iv);
|
||||
AES_CBC_decrypt_buffer(&aes_ctx, buffer, dataLength);
|
||||
}
|
||||
|
||||
|
||||
29
lib/MySensors/hal/crypto/AVR/MyCryptoAVR.h
Normal file
29
lib/MySensors/hal/crypto/AVR/MyCryptoAVR.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MyCryptoGeneric_h
|
||||
#define MyCryptoGeneric_h
|
||||
|
||||
#include "hal/crypto/MyCryptoHAL.h"
|
||||
#include "hal/crypto/AVR/drivers/AES/aes.cpp"
|
||||
#include "hal/crypto/AVR/drivers/SHA256/sha256.cpp"
|
||||
#include "hal/crypto/AVR/drivers/HMAC_SHA256/hmac_sha256.cpp"
|
||||
|
||||
#endif
|
||||
577
lib/MySensors/hal/crypto/AVR/drivers/AES/aes.cpp
Normal file
577
lib/MySensors/hal/crypto/AVR/drivers/AES/aes.cpp
Normal file
@@ -0,0 +1,577 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* AES implementation: https://github.com/kokke/tiny-AES-c
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode.
|
||||
Block size can be chosen in aes.h - available choices are AES128, AES192, AES256.
|
||||
|
||||
The implementation is verified against the test vectors in:
|
||||
National Institute of Standards and Technology Special Publication 800-38A 2001 ED
|
||||
|
||||
ECB-AES128
|
||||
----------
|
||||
|
||||
plain-text:
|
||||
6bc1bee22e409f96e93d7e117393172a
|
||||
ae2d8a571e03ac9c9eb76fac45af8e51
|
||||
30c81c46a35ce411e5fbc1191a0a52ef
|
||||
f69f2445df4f9b17ad2b417be66c3710
|
||||
|
||||
key:
|
||||
2b7e151628aed2a6abf7158809cf4f3c
|
||||
|
||||
resulting cipher
|
||||
3ad77bb40d7a3660a89ecaf32466ef97
|
||||
f5d3d58503b9699de785895a96fdbaaf
|
||||
43b1cd7f598ece23881b00e3ed030688
|
||||
7b0c785e27e8ad3f8223207104725dd4
|
||||
|
||||
|
||||
NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0)
|
||||
You should pad the end of the string with zeros if this is not the case.
|
||||
For AES192/256 the key size is proportionally larger.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Includes: */
|
||||
/*****************************************************************************/
|
||||
|
||||
#include "aes.h"
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Defines: */
|
||||
/*****************************************************************************/
|
||||
// The number of columns comprising a state in AES. This is a constant in AES. Value=4
|
||||
#define Nb 4
|
||||
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
#define Nk 8
|
||||
#define Nr 14
|
||||
#elif defined(AES192) && (AES192 == 1)
|
||||
#define Nk 6
|
||||
#define Nr 12
|
||||
#else
|
||||
#define Nk 4 // The number of 32 bit words in a key.
|
||||
#define Nr 10 // The number of rounds in AES Cipher.
|
||||
#endif
|
||||
|
||||
// jcallan@github points out that declaring Multiply as a function
|
||||
// reduces code size considerably with the Keil ARM compiler.
|
||||
// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3
|
||||
#ifndef MULTIPLY_AS_A_FUNCTION
|
||||
#define MULTIPLY_AS_A_FUNCTION 0
|
||||
#endif
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Private variables: */
|
||||
/*****************************************************************************/
|
||||
// state - array holding the intermediate results during decryption.
|
||||
typedef uint8_t state_t[4][4];
|
||||
|
||||
// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM
|
||||
// The numbers below can be computed dynamically trading ROM for RAM -
|
||||
// This can be useful in (embedded) bootloader applications, where ROM is often limited.
|
||||
static const uint8_t sbox[256] PROGMEM = {
|
||||
//0 1 2 3 4 5 6 7 8 9 A B C D E F
|
||||
0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
|
||||
0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
|
||||
0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
|
||||
0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
|
||||
0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
|
||||
0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
|
||||
0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
|
||||
0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
|
||||
0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
|
||||
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
|
||||
0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
|
||||
0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
|
||||
0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
|
||||
0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
|
||||
0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
|
||||
0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16
|
||||
};
|
||||
|
||||
static const uint8_t rsbox[256] PROGMEM = {
|
||||
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb,
|
||||
0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb,
|
||||
0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e,
|
||||
0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25,
|
||||
0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92,
|
||||
0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84,
|
||||
0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06,
|
||||
0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b,
|
||||
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73,
|
||||
0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e,
|
||||
0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b,
|
||||
0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4,
|
||||
0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f,
|
||||
0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef,
|
||||
0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61,
|
||||
0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
|
||||
};
|
||||
|
||||
// The round constant word array, Rcon[i], contains the values given by
|
||||
// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8)
|
||||
static const uint8_t Rcon[11] PROGMEM = {
|
||||
0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36
|
||||
};
|
||||
|
||||
/*
|
||||
* Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12),
|
||||
* that you can remove most of the elements in the Rcon array, because they are unused.
|
||||
*
|
||||
* From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon
|
||||
*
|
||||
* "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed),
|
||||
* up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm."
|
||||
*/
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Private functions: */
|
||||
/*****************************************************************************/
|
||||
/*
|
||||
static uint8_t getSBoxValue(uint8_t num)
|
||||
{
|
||||
return sbox[num];
|
||||
}
|
||||
*/
|
||||
#define getSBoxValue(num) pgm_read_byte(&sbox[(num)])
|
||||
/*
|
||||
static uint8_t getSBoxInvert(uint8_t num)
|
||||
{
|
||||
return rsbox[num];
|
||||
}
|
||||
*/
|
||||
#define getSBoxInvert(num) pgm_read_byte(&rsbox[(num)])
|
||||
|
||||
// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states.
|
||||
static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key)
|
||||
{
|
||||
unsigned i;
|
||||
uint8_t tempa[4]; // Used for the column/row operations
|
||||
|
||||
// The first round key is the key itself.
|
||||
for (i = 0; i < Nk; ++i) {
|
||||
RoundKey[(i * 4) + 0] = Key[(i * 4) + 0];
|
||||
RoundKey[(i * 4) + 1] = Key[(i * 4) + 1];
|
||||
RoundKey[(i * 4) + 2] = Key[(i * 4) + 2];
|
||||
RoundKey[(i * 4) + 3] = Key[(i * 4) + 3];
|
||||
}
|
||||
|
||||
// All other round keys are found from the previous round keys.
|
||||
for (i = Nk; i < Nb * (Nr + 1); ++i) {
|
||||
unsigned j, k;
|
||||
{
|
||||
k = (i - 1) * 4;
|
||||
tempa[0] = RoundKey[k + 0];
|
||||
tempa[1] = RoundKey[k + 1];
|
||||
tempa[2] = RoundKey[k + 2];
|
||||
tempa[3] = RoundKey[k + 3];
|
||||
}
|
||||
|
||||
if (i % Nk == 0) {
|
||||
// This function shifts the 4 bytes in a word to the left once.
|
||||
// [a0,a1,a2,a3] becomes [a1,a2,a3,a0]
|
||||
|
||||
// Function RotWord()
|
||||
{
|
||||
const uint8_t u8tmp = tempa[0];
|
||||
tempa[0] = tempa[1];
|
||||
tempa[1] = tempa[2];
|
||||
tempa[2] = tempa[3];
|
||||
tempa[3] = u8tmp;
|
||||
}
|
||||
|
||||
// SubWord() is a function that takes a four-byte input word and
|
||||
// applies the S-box to each of the four bytes to produce an output word.
|
||||
|
||||
// Function Subword()
|
||||
{
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
|
||||
tempa[0] = tempa[0] ^ pgm_read_byte(&Rcon[i / Nk]);
|
||||
}
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
if (i % Nk == 4) {
|
||||
// Function Subword()
|
||||
{
|
||||
tempa[0] = getSBoxValue(tempa[0]);
|
||||
tempa[1] = getSBoxValue(tempa[1]);
|
||||
tempa[2] = getSBoxValue(tempa[2]);
|
||||
tempa[3] = getSBoxValue(tempa[3]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
j = i * 4;
|
||||
k = (i - Nk) * 4;
|
||||
RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0];
|
||||
RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1];
|
||||
RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2];
|
||||
RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3];
|
||||
}
|
||||
}
|
||||
|
||||
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key)
|
||||
{
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
}
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv)
|
||||
{
|
||||
KeyExpansion(ctx->RoundKey, key);
|
||||
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv)
|
||||
{
|
||||
memcpy(ctx->Iv, iv, AES_BLOCKLEN);
|
||||
}
|
||||
#endif
|
||||
|
||||
// This function adds the round key to state.
|
||||
// The round key is added to the state by an XOR function.
|
||||
static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey)
|
||||
{
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
(*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
static void SubBytes(state_t* state)
|
||||
{
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
(*state)[j][i] = getSBoxValue((*state)[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The ShiftRows() function shifts the rows in the state to the left.
|
||||
// Each row is shifted with different offset.
|
||||
// Offset = Row number. So the first row is not shifted.
|
||||
static void ShiftRows(state_t* state)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
// Rotate first row 1 columns to left
|
||||
temp = (*state)[0][1];
|
||||
(*state)[0][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[3][1];
|
||||
(*state)[3][1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to left
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
||||
temp = (*state)[1][2];
|
||||
(*state)[1][2] = (*state)[3][2];
|
||||
(*state)[3][2] = temp;
|
||||
|
||||
// Rotate third row 3 columns to left
|
||||
temp = (*state)[0][3];
|
||||
(*state)[0][3] = (*state)[3][3];
|
||||
(*state)[3][3] = (*state)[2][3];
|
||||
(*state)[2][3] = (*state)[1][3];
|
||||
(*state)[1][3] = temp;
|
||||
}
|
||||
|
||||
static uint8_t xtime(uint8_t x)
|
||||
{
|
||||
return ((x << 1) ^ (((x >> 7) & 1) * 0x1b));
|
||||
}
|
||||
|
||||
// MixColumns function mixes the columns of the state matrix
|
||||
static void MixColumns(state_t* state)
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
uint8_t Tmp, Tm, t;
|
||||
t = (*state)[i][0];
|
||||
Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3];
|
||||
Tm = (*state)[i][0] ^ (*state)[i][1];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][0] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][1] ^ (*state)[i][2];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][1] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][2] ^ (*state)[i][3];
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][2] ^= Tm ^ Tmp;
|
||||
Tm = (*state)[i][3] ^ t;
|
||||
Tm = xtime(Tm);
|
||||
(*state)[i][3] ^= Tm ^ Tmp;
|
||||
}
|
||||
}
|
||||
|
||||
// Multiply is used to multiply numbers in the field GF(2^8)
|
||||
// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary
|
||||
// The compiler seems to be able to vectorize the operation better this way.
|
||||
// See https://github.com/kokke/tiny-AES-c/pull/34
|
||||
#if MULTIPLY_AS_A_FUNCTION
|
||||
static uint8_t Multiply(uint8_t x, uint8_t y)
|
||||
{
|
||||
return (((y & 1) * x) ^
|
||||
((y >> 1 & 1) * xtime(x)) ^
|
||||
((y >> 2 & 1) * xtime(xtime(x))) ^
|
||||
((y >> 3 & 1) * xtime(xtime(xtime(x)))) ^
|
||||
((y >> 4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */
|
||||
}
|
||||
#else
|
||||
#define Multiply(x, y) \
|
||||
( ((y & 1) * x) ^ \
|
||||
((y>>1 & 1) * xtime(x)) ^ \
|
||||
((y>>2 & 1) * xtime(xtime(x))) ^ \
|
||||
((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \
|
||||
((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \
|
||||
|
||||
#endif
|
||||
|
||||
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
// MixColumns function mixes the columns of the state matrix.
|
||||
// The method used to multiply may be difficult to understand for the inexperienced.
|
||||
// Please use the references to gain more information.
|
||||
static void InvMixColumns(state_t* state)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
uint8_t a, b, c, d;
|
||||
a = (*state)[i][0];
|
||||
b = (*state)[i][1];
|
||||
c = (*state)[i][2];
|
||||
d = (*state)[i][3];
|
||||
|
||||
(*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09);
|
||||
(*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d);
|
||||
(*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b);
|
||||
(*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// The SubBytes Function Substitutes the values in the
|
||||
// state matrix with values in an S-box.
|
||||
static void InvSubBytes(state_t* state)
|
||||
{
|
||||
uint8_t i, j;
|
||||
for (i = 0; i < 4; ++i) {
|
||||
for (j = 0; j < 4; ++j) {
|
||||
(*state)[j][i] = getSBoxInvert((*state)[j][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void InvShiftRows(state_t* state)
|
||||
{
|
||||
uint8_t temp;
|
||||
|
||||
// Rotate first row 1 columns to right
|
||||
temp = (*state)[3][1];
|
||||
(*state)[3][1] = (*state)[2][1];
|
||||
(*state)[2][1] = (*state)[1][1];
|
||||
(*state)[1][1] = (*state)[0][1];
|
||||
(*state)[0][1] = temp;
|
||||
|
||||
// Rotate second row 2 columns to right
|
||||
temp = (*state)[0][2];
|
||||
(*state)[0][2] = (*state)[2][2];
|
||||
(*state)[2][2] = temp;
|
||||
|
||||
temp = (*state)[1][2];
|
||||
(*state)[1][2] = (*state)[3][2];
|
||||
(*state)[3][2] = temp;
|
||||
|
||||
// Rotate third row 3 columns to right
|
||||
temp = (*state)[0][3];
|
||||
(*state)[0][3] = (*state)[1][3];
|
||||
(*state)[1][3] = (*state)[2][3];
|
||||
(*state)[2][3] = (*state)[3][3];
|
||||
(*state)[3][3] = temp;
|
||||
}
|
||||
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
|
||||
// Cipher is the main function that encrypts the PlainText.
|
||||
static void Cipher(state_t* state, const uint8_t* RoundKey)
|
||||
{
|
||||
uint8_t round = 0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(0, state, RoundKey);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr-1 rounds are executed in the loop below.
|
||||
for (round = 1; round < Nr; ++round) {
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
MixColumns(state);
|
||||
AddRoundKey(round, state, RoundKey);
|
||||
}
|
||||
|
||||
// The last round is given below.
|
||||
// The MixColumns function is not here in the last round.
|
||||
SubBytes(state);
|
||||
ShiftRows(state);
|
||||
AddRoundKey(Nr, state, RoundKey);
|
||||
}
|
||||
|
||||
#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
static void InvCipher(state_t* state, const uint8_t* RoundKey)
|
||||
{
|
||||
uint8_t round = 0;
|
||||
|
||||
// Add the First round key to the state before starting the rounds.
|
||||
AddRoundKey(Nr, state, RoundKey);
|
||||
|
||||
// There will be Nr rounds.
|
||||
// The first Nr-1 rounds are identical.
|
||||
// These Nr-1 rounds are executed in the loop below.
|
||||
for (round = (Nr - 1); round > 0; --round) {
|
||||
InvShiftRows(state);
|
||||
InvSubBytes(state);
|
||||
AddRoundKey(round, state, RoundKey);
|
||||
InvMixColumns(state);
|
||||
}
|
||||
|
||||
// The last round is given below.
|
||||
// The MixColumns function is not here in the last round.
|
||||
InvShiftRows(state);
|
||||
InvSubBytes(state);
|
||||
AddRoundKey(0, state, RoundKey);
|
||||
}
|
||||
#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1)
|
||||
|
||||
/*****************************************************************************/
|
||||
/* Public functions: */
|
||||
/*****************************************************************************/
|
||||
#if defined(ECB) && (ECB == 1)
|
||||
|
||||
|
||||
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||
{
|
||||
// The next function call encrypts the PlainText with the Key using AES algorithm.
|
||||
Cipher((state_t*)buf, ctx->RoundKey);
|
||||
}
|
||||
|
||||
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf)
|
||||
{
|
||||
// The next function call decrypts the PlainText with the Key using AES algorithm.
|
||||
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||
}
|
||||
|
||||
|
||||
#endif // #if defined(ECB) && (ECB == 1)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(CBC) && (CBC == 1)
|
||||
|
||||
|
||||
static void XorWithIv(uint8_t* buf, const uint8_t* Iv)
|
||||
{
|
||||
uint8_t i;
|
||||
for (i = 0; i < AES_BLOCKLEN; ++i) { // The block in AES is always 128bit no matter the key size
|
||||
buf[i] ^= Iv[i];
|
||||
}
|
||||
}
|
||||
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length)
|
||||
{
|
||||
uintptr_t i;
|
||||
uint8_t *Iv = ctx->Iv;
|
||||
for (i = 0; i < length; i += AES_BLOCKLEN) {
|
||||
XorWithIv(buf, Iv);
|
||||
Cipher((state_t*)buf, ctx->RoundKey);
|
||||
Iv = buf;
|
||||
buf += AES_BLOCKLEN;
|
||||
//printf("Step %d - %d", i/16, i);
|
||||
}
|
||||
/* store Iv in ctx for next call */
|
||||
memcpy(ctx->Iv, Iv, AES_BLOCKLEN);
|
||||
}
|
||||
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||
{
|
||||
uintptr_t i;
|
||||
uint8_t storeNextIv[AES_BLOCKLEN];
|
||||
for (i = 0; i < length; i += AES_BLOCKLEN) {
|
||||
memcpy(storeNextIv, buf, AES_BLOCKLEN);
|
||||
InvCipher((state_t*)buf, ctx->RoundKey);
|
||||
XorWithIv(buf, ctx->Iv);
|
||||
memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN);
|
||||
buf += AES_BLOCKLEN;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // #if defined(CBC) && (CBC == 1)
|
||||
|
||||
|
||||
|
||||
#if defined(CTR) && (CTR == 1)
|
||||
|
||||
/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */
|
||||
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length)
|
||||
{
|
||||
uint8_t buffer[AES_BLOCKLEN];
|
||||
|
||||
unsigned i;
|
||||
int bi;
|
||||
for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) {
|
||||
if (bi == AES_BLOCKLEN) { /* we need to regen xor compliment in buffer */
|
||||
|
||||
memcpy(buffer, ctx->Iv, AES_BLOCKLEN);
|
||||
Cipher((state_t*)buffer, ctx->RoundKey);
|
||||
|
||||
/* Increment Iv and handle overflow */
|
||||
for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) {
|
||||
/* inc will overflow */
|
||||
if (ctx->Iv[bi] == 255) {
|
||||
ctx->Iv[bi] = 0;
|
||||
continue;
|
||||
}
|
||||
ctx->Iv[bi] += 1;
|
||||
break;
|
||||
}
|
||||
bi = 0;
|
||||
}
|
||||
|
||||
buf[i] = (buf[i] ^ buffer[bi]);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // #if defined(CTR) && (CTR == 1)
|
||||
111
lib/MySensors/hal/crypto/AVR/drivers/AES/aes.h
Normal file
111
lib/MySensors/hal/crypto/AVR/drivers/AES/aes.h
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* AES implementation: https://github.com/kokke/tiny-AES-c
|
||||
*/
|
||||
|
||||
#ifndef _AES_H_
|
||||
#define _AES_H_
|
||||
|
||||
// #define the macros below to 1/0 to enable/disable the mode of operation.
|
||||
//
|
||||
// CBC enables AES encryption in CBC-mode of operation.
|
||||
// CTR enables encryption in counter-mode.
|
||||
// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously.
|
||||
|
||||
// The #ifndef-guard allows it to be configured before #include'ing or at compile time.
|
||||
#ifndef CBC
|
||||
#define CBC 1
|
||||
#endif
|
||||
|
||||
#ifndef ECB
|
||||
#define ECB 0
|
||||
#endif
|
||||
|
||||
#ifndef CTR
|
||||
#define CTR 0
|
||||
#endif
|
||||
|
||||
|
||||
#define AES128 1
|
||||
//#define AES192 1
|
||||
//#define AES256 1
|
||||
|
||||
#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only
|
||||
|
||||
#if defined(AES256) && (AES256 == 1)
|
||||
#define AES_KEYLEN 32
|
||||
#define AES_keyExpSize 240
|
||||
#elif defined(AES192) && (AES192 == 1)
|
||||
#define AES_KEYLEN 24
|
||||
#define AES_keyExpSize 208
|
||||
#else
|
||||
#define AES_KEYLEN 16 // Key length in bytes
|
||||
#define AES_keyExpSize 176
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief AES state structure
|
||||
*/
|
||||
struct AES_ctx {
|
||||
uint8_t RoundKey[AES_keyExpSize]; //!< RoundKey
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
uint8_t Iv[AES_BLOCKLEN]; //!< Iv
|
||||
#endif
|
||||
};
|
||||
|
||||
void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key);
|
||||
#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1))
|
||||
void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv);
|
||||
void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv);
|
||||
#endif
|
||||
|
||||
#if defined(ECB) && (ECB == 1)
|
||||
// buffer size is exactly AES_BLOCKLEN bytes;
|
||||
// you need only AES_init_ctx as IV is not used in ECB
|
||||
// NB: ECB is considered insecure for most uses
|
||||
void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||
void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf);
|
||||
|
||||
#endif // #if defined(ECB) && (ECB == !)
|
||||
|
||||
|
||||
#if defined(CBC) && (CBC == 1)
|
||||
// buffer size MUST be mutile of AES_BLOCKLEN;
|
||||
// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||
void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||
|
||||
#endif // #if defined(CBC) && (CBC == 1)
|
||||
|
||||
|
||||
#if defined(CTR) && (CTR == 1)
|
||||
|
||||
// Same function for encrypting as for decrypting.
|
||||
// IV is incremented for every block, and used after encryption as XOR-compliment for output
|
||||
// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme
|
||||
// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv()
|
||||
// no IV should ever be reused with the same key
|
||||
void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length);
|
||||
|
||||
#endif // #if defined(CTR) && (CTR == 1)
|
||||
|
||||
|
||||
#endif //_AES_H_
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hmac_sha256.h"
|
||||
|
||||
/*
|
||||
* all lengths in bits!
|
||||
*/
|
||||
void hmac_sha256(void *dest, const void *key, uint16_t keylength_b, const void *msg,
|
||||
uint32_t msglength_b)
|
||||
{
|
||||
sha256_ctx_t s;
|
||||
uint8_t buffer[HMAC_SHA256_BLOCK_BYTES];
|
||||
|
||||
(void)memset((void *)buffer, 0x00, HMAC_SHA256_BLOCK_BYTES);
|
||||
|
||||
/* if key is larger than a block we have to hash it*/
|
||||
if (keylength_b > SHA256_BLOCK_BITS) {
|
||||
sha256((sha256_hash_t *)buffer, key, keylength_b);
|
||||
} else {
|
||||
(void)memcpy((void *)buffer, (const void *)key, (keylength_b + 7) / 8);
|
||||
}
|
||||
|
||||
for (uint8_t i = 0; i < SHA256_BLOCK_BYTES; ++i) {
|
||||
buffer[i] ^= IPAD;
|
||||
}
|
||||
sha256_init(&s);
|
||||
sha256_nextBlock(&s, buffer);
|
||||
while (msglength_b >= HMAC_SHA256_BLOCK_BITS) {
|
||||
sha256_nextBlock(&s, msg);
|
||||
msg = (uint8_t *)msg + HMAC_SHA256_BLOCK_BYTES;
|
||||
msglength_b -= HMAC_SHA256_BLOCK_BITS;
|
||||
}
|
||||
sha256_lastBlock(&s, msg, msglength_b);
|
||||
/* since buffer still contains key xor ipad we can do ... */
|
||||
for (uint8_t i = 0; i < HMAC_SHA256_BLOCK_BYTES; ++i) {
|
||||
buffer[i] ^= IPAD ^ OPAD;
|
||||
}
|
||||
sha256_ctx2hash((sha256_hash_t *)dest, &s); /* save inner hash temporary to dest */
|
||||
sha256_init(&s);
|
||||
sha256_nextBlock(&s, buffer);
|
||||
sha256_lastBlock(&s, dest, SHA256_HASH_BITS);
|
||||
sha256_ctx2hash((sha256_hash_t *)dest, &s);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* 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.
|
||||
*
|
||||
* ======================================================================
|
||||
*
|
||||
* HMAC SHA256 implementation for AVR:
|
||||
*
|
||||
* This file is part of the AVR-Crypto-Lib.
|
||||
* Copyright (C) 2006-2015 Daniel Otte (bg@nerilex.org)
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Author: Daniel Otte
|
||||
*
|
||||
* License: GPLv3 or later
|
||||
*
|
||||
* ======================================================================
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _HMAC_SHA256_
|
||||
#define _HMAC_SHA256_
|
||||
|
||||
#define IPAD 0x36 //!< HMAC, inner hash, xor byte
|
||||
#define OPAD 0x5C //!< HMAC, outer hash, xor byte
|
||||
|
||||
#define HMAC_SHA256_BITS SHA256_HASH_BITS //!< Defines the size of a SHA-256 HMAC hash value in bits
|
||||
#define HMAC_SHA256_BYTES SHA256_HASH_BYTES //!< Defines the size of a SHA-256 HMAC hash value in bytes
|
||||
#define HMAC_SHA256_BLOCK_BITS SHA256_BLOCK_BITS //!< Defines the size of a SHA-256 HMAC input block in bits
|
||||
#define HMAC_SHA256_BLOCK_BYTES SHA256_BLOCK_BYTES //!< Defines the size of a SHA-256 HMAC input block in bytes
|
||||
|
||||
/**
|
||||
* @brief hash context structure
|
||||
*/
|
||||
typedef struct {
|
||||
sha256_ctx_t a; //!< a
|
||||
sha256_ctx_t b; //!< b
|
||||
} hmac_sha256_ctx_t;
|
||||
|
||||
/**
|
||||
* @brief SHA256 HMAC function
|
||||
*
|
||||
* @param dest pointer to the location where the hash value is going to be written to
|
||||
* @param key pointer to the key that's is needed for the HMAC calculation
|
||||
* @param keylength_b length of the key
|
||||
* @param msg pointer to the message that's going to be hashed
|
||||
* @param msglength_b length of the message
|
||||
*/
|
||||
void hmac_sha256(void *dest, const void *key, uint16_t keylength_b, const void *msg,
|
||||
uint32_t msglength_b);
|
||||
|
||||
#endif
|
||||
1038
lib/MySensors/hal/crypto/AVR/drivers/SHA256/SHA256.S
Normal file
1038
lib/MySensors/hal/crypto/AVR/drivers/SHA256/SHA256.S
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user