Refactor RaspberryPi port
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
#ifndef Arduino_h
|
||||
#define Arduino_h
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef LSBFIRST
|
||||
#define LSBFIRST 0
|
||||
#endif
|
||||
|
||||
#ifndef MSBFIRST
|
||||
#define MSBFIRST 1
|
||||
#endif
|
||||
|
||||
#define abs(x) ((x)>0?(x):-(x))
|
||||
#define constrain(amt,low,high) ((amt)<(low)?(low):((amt)>(high)?(high):(amt)))
|
||||
#define round(x) ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))
|
||||
#define radians(deg) ((deg)*DEG_TO_RAD)
|
||||
#define degrees(rad) ((rad)*RAD_TO_DEG)
|
||||
#define sq(x) ((x)*(x))
|
||||
|
||||
#define lowByte(w) ((uint8_t) ((w) & 0xff))
|
||||
#define highByte(w) ((uint8_t) ((w) >> 8))
|
||||
|
||||
#define bit(b) (1UL << (b))
|
||||
|
||||
typedef bool boolean;
|
||||
typedef uint8_t byte;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* C++ version 0.4 char* style "itoa":
|
||||
* Written by Lukás Chmela
|
||||
* Released under GPLv3.
|
||||
*/
|
||||
char *itoa(int value, char* result, int base) {
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
int tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
// Apply negative sign
|
||||
if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* C++ version 0.4 char* style "itoa":
|
||||
* Written by Lukás Chmela
|
||||
* Released under GPLv3.
|
||||
*/
|
||||
char *ltoa(long value, char* result, int base) {
|
||||
// check that the base if valid
|
||||
if (base < 2 || base > 36) { *result = '\0'; return result; }
|
||||
|
||||
char* ptr = result, *ptr1 = result, tmp_char;
|
||||
long tmp_value;
|
||||
|
||||
do {
|
||||
tmp_value = value;
|
||||
value /= base;
|
||||
*ptr++ = "zyxwvutsrqponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
|
||||
} while ( value );
|
||||
|
||||
// Apply negative sign
|
||||
if (tmp_value < 0) *ptr++ = '-';
|
||||
*ptr-- = '\0';
|
||||
while(ptr1 < ptr) {
|
||||
tmp_char = *ptr;
|
||||
*ptr--= *ptr1;
|
||||
*ptr1++ = tmp_char;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *ultoa(long num, char *str, int radix)
|
||||
{
|
||||
unsigned long value;
|
||||
char *sp = str;
|
||||
char *sp2;
|
||||
|
||||
value = num;
|
||||
|
||||
/* Store sign at start of buffer for negative base-10 values */
|
||||
if (10 == radix && 0 > num) {
|
||||
*sp++ = '-';
|
||||
value = -num;
|
||||
}
|
||||
|
||||
sp2 = sp;
|
||||
|
||||
do {
|
||||
char rem = value % radix;
|
||||
value /= radix;
|
||||
if (10 > rem) {
|
||||
*sp++ = '0' + rem;
|
||||
} else {
|
||||
*sp++ = 'A' + rem - 10;
|
||||
}
|
||||
} while (0 < value);
|
||||
|
||||
/* Mark end of string */
|
||||
*sp-- = 0;
|
||||
|
||||
/* Reverse string contents (excluding sign) in place */
|
||||
while (sp2 < sp) {
|
||||
char tmp = *sp2;
|
||||
*sp2++ = *sp;
|
||||
*sp-- = tmp;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copyright (c) 2012, Peter A. Bigot <bigotp@acm.org>
|
||||
*
|
||||
* 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 software 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.
|
||||
*/
|
||||
|
||||
char *utoa(int num, char *str, int radix)
|
||||
{
|
||||
unsigned int value;
|
||||
char *sp = str;
|
||||
char *sp2;
|
||||
|
||||
value = num;
|
||||
|
||||
/* Store sign at start of buffer for negative base-10 values */
|
||||
if (10 == radix && 0 > num) {
|
||||
*sp++ = '-';
|
||||
value = -num;
|
||||
}
|
||||
|
||||
sp2 = sp;
|
||||
|
||||
do {
|
||||
char rem = value % radix;
|
||||
value /= radix;
|
||||
if (10 > rem) {
|
||||
*sp++ = '0' + rem;
|
||||
} else {
|
||||
*sp++ = 'A' + rem - 10;
|
||||
}
|
||||
} while (0 < value);
|
||||
|
||||
/* Mark end of string */
|
||||
*sp-- = 0;
|
||||
|
||||
/* Reverse string contents (excluding sign) in place */
|
||||
while (sp2 < sp) {
|
||||
char tmp = *sp2;
|
||||
*sp2++ = *sp;
|
||||
*sp-- = tmp;
|
||||
}
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
char *dtostrf(float f, int width, int decimals, char *result)
|
||||
{
|
||||
sprintf(result,"%*.*f", width, decimals, f);
|
||||
return result;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
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"
|
||||
|
||||
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
|
||||
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* 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 <sys/socket.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <sys/time.h>
|
||||
#include <netinet/tcp.h>
|
||||
#include "EthernetClient.h"
|
||||
|
||||
EthernetClient::EthernetClient() : _sock(-1) {
|
||||
}
|
||||
|
||||
EthernetClient::EthernetClient(int sock) : _sock(sock) {
|
||||
}
|
||||
|
||||
int EthernetClient::connect(const char* host, uint16_t port) {
|
||||
int sockfd;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
int rv;
|
||||
char s[INET6_ADDRSTRLEN];
|
||||
char port_str[6];
|
||||
|
||||
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) {
|
||||
fprintf(stderr, "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 ((sockfd = socket(p->ai_family, p->ai_socktype,
|
||||
p->ai_protocol)) == -1) {
|
||||
perror("socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (::connect(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close(sockfd);
|
||||
perror("connect");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "failed to connect\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
_sock = sockfd;
|
||||
|
||||
void *addr = &(((struct sockaddr_in*)p->ai_addr)->sin_addr);
|
||||
inet_ntop(p->ai_family, addr, s, sizeof s);
|
||||
ETHERNETCLIENT_DEBUG("connected to %s\n", s);
|
||||
|
||||
freeaddrinfo(servinfo); // 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 rc = 0;
|
||||
int bytes = 0;
|
||||
|
||||
if (_sock == -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (size > 0) {
|
||||
rc = send(_sock, buf + bytes, size, MSG_NOSIGNAL | MSG_DONTWAIT);
|
||||
if (rc == -1) {
|
||||
perror("send");
|
||||
close(_sock);
|
||||
_sock = -1;
|
||||
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, FIONREAD, &count);
|
||||
return count;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EthernetClient::read() {
|
||||
uint8_t b;
|
||||
if ( recv(_sock, &b, 1, 0) > 0 )
|
||||
{
|
||||
// recv worked
|
||||
return b;
|
||||
} else {
|
||||
// No data available
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int EthernetClient::read(uint8_t *buf, size_t size) {
|
||||
return recv(_sock, buf, size, 0);
|
||||
}
|
||||
|
||||
int EthernetClient::peek() {
|
||||
uint8_t b;
|
||||
|
||||
return recv(_sock, &b, 1, MSG_PEEK | MSG_DONTWAIT);
|
||||
}
|
||||
|
||||
void EthernetClient::flush() {
|
||||
// There isn't much we can do here
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
uint8_t s;
|
||||
do {
|
||||
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);
|
||||
|
||||
// if it hasn't closed, close it forcefully
|
||||
if (s != ETHERNETCLIENT_W5100_CLOSED)
|
||||
close(_sock);
|
||||
|
||||
_sock = -1;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::connected() {
|
||||
if (_sock == -1) return 0;
|
||||
|
||||
if (peek() < 0) {
|
||||
if (errno == EAGAIN) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return 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;
|
||||
}
|
||||
} else {
|
||||
perror("getsockopt");
|
||||
}
|
||||
|
||||
return ETHERNETCLIENT_W5100_CLOSED;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
uint8_t EthernetClient::getSocketNumber() {
|
||||
return _sock;
|
||||
}
|
||||
@@ -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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* 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
|
||||
|
||||
// debug
|
||||
#if defined(ETHERNETCLIENT_VERBOSE)
|
||||
#define ETHERNETCLIENT_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ETHERNETCLIENT_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
class EthernetClient : public Client {
|
||||
|
||||
public:
|
||||
EthernetClient();
|
||||
EthernetClient(int sock);
|
||||
|
||||
uint8_t status();
|
||||
virtual int connect(IPAddress ip, uint16_t port);
|
||||
virtual int connect(const char *host, uint16_t port);
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *buf, size_t size);
|
||||
size_t write(const char *str);
|
||||
size_t write(const char *buffer, size_t size);
|
||||
virtual int available();
|
||||
virtual int read();
|
||||
virtual int read(uint8_t *buf, size_t size);
|
||||
virtual int peek();
|
||||
virtual void flush();
|
||||
virtual void stop();
|
||||
virtual uint8_t connected();
|
||||
virtual operator bool();
|
||||
virtual bool operator==(const bool value) { return bool() == value; }
|
||||
virtual bool operator!=(const bool value) { return bool() != value; }
|
||||
virtual bool operator==(const EthernetClient&);
|
||||
virtual bool operator!=(const EthernetClient& rhs) { return !this->operator==(rhs); };
|
||||
uint8_t getSocketNumber();
|
||||
|
||||
friend class EthernetServer;
|
||||
|
||||
private:
|
||||
int _sock;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* 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 <sys/socket.h>
|
||||
#include <cstring>
|
||||
#include <sys/socket.h>
|
||||
#include <pthread.h>
|
||||
#include <netdb.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#include "EthernetServer.h"
|
||||
|
||||
struct server_vars {
|
||||
uint16_t port;
|
||||
struct IPAddress address;
|
||||
std::list<int> *new_clients;
|
||||
std::vector<int> *clients;
|
||||
};
|
||||
|
||||
static pthread_mutex_t new_clients_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
static pthread_mutex_t clients_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
void *incoming_connections(void *);
|
||||
|
||||
EthernetServer::EthernetServer(uint16_t port) : port(port)
|
||||
{
|
||||
clients.reserve(MY_GATEWAY_MAX_CLIENTS);
|
||||
}
|
||||
|
||||
void EthernetServer::begin()
|
||||
{
|
||||
begin(IPAddress(0,0,0,0));
|
||||
}
|
||||
|
||||
void EthernetServer::begin(IPAddress address)
|
||||
{
|
||||
pthread_t thread_id;
|
||||
pthread_attr_t detached_attr;
|
||||
|
||||
struct server_vars *vars = new struct server_vars;
|
||||
vars->port = port;
|
||||
vars->address = address;
|
||||
vars->new_clients = &new_clients;
|
||||
vars->clients = &clients;
|
||||
|
||||
pthread_attr_init(&detached_attr);
|
||||
pthread_attr_setdetachstate(&detached_attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_create(&thread_id, &detached_attr, &incoming_connections, vars);
|
||||
}
|
||||
|
||||
void EthernetServer::beginPacket(IPAddress address, uint16_t port)
|
||||
{
|
||||
//TODO: UDP
|
||||
(void)address;
|
||||
(void)port;
|
||||
}
|
||||
|
||||
int EthernetServer::parsePacket()
|
||||
{
|
||||
//TODO: UDP
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool EthernetServer::hasClient()
|
||||
{
|
||||
bool empty;
|
||||
|
||||
pthread_mutex_lock(&new_clients_mutex);
|
||||
empty = new_clients.empty();
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
|
||||
return !empty;
|
||||
}
|
||||
|
||||
EthernetClient EthernetServer::available()
|
||||
{
|
||||
int sock;
|
||||
|
||||
pthread_mutex_lock(&new_clients_mutex);
|
||||
if (new_clients.empty()) {
|
||||
sock = -1;
|
||||
} else {
|
||||
sock = new_clients.front();
|
||||
new_clients.pop_front();
|
||||
}
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
|
||||
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;
|
||||
size_t i = 0;
|
||||
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
while (i < clients.size()) {
|
||||
EthernetClient client(clients[i]);
|
||||
if (client.connected()) {
|
||||
n += client.write(buffer, size);
|
||||
i++;
|
||||
} else {
|
||||
clients[i] = clients.back();
|
||||
clients.pop_back();
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
|
||||
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 *incoming_connections(void* thread_arg)
|
||||
{
|
||||
struct server_vars *vars = (struct server_vars*) thread_arg;
|
||||
int sockfd, new_fd;
|
||||
struct addrinfo hints, *servinfo, *p;
|
||||
struct sockaddr_storage client_addr;
|
||||
socklen_t sin_size;
|
||||
int yes=1;
|
||||
int rv;
|
||||
char ipstr[INET_ADDRSTRLEN];
|
||||
char portstr[6];
|
||||
|
||||
memset(&hints, 0, sizeof hints);
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE;
|
||||
|
||||
sprintf(portstr, "%d", vars->port);
|
||||
if ((rv = getaddrinfo(vars->address.toString().c_str(), portstr, &hints, &servinfo)) != 0) {
|
||||
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 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) {
|
||||
perror("socket");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1) {
|
||||
perror("setsockopt");
|
||||
freeaddrinfo(servinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bind(sockfd, p->ai_addr, p->ai_addrlen) == -1) {
|
||||
close(sockfd);
|
||||
perror("bind");
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (p == NULL) {
|
||||
fprintf(stderr, "failed to bind\n");
|
||||
freeaddrinfo(servinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (listen(sockfd, ETHERNETSERVER_BACKLOG) == -1) {
|
||||
perror("listen");
|
||||
freeaddrinfo(servinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
freeaddrinfo(servinfo);
|
||||
|
||||
struct sockaddr_in *ipv4 = (struct sockaddr_in *)p->ai_addr;
|
||||
void *addr = &(ipv4->sin_addr);
|
||||
inet_ntop(p->ai_family, addr, ipstr, sizeof ipstr);
|
||||
ETHERNETSERVER_DEBUG("Listening for connections on %s:%s\n", ipstr, portstr);
|
||||
|
||||
while (1) { // accept() loop
|
||||
sin_size = sizeof client_addr;
|
||||
new_fd = accept(sockfd, (struct sockaddr *)&client_addr, &sin_size);
|
||||
if (new_fd == -1) {
|
||||
perror("accept");
|
||||
continue;
|
||||
}
|
||||
|
||||
void *addr = &(((struct sockaddr_in*)&client_addr)->sin_addr);
|
||||
inet_ntop(client_addr.ss_family, addr, ipstr, sizeof ipstr);
|
||||
ETHERNETSERVER_DEBUG("New connection from %s\n", ipstr);
|
||||
|
||||
pthread_mutex_lock(&new_clients_mutex);
|
||||
pthread_mutex_lock(&clients_mutex);
|
||||
int connected_clients = vars->new_clients->size() + vars->clients->size();
|
||||
|
||||
if (connected_clients == MY_GATEWAY_MAX_CLIENTS) {
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
ETHERNETSERVER_DEBUG("Max number of ethernet clients reached.");
|
||||
close(new_fd);
|
||||
usleep(5000000);
|
||||
} else {
|
||||
vars->new_clients->push_back(new_fd);
|
||||
vars->clients->push_back(new_fd);
|
||||
pthread_mutex_unlock(&clients_mutex);
|
||||
pthread_mutex_unlock(&new_clients_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
delete vars;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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 Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* 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 "EthernetClient.h"
|
||||
|
||||
#ifndef ETHERNETSERVER_BACKLOG
|
||||
#define ETHERNETSERVER_BACKLOG 10
|
||||
#endif
|
||||
|
||||
// debug
|
||||
#if defined(ETHERNETSERVER_VERBOSE)
|
||||
#define ETHERNETSERVER_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define ETHERNETSERVER_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
class EthernetClient;
|
||||
|
||||
class EthernetServer : public Server {
|
||||
|
||||
private:
|
||||
uint16_t port;
|
||||
std::list<int> new_clients;
|
||||
std::vector<int> clients;
|
||||
|
||||
public:
|
||||
EthernetServer(uint16_t);
|
||||
virtual void begin();
|
||||
void begin(IPAddress);
|
||||
void beginPacket(IPAddress, uint16_t);
|
||||
int parsePacket();
|
||||
bool hasClient();
|
||||
EthernetClient available();
|
||||
virtual size_t write(uint8_t);
|
||||
virtual size_t write(const uint8_t *, size_t);
|
||||
size_t write(const char *str);
|
||||
size_t write(const char *buffer, size_t size);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
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 <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);
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
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>
|
||||
|
||||
// A class to make it easier to handle and pass around IP addresses
|
||||
|
||||
// class IPAddress: public Printable {
|
||||
class IPAddress {
|
||||
private:
|
||||
union {
|
||||
uint8_t bytes[4]; // IPv4 address
|
||||
uint32_t dword;
|
||||
} _address;
|
||||
|
||||
// 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.
|
||||
uint8_t* raw_address() {
|
||||
return _address.bytes;
|
||||
}
|
||||
|
||||
public:
|
||||
// Constructors
|
||||
IPAddress();
|
||||
IPAddress(uint8_t first_octet, uint8_t second_octet, uint8_t third_octet, uint8_t fourth_octet);
|
||||
IPAddress(uint32_t address);
|
||||
IPAddress(const uint8_t *address);
|
||||
|
||||
bool fromString(const char *address);
|
||||
bool fromString(const std::string &address) { return fromString(address.c_str()); }
|
||||
|
||||
// Overloaded cast operator to 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;
|
||||
}
|
||||
bool operator==(const IPAddress& addr) const {
|
||||
return _address.dword == addr._address.dword;
|
||||
}
|
||||
bool operator==(uint32_t addr) const {
|
||||
return _address.dword == addr;
|
||||
}
|
||||
bool operator==(const uint8_t* addr) const;
|
||||
|
||||
// Overloaded index operator to allow getting and setting individual octets of the address
|
||||
uint8_t operator[](int index) const {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
uint8_t& operator[](int index) {
|
||||
return _address.bytes[index];
|
||||
}
|
||||
|
||||
// Overloaded copy operators to allow initialisation of IPAddress objects from other types
|
||||
IPAddress& operator=(const uint8_t *address);
|
||||
IPAddress& operator=(uint32_t address);
|
||||
|
||||
std::string toString();
|
||||
|
||||
friend class Client;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
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
|
||||
|
||||
class Server {
|
||||
public:
|
||||
virtual void begin() =0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#ifndef Stream_h
|
||||
#define Stream_h
|
||||
|
||||
class Stream {
|
||||
public:
|
||||
virtual size_t write(uint8_t) = 0;
|
||||
virtual size_t write(const uint8_t *buffer, size_t size) = 0;
|
||||
|
||||
virtual int available() = 0;
|
||||
virtual int read() = 0;
|
||||
virtual int peek() = 0;
|
||||
virtual void flush() = 0;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,210 @@
|
||||
/**
|
||||
* The MySensors Arduino library handles the wireless radio link and protocol
|
||||
* between your home built sensors/actuators and HA controller of choice.
|
||||
* The sensors forms a self healing radio network with optional repeaters. Each
|
||||
* repeater and gateway builds a routing tables in EEPROM which keeps track of the
|
||||
* network topology allowing messages to be routed to nodes.
|
||||
*
|
||||
* Created by Marcelo Aquino <marceloaqno@gmail.org>
|
||||
* Copyright (C) 2016 Marcelo Aquino
|
||||
* 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 Olivier Mauti work(RF24.h), copyright (C) 2016 Olivier Mauti <olivier@mysensors.org>
|
||||
*/
|
||||
|
||||
#include "RF24.h"
|
||||
|
||||
// pipes
|
||||
#define BROADCAST_PIPE 1
|
||||
#define NODE_PIPE 2
|
||||
|
||||
// debug
|
||||
#if defined(MY_DEBUG_VERBOSE_RF24)
|
||||
#define RF24_DEBUG(x,...) debug(x, ##__VA_ARGS__)
|
||||
#else
|
||||
#define RF24_DEBUG(x,...)
|
||||
#endif
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
typedef void (*RF24_receiveCallbackType)(void);
|
||||
|
||||
void (* RF24_receiveCallback)(void) = NULL;
|
||||
|
||||
static pthread_mutex_t rf24_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
#endif
|
||||
|
||||
static uint8_t MY_RF24_BASE_ADDR[MY_RF24_ADDR_WIDTH] = { MY_RF24_BASE_RADIO_ID };
|
||||
static uint8_t MY_RF24_NODE_ADDRESS = AUTO;
|
||||
|
||||
RF24 _rf24(MY_RF24_CE_PIN, MY_RF24_CS_PIN);
|
||||
|
||||
static void RF24_startListening(void) {
|
||||
RF24_DEBUG(PSTR("start listening\n"));
|
||||
|
||||
_rf24.startListening();
|
||||
}
|
||||
|
||||
static void RF24_powerDown(void) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
_rf24.powerDown();
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool RF24_sendMessage( uint8_t recipient, const void* buf, uint8_t len ) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
// Make sure radio has powered up
|
||||
_rf24.powerUp();
|
||||
_rf24.stopListening();
|
||||
|
||||
RF24_DEBUG(PSTR("send message to %d, len=%d\n"), recipient,len);
|
||||
|
||||
MY_RF24_BASE_ADDR[0] = recipient;
|
||||
_rf24.openWritingPipe(MY_RF24_BASE_ADDR);
|
||||
bool ok = _rf24.write(buf, len, recipient == BROADCAST_ADDRESS);
|
||||
_rf24.startListening();
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
static bool RF24_isDataAvailable() {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
uint8_t pipe_num = 255;
|
||||
_rf24.available(&pipe_num);
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return (pipe_num <= 5);
|
||||
}
|
||||
|
||||
static uint8_t RF24_readMessage( void* buf) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
uint8_t len = _rf24.getDynamicPayloadSize();
|
||||
_rf24.read(buf, len);
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return len;
|
||||
}
|
||||
|
||||
static void RF24_setNodeAddress(uint8_t address) {
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
if (address != AUTO){
|
||||
MY_RF24_NODE_ADDRESS = address;
|
||||
// enable node pipe
|
||||
MY_RF24_BASE_ADDR[0] = MY_RF24_NODE_ADDRESS;
|
||||
_rf24.openReadingPipe(NODE_PIPE, MY_RF24_BASE_ADDR);
|
||||
// enable autoACK on node pipe
|
||||
_rf24.setAutoAck(NODE_PIPE, true);
|
||||
}
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
static uint8_t RF24_getNodeID(void) {
|
||||
return MY_RF24_NODE_ADDRESS;
|
||||
}
|
||||
|
||||
bool RF24_sanityCheck(void) {
|
||||
bool ok = true;
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_lock(&rf24_mutex);
|
||||
#endif
|
||||
// detect HW defect ot interrupted SPI line, CE disconnect cannot be detected
|
||||
if (_rf24.getPALevel() != MY_RF24_PA_LEVEL || _rf24.getDataRate() != MY_RF24_DATARATE ||
|
||||
_rf24.getChannel() != MY_RF24_CHANNEL) {
|
||||
ok = false;
|
||||
}
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
pthread_mutex_unlock(&rf24_mutex);
|
||||
#endif
|
||||
return ok;
|
||||
}
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
void RF24_irqHandler(void) {
|
||||
if (RF24_receiveCallback) {
|
||||
while (RF24_isDataAvailable()) {
|
||||
RF24_receiveCallback();
|
||||
}
|
||||
} else {
|
||||
// clear RX interrupt
|
||||
bool tx_ok,tx_fail,rx;
|
||||
_rf24.whatHappened(tx_ok,tx_fail,rx);
|
||||
}
|
||||
}
|
||||
|
||||
void RF24_registerReceiveCallback(RF24_receiveCallbackType cb) {
|
||||
RF24_receiveCallback = cb;
|
||||
}
|
||||
#endif
|
||||
|
||||
static bool RF24_initialize(void) {
|
||||
// start up the radio library
|
||||
_rf24.begin();
|
||||
// determine whether the hardware is an nRF24L01+ or not
|
||||
if (!_rf24.isPVariant()) {
|
||||
RF24_DEBUG(PSTR("radio hardware not compatible"));
|
||||
return false;
|
||||
}
|
||||
// set CRC
|
||||
_rf24.setCRCLength(RF24_CRC_16);
|
||||
// set address width
|
||||
_rf24.setAddressWidth(MY_RF24_ADDR_WIDTH);
|
||||
// auto retransmit delay 1500us, auto retransmit count 15
|
||||
_rf24.setRetries(5, 15);
|
||||
// channel
|
||||
_rf24.setChannel(MY_RF24_CHANNEL);
|
||||
// PA level
|
||||
_rf24.setPALevel(MY_RF24_PA_LEVEL);
|
||||
// data rate
|
||||
_rf24.setDataRate(MY_RF24_DATARATE);
|
||||
// sanity check
|
||||
#if defined(MY_RF24_SANITY_CHECK)
|
||||
if (!RF24_sanityCheck()) {
|
||||
RF24_DEBUG(PSTR("RF24:Sanity check failed: configuration mismatch! Check wiring, replace module or non-P version\n"));
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
// enable Dynamic payload
|
||||
_rf24.enableDynamicPayloads();
|
||||
// enable ACK payload
|
||||
_rf24.enableAckPayload();
|
||||
// disable AA on all pipes, activate when node pipe set
|
||||
_rf24.setAutoAck(false);
|
||||
// all nodes listen to broadcast pipe (for FIND_PARENT_RESPONSE messages)
|
||||
MY_RF24_BASE_ADDR[0] = BROADCAST_ADDRESS;
|
||||
_rf24.openReadingPipe(BROADCAST_PIPE, MY_RF24_BASE_ADDR);
|
||||
|
||||
//_rf24.printDetails();
|
||||
|
||||
#ifdef MY_RF24_IRQ_PIN
|
||||
// Mask all interrupts except the receive interrupt
|
||||
_rf24.maskIRQ(1,1,0);
|
||||
|
||||
attachInterrupt(MY_RF24_IRQ_PIN, INT_EDGE_FALLING, RF24_irqHandler);
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
Reference in New Issue
Block a user