Refactor RaspberryPi port

This commit is contained in:
Marcelo Aquino
2016-08-16 13:42:51 -03:00
parent 2315e2d62c
commit 6b756335d0
32 changed files with 2460 additions and 224 deletions
+212
View File
@@ -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
+46
View File
@@ -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
+253
View File
@@ -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;
}
+80
View 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 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
+241
View File
@@ -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;
}
+64
View File
@@ -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
+105
View File
@@ -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);
}
+87
View File
@@ -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
+28
View File
@@ -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
+15
View File
@@ -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
+210
View File
@@ -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;
}