knx/src/linux_platform.cpp

1176 lines
26 KiB
C++
Raw Normal View History

2018-11-07 00:32:36 +01:00
#include "linux_platform.h"
#ifdef __linux__
#include <cstdio>
2018-11-07 00:32:36 +01:00
#include <string>
#include <cstring>
#include <cstdlib>
#include <stdexcept>
#include <cmath>
2018-11-07 00:32:36 +01:00
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <net/if_arp.h>
2018-11-07 00:32:36 +01:00
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <termios.h>
2018-11-07 00:32:36 +01:00
#include <sys/ioctl.h> // Needed for SPI port
#include <linux/spi/spidev.h> // Needed for SPI port
#include <poll.h> // Needed for GPIO edge detection
#include <sys/time.h> // Needed for delayMicroseconds()
2019-10-25 16:41:29 +02:00
2018-11-07 00:32:36 +01:00
#include "knx/device_object.h"
#include "knx/address_table_object.h"
#include "knx/association_table_object.h"
#include "knx/group_object_table_object.h"
#include "knx/application_program_object.h"
#include "knx/ip_parameter_object.h"
2018-12-22 01:55:08 +01:00
#include "knx/bits.h"
#include "knx/ip_host_protocol_address_information.h"
2018-11-07 00:32:36 +01:00
#define MAX_MEM 4096
2019-08-22 22:57:35 +02:00
LinuxPlatform::LinuxPlatform()
{
int socketMac = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
if (socketMac < 0)
{
printf("Lookup socket creation failed");
return;
}
struct ifreq ifr;
struct ifconf ifc;
char buf[1024];
ifc.ifc_len = sizeof(buf);
ifc.ifc_buf = buf;
if (ioctl(socketMac, SIOCGIFCONF, &ifc) < 0)
return;
struct ifreq* it = ifc.ifc_req;
const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
for (; it != end; ++it)
{
strcpy(ifr.ifr_name, it->ifr_name);
if (ioctl(socketMac, SIOCGIFFLAGS, &ifr))
continue;
if (ifr.ifr_flags & IFF_LOOPBACK) // don't count loopback
continue;
if (ioctl(socketMac, SIOCGIFHWADDR, &ifr))
continue;
if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
continue;
memcpy(_macAddress, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
ioctl(socketMac, SIOCGIFADDR, &ifr);
2019-12-28 00:29:17 +01:00
struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr;
_ipAddress = ntohl(ipaddr->sin_addr.s_addr);
//printf("IP address: %s\n", inet_ntoa(ipaddr->sin_addr));
ioctl(socketMac, SIOCGIFNETMASK, &ifr);
struct sockaddr_in* netmask = (struct sockaddr_in*)&ifr.ifr_netmask;
_netmask = ntohl(netmask->sin_addr.s_addr);
//printf("Netmask: %s\n", inet_ntoa(ipaddr->sin_addr));
break;
}
close(socketMac);
// default GW
FILE* f;
char line[100], *p, *c, *g, *saveptr;
f = fopen("/proc/net/route", "r");
while (fgets(line, 100, f))
{
p = strtok_r(line, " \t", &saveptr);
c = strtok_r(NULL, " \t", &saveptr);
g = strtok_r(NULL, " \t", &saveptr);
if (p != NULL && c != NULL)
{
if (strcmp(c, "00000000") == 0)
{
//printf("Default interface is : %s \n" , p);
if (g)
{
char* pEnd;
_defaultGateway = ntohl(strtol(g, &pEnd, 16));
}
break;
}
}
}
fclose(f);
}
2019-05-31 23:44:03 +02:00
LinuxPlatform::~LinuxPlatform()
{
delete[] _args;
2018-11-07 00:32:36 +01:00
}
2019-08-22 21:31:02 +02:00
uint32_t millis()
2018-11-07 00:32:36 +01:00
{
struct timespec spec;
clock_gettime(CLOCK_MONOTONIC, &spec);
return spec.tv_sec * 1000 + round(spec.tv_nsec / 1.0e6);
}
2019-08-22 21:31:02 +02:00
void delay(uint32_t millis)
2018-11-07 00:32:36 +01:00
{
struct timespec ts;
ts.tv_sec = millis / 1000;
ts.tv_nsec = (millis % 1000) * 1000000;
nanosleep(&ts, NULL);
}
void LinuxPlatform::restart()
{
2019-05-31 23:44:03 +02:00
execv(_args[0], _args);
2018-11-07 00:32:36 +01:00
}
void LinuxPlatform::fatalError()
{
printf("A fatal error occured. Stopping.\n");
while (true)
sleep(1);
}
void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port)
{
if (_multicastSocketFd >= 0)
closeMultiCast();
2018-11-07 00:32:36 +01:00
_multicastAddr = addr;
_multicastPort = port;
2018-11-07 00:32:36 +01:00
struct ip_mreq command;
uint32_t loop = 1;
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_ANY);
sin.sin_port = htons(port);
_multicastSocketFd = socket(AF_INET, SOCK_DGRAM, 0);
if (_multicastSocketFd == -1)
{
2018-11-07 00:32:36 +01:00
perror("socket()");
fatalError();
}
/* Mehr Prozessen erlauben, denselben Port zu nutzen */
loop = 1;
if (setsockopt(_multicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0)
2018-11-07 00:32:36 +01:00
{
perror("setsockopt:SO_REUSEADDR");
fatalError();
}
if (bind(_multicastSocketFd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
2018-11-07 00:32:36 +01:00
{
perror("bind");
fatalError();
}
2018-12-22 01:55:08 +01:00
/* loopback */
loop = 0;
if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0)
2018-11-07 00:32:36 +01:00
{
perror("setsockopt:IP_MULTICAST_LOOP");
fatalError();
}
/* Join the broadcast group: */
command.imr_multiaddr.s_addr = htonl(addr);
command.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0)
2018-11-07 00:32:36 +01:00
{
perror("setsockopt:IP_ADD_MEMBERSHIP");
fatalError();
}
uint32_t flags = fcntl(_multicastSocketFd, F_GETFL);
2018-11-07 00:32:36 +01:00
flags |= O_NONBLOCK;
fcntl(_multicastSocketFd, F_SETFL, flags);
2018-11-07 00:32:36 +01:00
}
void LinuxPlatform::closeMultiCast()
{
struct ip_mreq command;
command.imr_multiaddr.s_addr = htonl(_multicastAddr);
command.imr_interface.s_addr = htonl(INADDR_ANY);
if (setsockopt(_multicastSocketFd,
IPPROTO_IP,
IP_DROP_MEMBERSHIP,
&command, sizeof(command)) < 0)
{
2018-11-07 00:32:36 +01:00
perror("setsockopt:IP_DROP_MEMBERSHIP");
}
close(_multicastSocketFd);
_multicastSocketFd = -1;
2018-11-07 00:32:36 +01:00
}
bool LinuxPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len)
2018-11-07 00:32:36 +01:00
{
struct sockaddr_in address = {0};
2018-11-07 00:32:36 +01:00
address.sin_family = AF_INET;
address.sin_addr.s_addr = htonl(_multicastAddr);
address.sin_port = htons(_multicastPort);
2018-11-07 00:32:36 +01:00
ssize_t retVal = 0;
do
{
retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address));
2018-11-07 00:32:36 +01:00
if (retVal == -1)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
return false;
}
} while (retVal == -1);
// printHex("<-", buffer, len);
2018-11-07 00:32:36 +01:00
return true;
}
int LinuxPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen)
2018-11-07 00:32:36 +01:00
{
uint32_t sin_len;
struct sockaddr_in sin;
sin_len = sizeof(sin);
ssize_t len = recvfrom(_multicastSocketFd, buffer, maxLen, 0, (struct sockaddr*)&sin, &sin_len);
// if (len > 0)
// printHex("->", buffer, len);
2018-11-07 00:32:36 +01:00
return len;
}
uint8_t* LinuxPlatform::getEepromBuffer(uint16_t size)
2018-11-07 00:32:36 +01:00
{
2019-01-21 21:29:00 +01:00
if (_fd < 0)
doMemoryMapping();
2018-11-07 00:32:36 +01:00
return _mappedFile + 2;
}
void LinuxPlatform::commitToEeprom()
{
2019-01-21 21:29:00 +01:00
if (_fd < 0)
doMemoryMapping();
2018-11-07 00:32:36 +01:00
fsync(_fd);
}
#define FLASHSIZE 0x10000
void LinuxPlatform::doMemoryMapping()
{
2019-01-21 21:29:00 +01:00
_fd = open(_flashFilePath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IROTH);
2018-11-07 00:32:36 +01:00
if (_fd < 0)
{
puts("Error in file opening");
2018-11-07 00:32:36 +01:00
//exit(-1);
}
struct stat st;
uint32_t ret = fstat(_fd, &st);
if (ret < 0)
{
puts("Error in fstat");
2018-11-07 00:32:36 +01:00
//exit(-1);
}
size_t len_file = st.st_size;
if (len_file < FLASHSIZE)
{
if (ftruncate(_fd, FLASHSIZE) != 0)
{
puts("Error extending file");
2018-11-07 00:32:36 +01:00
//exit(-1);
}
len_file = FLASHSIZE;
}
unsigned char* addr = (unsigned char*)mmap(NULL, len_file, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
if (addr[0] != 0xAF || addr[1] != 0xFE)
{
memset(addr, 0, FLASHSIZE);
addr[0] = 0xAF;
addr[1] = 0xFE;
}
if (addr == MAP_FAILED)
{
puts("Error in mmap");
2018-11-07 00:32:36 +01:00
//exit(-1);
}
_mappedFile = addr;
}
2019-10-25 16:41:29 +02:00
void LinuxPlatform::closeSpi()
{
close(_spiFd);
printf("SPI device closed.\r\n");
2019-10-25 16:41:29 +02:00
}
int LinuxPlatform::readWriteSpi(uint8_t* data, size_t len)
2019-10-25 16:41:29 +02:00
{
uint16_t spiDelay = 0;
2019-10-25 16:41:29 +02:00
uint32_t spiSpeed = 8000000; // 4 MHz SPI speed
uint8_t spiBPW = 8; // Bits per word
2019-10-25 16:41:29 +02:00
struct spi_ioc_transfer spi;
2019-10-25 16:41:29 +02:00
// Mentioned in spidev.h but not used in the original kernel documentation
// test program )-:
memset(&spi, 0, sizeof(spi));
2019-10-25 16:41:29 +02:00
spi.tx_buf = (uint64_t)data;
spi.rx_buf = (uint64_t)data;
spi.len = len;
spi.delay_usecs = spiDelay;
spi.speed_hz = spiSpeed;
2019-10-25 16:41:29 +02:00
spi.bits_per_word = spiBPW;
return ioctl(_spiFd, SPI_IOC_MESSAGE(1), &spi);
2019-10-25 16:41:29 +02:00
}
void LinuxPlatform::setupSpi()
{
if ((_spiFd = open("/dev/spidev0.0", O_RDWR)) < 0)
2019-10-25 16:41:29 +02:00
{
printf("ERROR: SPI setup failed! Could not open SPI device!\r\n");
2019-10-25 16:41:29 +02:00
return;
}
// Set SPI parameters.
int mode = 0; // Mode 0
uint8_t spiBPW = 8; // Bits per word
2019-10-25 16:41:29 +02:00
int speed = 8000000; // 4 MHz SPI speed
if (ioctl(_spiFd, SPI_IOC_WR_MODE, &mode) < 0)
2019-10-25 16:41:29 +02:00
{
printf("ERROR: SPI Mode Change failure: %s\n", strerror(errno));
2019-10-25 16:41:29 +02:00
close(_spiFd);
return;
}
if (ioctl(_spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
2019-10-25 16:41:29 +02:00
{
printf("ERROR: SPI BPW Change failure: %s\n", strerror(errno));
2019-10-25 16:41:29 +02:00
close(_spiFd);
return;
}
if (ioctl(_spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
2019-10-25 16:41:29 +02:00
{
printf("ERROR: SPI Speed Change failure: %s\n", strerror(errno));
2019-10-25 16:41:29 +02:00
close(_spiFd);
return;
}
printf("SPI device setup ok.\r\n");
2019-10-25 16:41:29 +02:00
}
2019-01-21 21:29:00 +01:00
void LinuxPlatform::flashFilePath(const std::string path)
{
_flashFilePath = path;
}
std::string LinuxPlatform::flashFilePath()
{
return _flashFilePath;
}
size_t LinuxPlatform::readBytesUart(uint8_t *buffer, size_t length)
{
return read(_uartFd, buffer, length);
}
int LinuxPlatform::readUart()
{
uint8_t x ;
if (read(_uartFd, &x, 1) != 1)
{
return -1;
}
return ((int)x) & 0xFF ;
}
size_t LinuxPlatform::writeUart(const uint8_t *buffer, size_t size)
{
return write(_uartFd, buffer, size) ;
}
size_t LinuxPlatform::writeUart(const uint8_t data)
{
return write(_uartFd, &data, 1) ;
}
int LinuxPlatform::uartAvailable()
{
int result ;
if (ioctl(_uartFd, FIONREAD, &result) == -1)
{
return -1;
}
return result ;
}
void LinuxPlatform::closeUart()
{
if (_uartFd >= 0)
{
close(_uartFd);
}
}
void LinuxPlatform::setupUart()
{
/*
* 19200,8E1, no handshake
*/
struct termios options; /* Schnittstellenoptionen */
/* Port oeffnen - read/write, kein "controlling tty", Status von DCD ignorieren */
_uartFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
if (_uartFd >= 0)
{
/* get the current options */
fcntl(_uartFd, F_SETFL, 0);
if (tcgetattr(_uartFd, &options) != 0)
{
close(_uartFd);
_uartFd = -1;
return;
}
memset(&options, 0, sizeof(options)); /* Structur loeschen, ggf. vorher sichern
und bei Programmende wieder restaurieren */
/* Baudrate setzen */
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);
/* setze Optionen */
options.c_cflag |= PARENB; /* Enable Paritybit */
options.c_cflag &= ~PARODD; /* Even parity */
options.c_cflag &= ~CSTOPB; /* 1 Stoppbit */
options.c_cflag &= ~CSIZE; /* 8 Datenbits */
options.c_cflag |= CS8;
/* 19200 bps, 8 Datenbits, CD-Signal ignorieren, Lesen erlauben */
options.c_cflag |= (CLOCAL | CREAD);
/* Kein Echo, keine Steuerzeichen, keine Interrupts */
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
options.c_iflag = IGNPAR; /* Parity-Fehler ignorieren */
options.c_oflag &= ~OPOST; /* setze "raw" Input */
options.c_cc[VMIN] = 0; /* warten auf min. 0 Zeichen */
options.c_cc[VTIME] = 10; /* Timeout 1 Sekunde */
tcflush(_uartFd,TCIOFLUSH); /* Puffer leeren */
if (tcsetattr(_uartFd, TCSAFLUSH, &options) != 0)
{
close(_uartFd);
_uartFd = -1;
return;
}
}
}
void printUint64(uint64_t value, int base = DEC)
{
char buf[8 * sizeof(uint64_t) + 1];
char* str = &buf[sizeof(buf) - 1];
*str = '\0';
uint64_t n = value;
do {
char c = n % base;
n /= base;
*--str = c < 10 ? c + '0' : c + 'A' - 10;
} while (n > 0);
print(str);
}
void print(const char* s)
{
printf("%s", s);
}
void print(char c)
{
printf("%c", c);
}
void print(unsigned char num)
{
print(num, DEC);
}
void print(unsigned char num, int base)
{
if (base == HEX)
printf("%X", num);
else
printf("%d", num);
}
void print(int num)
{
print(num, DEC);
}
void print(int num, int base)
{
if (base == HEX)
printf("%X", num);
else
printf("%d", num);
}
void print(unsigned int num)
{
print(num, DEC);
}
void print(unsigned int num, int base)
{
if (base == HEX)
printf("%X", num);
else
printf("%d", num);
}
void print(long num)
{
print(num, DEC);
}
void print(long num, int base)
{
if (base == HEX)
printf("%lX", num);
else
printf("%ld", num);
}
void print(unsigned long num)
{
print(num, DEC);
}
void print(unsigned long num, int base)
{
if (base == HEX)
printf("%lX", num);
else
printf("%ld", num);
}
void print(unsigned long long num)
{
printUint64(num);
}
void print(unsigned long long num, int base)
{
printUint64(num, base);
}
void print(double num)
{
printf("%f", num);
}
void println(const char* s)
{
printf("%s\n", s);
}
void println(char c)
{
printf("%c\n", c);
}
void println(unsigned char num)
{
println(num, DEC);
}
void println(unsigned char num, int base)
{
if (base == HEX)
printf("%X\n", num);
else
printf("%d\n", num);
}
void println(int num)
{
println(num, DEC);
}
void println(int num, int base)
{
if (base == HEX)
printf("%X\n", num);
else
printf("%d\n", num);
}
void println(unsigned int num)
{
println(num, DEC);
}
void println(unsigned int num, int base)
{
if (base == HEX)
printf("%X\n", num);
else
printf("%d\n", num);
}
void println(long num)
{
println(num, DEC);
}
void println(long num, int base)
{
if (base == HEX)
printf("%lX\n", num);
else
printf("%ld\n", num);
}
void println(unsigned long num)
{
println(num, DEC);
}
void println(unsigned long num, int base)
{
if (base == HEX)
printf("%lX\n", num);
else
printf("%ld\n", num);
}
void println(unsigned long long num)
{
printUint64(num);
println("");
}
void println(unsigned long long num, int base)
{
printUint64(num, base);
println("");
}
void println(double num)
{
printf("%f\n", num);
}
void println(double num, int places)
{
printf("%f\n", num);
}
void println(void)
{
printf("\n");
}
2019-08-22 22:57:35 +02:00
void pinMode(uint32_t dwPin, uint32_t dwMode)
{
gpio_export(dwPin);
gpio_direction(dwPin, dwMode);
2019-08-22 22:57:35 +02:00
}
void digitalWrite(uint32_t dwPin, uint32_t dwVal)
{
gpio_write(dwPin, dwVal);
}
uint32_t digitalRead(uint32_t dwPin)
{
return gpio_read(dwPin);
2019-08-22 22:57:35 +02:00
}
typedef void (*voidFuncPtr)(void);
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
{
}
void LinuxPlatform::cmdLineArgs(int argc, char** argv)
{
if (_args)
delete[] _args;
_args = new char*[argc + 1];
memcpy(_args, argv, argc * sizeof(char*));
_args[argc] = 0;
}
2019-10-25 16:41:29 +02:00
/* Buffer size for string operations (e.g. snprintf())*/
#define MAX_STRBUF_SIZE 100
#define MAX_NUM_GPIO 64
static int gpioFds[MAX_NUM_GPIO] =
{
-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,
};
2019-10-25 16:41:29 +02:00
/* Activate GPIO-Pin
* Write GPIO pin number to /sys/class/gpio/export
* Result: 0 = success, -1 = error
2019-10-25 16:41:29 +02:00
*/
int gpio_export(int pin)
{
char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */
ssize_t bytes; /* Used Buffer length */
int fd; /* Filedescriptor */
int res; /* Result from write() */
fprintf(stderr, "Export GPIO pin %d\n", pin);
2019-10-25 16:41:29 +02:00
fd = open("/sys/class/gpio/export", O_WRONLY);
if (fd < 0)
{
perror("Could not export GPIO pin(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin);
2019-10-25 16:41:29 +02:00
res = write(fd, buffer, bytes);
if (res < 0)
{
perror("Could not export GPIO pin(write)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
close(fd);
delay(100);
return (0);
2019-10-25 16:41:29 +02:00
}
/* Deactivate GPIO pin
* Write GPIO pin number to /sys/class/gpio/unexport
* Result: 0 = success, -1 = error
2019-10-25 16:41:29 +02:00
*/
int gpio_unexport(int pin)
{
char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */
ssize_t bytes; /* Used Buffer length */
int fd; /* Filedescriptor */
int res; /* Result from write() */
fprintf(stderr, "Unexport GPIO pin %d\n", pin);
close(gpioFds[pin]);
2019-10-25 16:41:29 +02:00
fd = open("/sys/class/gpio/unexport", O_WRONLY);
if (fd < 0)
{
perror("Could not unexport GPIO pin(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin);
2019-10-25 16:41:29 +02:00
res = write(fd, buffer, bytes);
if (res < 0)
{
perror("Could not unexport GPIO pin(write)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
close(fd);
return (0);
2019-10-25 16:41:29 +02:00
}
/* Set GPIO pin mode (input/output)
* Write GPIO pin number to /sys/class/gpioXX/direction
* Direction: 0 = input, 1 = output
* Result: 0 = success, -1 = error
2019-10-25 16:41:29 +02:00
*/
int gpio_direction(int pin, int dir)
{
char path[MAX_STRBUF_SIZE]; /* Buffer for path */
int fd; /* Filedescriptor */
int res; /* Result from write() */
fprintf(stderr, "Set GPIO direction for pin %d to %s\n", pin, (dir == INPUT) ? "INPUT" : "OUTPUT");
2019-10-25 16:41:29 +02:00
snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/direction", pin);
2019-10-25 16:41:29 +02:00
fd = open(path, O_WRONLY);
if (fd < 0)
{
perror("Could not set mode for GPIO pin(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
switch (dir)
{
case INPUT:
res = write(fd, "in", 2);
break;
case OUTPUT:
res = write(fd, "out", 3);
break;
default:
res = -1;
break;
2019-10-25 16:41:29 +02:00
}
if (res < 0)
{
perror("Could not set mode for GPIO pin(write)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
close(fd);
return (0);
2019-10-25 16:41:29 +02:00
}
/* Read from GPIO pin
* Result: -1 = error, 0/1 = GPIO pin state
2019-10-25 16:41:29 +02:00
*/
int gpio_read(int pin)
{
char path[MAX_STRBUF_SIZE]; /* Buffer for path */
char c;
2019-10-25 16:41:29 +02:00
snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin);
if (gpioFds[pin] < 0)
gpioFds[pin] = open(path, O_RDWR);
if (gpioFds[pin] < 0)
2019-10-25 16:41:29 +02:00
{
perror("Could not read from GPIO(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
lseek(gpioFds[pin], 0L, SEEK_SET);
if (read(gpioFds[pin], &c, 1) < 0)
2019-10-25 16:41:29 +02:00
{
perror("Could not read from GPIO(read)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
return (c == '0') ? LOW : HIGH;
2019-10-25 16:41:29 +02:00
}
/* Write to GPIO pin
* Result: -1 = error, 0 = success
2019-10-25 16:41:29 +02:00
*/
int gpio_write(int pin, int value)
{
char path[MAX_STRBUF_SIZE]; /* Buffer for path */
int res; /* Result from write()*/
2019-10-25 16:41:29 +02:00
snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin);
if (gpioFds[pin] < 0)
gpioFds[pin] = open(path, O_RDWR);
2019-10-25 16:41:29 +02:00
if (gpioFds[pin] < 0)
2019-10-25 16:41:29 +02:00
{
perror("Could not write to GPIO(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
switch (value)
{
case LOW:
res = write(gpioFds[pin], "0\n", 2);
break;
case HIGH:
res = write(gpioFds[pin], "1\n", 2);
break;
default:
res = -1;
break;
2019-10-25 16:41:29 +02:00
}
if (res < 0)
{
perror("Could not write to GPIO(write)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
return (0);
2019-10-25 16:41:29 +02:00
}
/* Set GPIO pin edge detection
* 'r' (rising)
* 'f' (falling)
* 'b' (both)
2019-10-25 16:41:29 +02:00
*/
int gpio_edge(unsigned int pin, char edge)
{
char path[MAX_STRBUF_SIZE]; /* Buffer for path */
int fd; /* Filedescriptor */
2019-10-25 16:41:29 +02:00
snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/edge", pin);
2019-10-25 16:41:29 +02:00
fd = open(path, O_WRONLY | O_NONBLOCK);
2019-10-25 16:41:29 +02:00
if (fd < 0)
{
perror("Could not set GPIO edge detection(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
switch (edge)
{
case 'r':
strncpy(path, "rising", 8);
break;
case 'f':
strncpy(path, "falling", 8);
break;
case 'b':
strncpy(path, "both", 8);
break;
case 'n':
strncpy(path, "none", 8);
break;
default:
close(fd);
return (-2);
2019-10-25 16:41:29 +02:00
}
write(fd, path, strlen(path) + 1);
close(fd);
return 0;
}
/* Wait for edge on GPIO pin
* timeout in milliseconds
* Result: <0: error, 0: poll() Timeout,
* 1: edge detected, GPIO pin reads "0"
* 2: edge detected, GPIO pin reads "1"
2019-10-25 16:41:29 +02:00
*/
int gpio_wait(unsigned int pin, int timeout)
{
char path[MAX_STRBUF_SIZE]; /* Buffer for path */
int fd; /* Filedescriptor */
struct pollfd polldat[1]; /* Variable for poll() */
char buf[MAX_STRBUF_SIZE]; /* Read buffer */
int rc; /* Result */
2019-10-25 16:41:29 +02:00
/* Open GPIO pin */
snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin);
fd = open(path, O_RDONLY | O_NONBLOCK);
2019-10-25 16:41:29 +02:00
if (fd < 0)
{
perror("Could not wait for GPIO edge(open)!\n");
return (-1);
2019-10-25 16:41:29 +02:00
}
/* prepare poll() */
2019-10-25 16:41:29 +02:00
memset((void*)buf, 0, sizeof(buf));
memset((void*)polldat, 0, sizeof(polldat));
polldat[0].fd = fd;
polldat[0].events = POLLPRI;
/* clear any existing detected edges before */
2019-10-25 16:41:29 +02:00
lseek(fd, 0, SEEK_SET);
rc = read(fd, buf, MAX_STRBUF_SIZE - 1);
2019-10-25 16:41:29 +02:00
rc = poll(polldat, 1, timeout);
if (rc < 0)
{ /* poll() failed! */
perror("Could not wait for GPIO edge(poll)!\n");
2019-10-25 16:41:29 +02:00
close(fd);
return (-1);
2019-10-25 16:41:29 +02:00
}
if (rc == 0)
{ /* poll() timeout! */
close(fd);
return (0);
2019-10-25 16:41:29 +02:00
}
if (polldat[0].revents & POLLPRI)
{
if (rc < 0)
{ /* read() failed! */
perror("Could not wait for GPIO edge(read)!\n");
2019-10-25 16:41:29 +02:00
close(fd);
return (-2);
2019-10-25 16:41:29 +02:00
}
/* printf("poll() GPIO %d interrupt occurred: %s\n", pin, buf); */
close(fd);
return (1 + atoi(buf));
2019-10-25 16:41:29 +02:00
}
close(fd);
return (-1);
2019-10-25 16:41:29 +02:00
}
void delayMicrosecondsHard(unsigned int howLong)
2019-10-25 16:41:29 +02:00
{
struct timeval tNow, tLong, tEnd;
2019-10-25 16:41:29 +02:00
gettimeofday(&tNow, NULL);
tLong.tv_sec = howLong / 1000000;
tLong.tv_usec = howLong % 1000000;
timeradd(&tNow, &tLong, &tEnd);
2019-10-25 16:41:29 +02:00
while (timercmp(&tNow, &tEnd, <))
gettimeofday(&tNow, NULL);
2019-10-25 16:41:29 +02:00
}
void delayMicroseconds(unsigned int howLong)
2019-10-25 16:41:29 +02:00
{
struct timespec sleeper;
unsigned int uSecs = howLong % 1000000;
unsigned int wSecs = howLong / 1000000;
2019-10-25 16:41:29 +02:00
/**/ if (howLong == 0)
return;
else if (howLong < 100)
delayMicrosecondsHard(howLong);
else
{
sleeper.tv_sec = wSecs;
sleeper.tv_nsec = (long)(uSecs * 1000L);
nanosleep(&sleeper, NULL);
}
2019-10-25 16:41:29 +02:00
}
2019-12-28 00:29:17 +01:00
bool LinuxPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
{
struct sockaddr_in address = {0};
address.sin_family = AF_INET;
2019-12-28 00:29:17 +01:00
address.sin_addr.s_addr = htonl(addr);
address.sin_port = htons(port);
ssize_t retVal = 0;
do
{
2019-12-28 00:29:17 +01:00
retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address));
if (retVal == -1)
{
if (errno != EAGAIN && errno != EWOULDBLOCK)
return false;
}
} while (retVal == -1);
// printHex("<-", buffer, len);
return true;
}
void LinuxPlatform::macAddress(uint8_t* mac_address)
{
memcpy(mac_address, _macAddress, IFHWADDRLEN);
}
uint32_t LinuxPlatform::currentIpAddress()
{
return _ipAddress;
}
uint32_t LinuxPlatform::currentSubnetMask()
{
return _netmask;
}
uint32_t LinuxPlatform::currentDefaultGateway()
{
return _defaultGateway;
}
#endif