mirror of
https://github.com/IoTManagerProject/IoTManager.git
synced 2026-03-30 11:59:12 +03:00
gatewayTransportSend
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;
|
||||
}
|
||||
Reference in New Issue
Block a user