diff --git a/examples/knx-linux/CMakeLists.txt b/examples/knx-linux/CMakeLists.txt index 470dfaa..3389d64 100644 --- a/examples/knx-linux/CMakeLists.txt +++ b/examples/knx-linux/CMakeLists.txt @@ -51,6 +51,8 @@ add_executable(knx-linux ../../src/knx/ip_parameter_object.h ../../src/knx/knx_ip_frame.cpp ../../src/knx/knx_ip_routing_indication.cpp + ../../src/knx/knx_ip_search_request.cpp + ../../src/knx/ip_host_protocol_address_information.cpp ../../src/knx/knx_value.cpp ../../src/knx/knx_value.h ../../src/knx/memory.cpp diff --git a/examples/knx-linux/knx-linux.vcxproj b/examples/knx-linux/knx-linux.vcxproj index b74baa1..aeca3e7 100644 --- a/examples/knx-linux/knx-linux.vcxproj +++ b/examples/knx-linux/knx-linux.vcxproj @@ -97,9 +97,13 @@ + + + + @@ -151,9 +155,13 @@ + + + + diff --git a/examples/knx-linux/knx-linux.vcxproj.filters b/examples/knx-linux/knx-linux.vcxproj.filters index fa8dd01..be2aad8 100644 --- a/examples/knx-linux/knx-linux.vcxproj.filters +++ b/examples/knx-linux/knx-linux.vcxproj.filters @@ -176,6 +176,18 @@ Header files\knx + + Header files\knx + + + Header files\knx + + + Header files\knx + + + Header files\knx + @@ -310,5 +322,17 @@ Source files\knx + + Source files\knx + + + Source files\knx + + + Source files\knx + + + Source files\knx + \ No newline at end of file diff --git a/src/knx/bau_systemB.cpp b/src/knx/bau_systemB.cpp index 7cfc22e..e6e842d 100644 --- a/src/knx/bau_systemB.cpp +++ b/src/knx/bau_systemB.cpp @@ -232,6 +232,10 @@ void BauSystemB::propertyValueReadIndication(Priority priority, HopCountType hop uint8_t data[size]; if(obj) obj->readProperty((PropertyID)propertyId, startIndex, elementCount, data); + + if (elementCount == 0) + size = 0; + _appLayer.propertyValueReadResponse(AckRequested, priority, hopType, asap, objectIndex, propertyId, elementCount, startIndex, data, size); } diff --git a/src/knx/ip_data_link_layer.cpp b/src/knx/ip_data_link_layer.cpp index 2cb2ad2..ccd3e33 100644 --- a/src/knx/ip_data_link_layer.cpp +++ b/src/knx/ip_data_link_layer.cpp @@ -7,6 +7,7 @@ #include "device_object.h" #include "address_table_object.h" #include "knx_ip_routing_indication.h" +#include "knx_ip_search_request.h" #include #include @@ -55,9 +56,19 @@ void IpDataLinkLayer::loop() switch ((KnxIpServiceType)code) { case RoutingIndication: + { KnxIpRoutingIndication routingIndication(buffer, len); frameRecieved(routingIndication.frame()); break; + } + case SearchRequest: + { + KnxIpSearchRequest searchRequest(buffer, len); + break; + } + default: + print("Unhandled service identifier: "); + println(code, HEX); } } diff --git a/src/knx/ip_host_protocol_address_information.cpp b/src/knx/ip_host_protocol_address_information.cpp new file mode 100644 index 0000000..79a86cd --- /dev/null +++ b/src/knx/ip_host_protocol_address_information.cpp @@ -0,0 +1,31 @@ +#include "ip_host_protocol_address_information.h" +#include "bits.h" +#ifdef USE_IP +IpHostProtocolAddressInformation::IpHostProtocolAddressInformation(uint8_t* data) + : _data(data) +{} + + +uint8_t IpHostProtocolAddressInformation::length() +{ + return *_data; +} + + +HostProtocolCode IpHostProtocolAddressInformation::code() +{ + return (HostProtocolCode)_data[1]; +} + + +uint32_t IpHostProtocolAddressInformation::ipAddress() +{ + return getInt(_data + 2); +} + + +uint16_t IpHostProtocolAddressInformation::ipPortNumber() +{ + return getWord(_data + 6); +} +#endif \ No newline at end of file diff --git a/src/knx/ip_host_protocol_address_information.h b/src/knx/ip_host_protocol_address_information.h new file mode 100644 index 0000000..29df5b7 --- /dev/null +++ b/src/knx/ip_host_protocol_address_information.h @@ -0,0 +1,24 @@ +#pragma once + +#include +#include "config.h" + +enum HostProtocolCode : uint8_t +{ + IPV4_UDP = 1, + IPV4_TCP = 2 +}; + +#ifdef USE_IP +class IpHostProtocolAddressInformation +{ + public: + IpHostProtocolAddressInformation(uint8_t* data); + uint8_t length(); + HostProtocolCode code(); + uint32_t ipAddress(); + uint16_t ipPortNumber(); + private: + uint8_t* _data; +}; +#endif \ No newline at end of file diff --git a/src/knx/knx_ip_dib.cpp b/src/knx/knx_ip_dib.cpp new file mode 100644 index 0000000..fadffeb --- /dev/null +++ b/src/knx/knx_ip_dib.cpp @@ -0,0 +1,15 @@ +#include "knx_ip_dib.h" + +DIB::DIB(uint8_t* data) : _data(data) +{} + +DescriptionTypeCode DIB::code() +{ + return (DescriptionTypeCode)_data[1]; +} + + +uint8_t DIB::length() +{ + return *_data; +} diff --git a/src/knx/knx_ip_dib.h b/src/knx/knx_ip_dib.h new file mode 100644 index 0000000..bafe7e6 --- /dev/null +++ b/src/knx/knx_ip_dib.h @@ -0,0 +1,27 @@ +#pragma once + +#include +#include "config.h" + +#ifdef USE_IP + +enum DescriptionTypeCode : uint8_t +{ + DEVICE_INFO = 0x01, + SUPP_SVC_FAMILIES = 0x02, + IP_CONFIG = 0x03, + IP_CUR_CONFIG = 0x04, + KNX_ADDRESSES = 0x05, + MFR_DATA = 0xFE +}; + +class DIB +{ + public: + DIB(uint8_t* data); + DescriptionTypeCode code(); + uint8_t length(); + private: + uint8_t* _data = 0; +}; +#endif diff --git a/src/knx/knx_ip_frame.cpp b/src/knx/knx_ip_frame.cpp index 038a817..df0aa29 100644 --- a/src/knx/knx_ip_frame.cpp +++ b/src/knx/knx_ip_frame.cpp @@ -10,6 +10,7 @@ KnxIpFrame::KnxIpFrame(uint8_t* data, uint16_t length) { _data = data; + _dataLength = length; } uint8_t KnxIpFrame::headerLength() const @@ -62,13 +63,14 @@ uint8_t* KnxIpFrame::data() KnxIpFrame::~KnxIpFrame() { if (_freeData) - delete _data; + delete[] _data; } KnxIpFrame::KnxIpFrame(uint16_t length) { _data = new uint8_t[length]; + _dataLength = length; _freeData = true; headerLength(KNXIP_HEADER_LEN); protocolVersion(KnxIp1_0); diff --git a/src/knx/knx_ip_frame.h b/src/knx/knx_ip_frame.h index b5ab6c8..688b2b2 100644 --- a/src/knx/knx_ip_frame.h +++ b/src/knx/knx_ip_frame.h @@ -53,5 +53,6 @@ class KnxIpFrame protected: bool _freeData = false; uint8_t* _data = 0; + uint16_t _dataLength; }; #endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_request.cpp b/src/knx/knx_ip_search_request.cpp new file mode 100644 index 0000000..ef9cca1 --- /dev/null +++ b/src/knx/knx_ip_search_request.cpp @@ -0,0 +1,13 @@ +#include "knx_ip_search_request.h" +#ifdef USE_IP +KnxIpSearchRequest::KnxIpSearchRequest(uint8_t* data, uint16_t length) + : KnxIpFrame(data, length), _hpai(data + KNXIP_HEADER_LEN) +{ +} + + +IpHostProtocolAddressInformation& KnxIpSearchRequest::hpai() +{ + return _hpai; +} +#endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_request.h b/src/knx/knx_ip_search_request.h new file mode 100644 index 0000000..e51ae46 --- /dev/null +++ b/src/knx/knx_ip_search_request.h @@ -0,0 +1,14 @@ +#pragma once + +#include "knx_ip_frame.h" +#include "ip_host_protocol_address_information.h" +#ifdef USE_IP +class KnxIpSearchRequest : public KnxIpFrame +{ + public: + KnxIpSearchRequest(uint8_t* data, uint16_t length); + IpHostProtocolAddressInformation& hpai(); + private: + IpHostProtocolAddressInformation _hpai; +}; +#endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_response.cpp b/src/knx/knx_ip_search_response.cpp new file mode 100644 index 0000000..54cc32e --- /dev/null +++ b/src/knx/knx_ip_search_response.cpp @@ -0,0 +1,4 @@ +#include "knx_ip_search_response.h" +#ifdef USE_IP + +#endif \ No newline at end of file diff --git a/src/knx/knx_ip_search_response.h b/src/knx/knx_ip_search_response.h new file mode 100644 index 0000000..2bff759 --- /dev/null +++ b/src/knx/knx_ip_search_response.h @@ -0,0 +1,13 @@ +#pragma once + +#include "knx_ip_frame.h" +#include "ip_host_protocol_address_information.h" +#ifdef USE_IP + +class KnxIpSearchResponse : public KnxIpFrame +{ + IpHostProtocolAddressInformation& controlEndpoint(); + +}; + +#endif \ No newline at end of file diff --git a/src/knx/platform.cpp b/src/knx/platform.cpp index 14e6187..7ed8cfc 100644 --- a/src/knx/platform.cpp +++ b/src/knx/platform.cpp @@ -84,6 +84,24 @@ bool Platform::sendBytesMultiCast(uint8_t *buffer, uint16_t len) } int Platform::readBytesMultiCast(uint8_t *buffer, uint16_t maxLen) +{ + return 0; +} + +void Platform::setupUniCast(uint32_t addr, uint16_t port, uint8_t type) +{} + + +void Platform::closeUniCast() +{} + + +bool Platform::sendBytesUniCast(uint8_t* buffer, uint16_t len) +{ + return false; +} + +int Platform::readBytesUniCast(uint8_t *buffer, uint16_t maxLen) { return 0; } \ No newline at end of file diff --git a/src/knx/platform.h b/src/knx/platform.h index 62122dd..347e825 100644 --- a/src/knx/platform.h +++ b/src/knx/platform.h @@ -29,6 +29,12 @@ class Platform virtual void closeMultiCast(); virtual bool sendBytesMultiCast(uint8_t* buffer, uint16_t len); virtual int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen); + + //unicast socket + virtual void setupUniCast(uint32_t addr, uint16_t port, uint8_t type); + virtual void closeUniCast(); + virtual bool sendBytesUniCast(uint8_t* buffer, uint16_t len); + virtual int readBytesUniCast(uint8_t* buffer, uint16_t maxLen); //UART virtual void setupUart(); diff --git a/src/linux_platform.cpp b/src/linux_platform.cpp index e37d3f8..552cdd6 100644 --- a/src/linux_platform.cpp +++ b/src/linux_platform.cpp @@ -15,14 +15,17 @@ #include #include #include +#include +#include +#include #include #include #include -#include // Needed for SPI port -#include // Needed for SPI port -#include // Needed for GPIO edge detection -#include // Needed for delayMicroseconds() +#include // Needed for SPI port +#include // Needed for SPI port +#include // Needed for GPIO edge detection +#include // Needed for delayMicroseconds() #include "knx/device_object.h" #include "knx/address_table_object.h" @@ -31,18 +34,97 @@ #include "knx/application_program_object.h" #include "knx/ip_parameter_object.h" #include "knx/bits.h" +#include "knx/ip_host_protocol_address_information.h" #define MAX_MEM 4096 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); + + 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); +} LinuxPlatform::~LinuxPlatform() { delete[] _args; } - uint32_t millis() { struct timespec spec; @@ -59,8 +141,6 @@ void delay(uint32_t millis) nanosleep(&ts, NULL); } - - void LinuxPlatform::restart() { execv(_args[0], _args); @@ -75,8 +155,11 @@ void LinuxPlatform::fatalError() void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) { + if (_multicastSocketFd >= 0) + closeMultiCast(); + _multicastAddr = addr; - _port = port; + _multicastPort = port; struct ip_mreq command; uint32_t loop = 1; @@ -87,21 +170,22 @@ void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) sin.sin_addr.s_addr = htonl(INADDR_ANY); sin.sin_port = htons(port); - _socketFd = socket(AF_INET, SOCK_DGRAM, 0); - if (_socketFd == -1) { + _multicastSocketFd = socket(AF_INET, SOCK_DGRAM, 0); + if (_multicastSocketFd == -1) + { perror("socket()"); fatalError(); } /* Mehr Prozessen erlauben, denselben Port zu nutzen */ loop = 1; - if (setsockopt(_socketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) + if (setsockopt(_multicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) { perror("setsockopt:SO_REUSEADDR"); fatalError(); } - if (bind(_socketFd, (struct sockaddr *)&sin, sizeof(sin)) < 0) + if (bind(_multicastSocketFd, (struct sockaddr*)&sin, sizeof(sin)) < 0) { perror("bind"); fatalError(); @@ -109,7 +193,7 @@ void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) /* loopback */ loop = 0; - if (setsockopt(_socketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) + if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0) { perror("setsockopt:IP_MULTICAST_LOOP"); fatalError(); @@ -119,15 +203,15 @@ void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port) command.imr_multiaddr.s_addr = htonl(addr); command.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(_socketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0) + if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0) { perror("setsockopt:IP_ADD_MEMBERSHIP"); fatalError(); } - uint32_t flags = fcntl(_socketFd, F_GETFL); + uint32_t flags = fcntl(_multicastSocketFd, F_GETFL); flags |= O_NONBLOCK; - fcntl(_socketFd, F_SETFL, flags); + fcntl(_multicastSocketFd, F_SETFL, flags); } void LinuxPlatform::closeMultiCast() @@ -136,54 +220,56 @@ void LinuxPlatform::closeMultiCast() command.imr_multiaddr.s_addr = htonl(_multicastAddr); command.imr_interface.s_addr = htonl(INADDR_ANY); - if (setsockopt(_socketFd, - IPPROTO_IP, - IP_DROP_MEMBERSHIP, - &command, sizeof(command)) < 0) { + if (setsockopt(_multicastSocketFd, + IPPROTO_IP, + IP_DROP_MEMBERSHIP, + &command, sizeof(command)) < 0) + { perror("setsockopt:IP_DROP_MEMBERSHIP"); } - close(_socketFd); + close(_multicastSocketFd); + _multicastSocketFd = -1; } bool LinuxPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len) { - struct sockaddr_in address = { 0 }; + struct sockaddr_in address = {0}; address.sin_family = AF_INET; address.sin_addr.s_addr = htonl(_multicastAddr); - address.sin_port = htons(_port); + address.sin_port = htons(_multicastPort); ssize_t retVal = 0; do { - retVal = sendto(_socketFd, buffer, len, 0, (struct sockaddr *) &address, sizeof(address)); + 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); + // printHex("<-", buffer, len); return true; } -int LinuxPlatform::readBytesMultiCast(uint8_t * buffer, uint16_t maxLen) +int LinuxPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) { uint32_t sin_len; struct sockaddr_in sin; sin_len = sizeof(sin); - ssize_t len = recvfrom(_socketFd, buffer, maxLen, 0, (struct sockaddr *) &sin, &sin_len); -// if (len > 0) -// printHex("->", buffer, len); - + ssize_t len = recvfrom(_multicastSocketFd, buffer, maxLen, 0, (struct sockaddr*)&sin, &sin_len); + // if (len > 0) + // printHex("->", buffer, len); + return len; } -uint8_t * LinuxPlatform::getEepromBuffer(uint16_t size) +uint8_t* LinuxPlatform::getEepromBuffer(uint16_t size) { if (_fd < 0) doMemoryMapping(); - + return _mappedFile + 2; } @@ -191,7 +277,7 @@ void LinuxPlatform::commitToEeprom() { if (_fd < 0) doMemoryMapping(); - + fsync(_fd); } @@ -242,69 +328,67 @@ void LinuxPlatform::doMemoryMapping() void LinuxPlatform::closeSpi() { close(_spiFd); - printf ("SPI device closed.\r\n"); + printf("SPI device closed.\r\n"); } -int LinuxPlatform::readWriteSpi (uint8_t *data, size_t len) +int LinuxPlatform::readWriteSpi(uint8_t* data, size_t len) { - uint16_t spiDelay = 0 ; + uint16_t spiDelay = 0; uint32_t spiSpeed = 8000000; // 4 MHz SPI speed - uint8_t spiBPW = 8; // Bits per word + uint8_t spiBPW = 8; // Bits per word - struct spi_ioc_transfer spi ; + struct spi_ioc_transfer spi; // Mentioned in spidev.h but not used in the original kernel documentation // test program )-: - memset (&spi, 0, sizeof (spi)) ; + memset(&spi, 0, sizeof(spi)); - spi.tx_buf = (uint64_t)data; - spi.rx_buf = (uint64_t)data; - spi.len = len; - spi.delay_usecs = spiDelay; - spi.speed_hz = spiSpeed; + spi.tx_buf = (uint64_t)data; + spi.rx_buf = (uint64_t)data; + spi.len = len; + spi.delay_usecs = spiDelay; + spi.speed_hz = spiSpeed; spi.bits_per_word = spiBPW; - return ioctl (_spiFd, SPI_IOC_MESSAGE(1), &spi) ; + return ioctl(_spiFd, SPI_IOC_MESSAGE(1), &spi); } void LinuxPlatform::setupSpi() { - if ((_spiFd = open ("/dev/spidev0.0", O_RDWR)) < 0) + if ((_spiFd = open("/dev/spidev0.0", O_RDWR)) < 0) { - printf ("ERROR: SPI setup failed! Could not open SPI device!\r\n"); + printf("ERROR: SPI setup failed! Could not open SPI device!\r\n"); return; } // Set SPI parameters. - int mode = 0; // Mode 0 - uint8_t spiBPW = 8; // Bits per word + int mode = 0; // Mode 0 + uint8_t spiBPW = 8; // Bits per word int speed = 8000000; // 4 MHz SPI speed - if (ioctl (_spiFd, SPI_IOC_WR_MODE, &mode) < 0) + if (ioctl(_spiFd, SPI_IOC_WR_MODE, &mode) < 0) { - printf ("ERROR: SPI Mode Change failure: %s\n", strerror (errno)) ; + printf("ERROR: SPI Mode Change failure: %s\n", strerror(errno)); close(_spiFd); return; } - if (ioctl (_spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) + if (ioctl(_spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0) { - printf ("ERROR: SPI BPW Change failure: %s\n", strerror (errno)) ; + printf("ERROR: SPI BPW Change failure: %s\n", strerror(errno)); close(_spiFd); return; } - if (ioctl (_spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) + if (ioctl(_spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { - printf ("ERROR: SPI Speed Change failure: %s\n", strerror (errno)) ; + printf("ERROR: SPI Speed Change failure: %s\n", strerror(errno)); close(_spiFd); return; } - printf ("SPI device setup ok.\r\n"); - - + printf("SPI device setup ok.\r\n"); } void LinuxPlatform::flashFilePath(const std::string path) @@ -312,7 +396,6 @@ void LinuxPlatform::flashFilePath(const std::string path) _flashFilePath = path; } - std::string LinuxPlatform::flashFilePath() { return _flashFilePath; @@ -521,13 +604,73 @@ void LinuxPlatform::cmdLineArgs(int argc, char** argv) #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, -} ; +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, +}; /* Activate GPIO-Pin * Write GPIO pin number to /sys/class/gpio/export @@ -535,10 +678,10 @@ static int gpioFds [MAX_NUM_GPIO] = */ 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() */ + 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); @@ -546,7 +689,7 @@ int gpio_export(int pin) if (fd < 0) { perror("Could not export GPIO pin(open)!\n"); - return(-1); + return (-1); } bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin); @@ -555,13 +698,13 @@ int gpio_export(int pin) if (res < 0) { perror("Could not export GPIO pin(write)!\n"); - return(-1); + return (-1); } close(fd); delay(100); - return(0); + return (0); } /* Deactivate GPIO pin @@ -570,10 +713,10 @@ int gpio_export(int pin) */ 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() */ + 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); @@ -583,7 +726,7 @@ int gpio_unexport(int pin) if (fd < 0) { perror("Could not unexport GPIO pin(open)!\n"); - return(-1); + return (-1); } bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin); @@ -592,11 +735,11 @@ int gpio_unexport(int pin) if (res < 0) { perror("Could not unexport GPIO pin(write)!\n"); - return(-1); + return (-1); } close(fd); - return(0); + return (0); } /* Set GPIO pin mode (input/output) @@ -606,35 +749,41 @@ int gpio_unexport(int pin) */ int gpio_direction(int pin, int dir) { - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int fd; /* Filedescriptor */ - int res; /* Result from write() */ + 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"); + fprintf(stderr, "Set GPIO direction for pin %d to %s\n", pin, (dir == INPUT) ? "INPUT" : "OUTPUT"); snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/direction", pin); fd = open(path, O_WRONLY); if (fd < 0) { perror("Could not set mode for GPIO pin(open)!\n"); - return(-1); + return (-1); } switch (dir) { - case INPUT : res = write(fd,"in",2); break; - case OUTPUT: res = write(fd,"out",3); break; - default: res = -1; break; + case INPUT: + res = write(fd, "in", 2); + break; + case OUTPUT: + res = write(fd, "out", 3); + break; + default: + res = -1; + break; } if (res < 0) { perror("Could not set mode for GPIO pin(write)!\n"); - return(-1); + return (-1); } close(fd); - return(0); + return (0); } /* Read from GPIO pin @@ -642,7 +791,7 @@ int gpio_direction(int pin, int dir) */ int gpio_read(int pin) { - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ char c; snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); @@ -651,14 +800,14 @@ int gpio_read(int pin) if (gpioFds[pin] < 0) { perror("Could not read from GPIO(open)!\n"); - return(-1); + return (-1); } - lseek(gpioFds [pin], 0L, SEEK_SET) ; + lseek(gpioFds[pin], 0L, SEEK_SET); if (read(gpioFds[pin], &c, 1) < 0) { perror("Could not read from GPIO(read)!\n"); - return(-1); + return (-1); } return (c == '0') ? LOW : HIGH; @@ -669,8 +818,8 @@ int gpio_read(int pin) */ int gpio_write(int pin, int value) { - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int res; /* Result from write()*/ + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + int res; /* Result from write()*/ snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); if (gpioFds[pin] < 0) @@ -679,23 +828,29 @@ int gpio_write(int pin, int value) if (gpioFds[pin] < 0) { perror("Could not write to GPIO(open)!\n"); - return(-1); + return (-1); } 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; + case LOW: + res = write(gpioFds[pin], "0\n", 2); + break; + case HIGH: + res = write(gpioFds[pin], "1\n", 2); + break; + default: + res = -1; + break; } if (res < 0) { perror("Could not write to GPIO(write)!\n"); - return(-1); + return (-1); } - return(0); + return (0); } /* Set GPIO pin edge detection @@ -705,25 +860,35 @@ int gpio_write(int pin, int value) */ int gpio_edge(unsigned int pin, char edge) { - char path[MAX_STRBUF_SIZE]; /* Buffer for path */ - int fd; /* Filedescriptor */ + char path[MAX_STRBUF_SIZE]; /* Buffer for path */ + int fd; /* Filedescriptor */ snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/edge", pin); - fd = open(path, O_WRONLY | O_NONBLOCK ); + fd = open(path, O_WRONLY | O_NONBLOCK); if (fd < 0) { perror("Could not set GPIO edge detection(open)!\n"); - return(-1); + return (-1); } 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); + 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); } write(fd, path, strlen(path) + 1); @@ -740,19 +905,19 @@ int gpio_edge(unsigned int pin, char edge) */ 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 */ + 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 */ /* Open GPIO pin */ snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin); - fd = open(path, O_RDONLY | O_NONBLOCK ); + fd = open(path, O_RDONLY | O_NONBLOCK); if (fd < 0) { perror("Could not wait for GPIO edge(open)!\n"); - return(-1); + return (-1); } /* prepare poll() */ @@ -770,13 +935,13 @@ int gpio_wait(unsigned int pin, int timeout) { /* poll() failed! */ perror("Could not wait for GPIO edge(poll)!\n"); close(fd); - return(-1); + return (-1); } if (rc == 0) { /* poll() timeout! */ close(fd); - return(0); + return (0); } if (polldat[0].revents & POLLPRI) @@ -785,46 +950,159 @@ int gpio_wait(unsigned int pin, int timeout) { /* read() failed! */ perror("Could not wait for GPIO edge(read)!\n"); close(fd); - return(-2); + return (-2); } /* printf("poll() GPIO %d interrupt occurred: %s\n", pin, buf); */ close(fd); - return(1 + atoi(buf)); + return (1 + atoi(buf)); } close(fd); - return(-1); + return (-1); } -void delayMicrosecondsHard (unsigned int howLong) +void delayMicrosecondsHard(unsigned int howLong) { - struct timeval tNow, tLong, tEnd ; + struct timeval tNow, tLong, tEnd; - gettimeofday (&tNow, NULL) ; - tLong.tv_sec = howLong / 1000000 ; - tLong.tv_usec = howLong % 1000000 ; - timeradd (&tNow, &tLong, &tEnd) ; + gettimeofday(&tNow, NULL); + tLong.tv_sec = howLong / 1000000; + tLong.tv_usec = howLong % 1000000; + timeradd(&tNow, &tLong, &tEnd); - while (timercmp (&tNow, &tEnd, <)) - gettimeofday (&tNow, NULL) ; + while (timercmp(&tNow, &tEnd, <)) + gettimeofday(&tNow, NULL); } -void delayMicroseconds (unsigned int howLong) +void delayMicroseconds(unsigned int howLong) { - struct timespec sleeper ; - unsigned int uSecs = howLong % 1000000 ; - unsigned int wSecs = howLong / 1000000 ; + struct timespec sleeper; + unsigned int uSecs = howLong % 1000000; + unsigned int wSecs = howLong / 1000000; - /**/ if (howLong == 0) - return ; - else if (howLong < 100) - delayMicrosecondsHard (howLong) ; - else - { - sleeper.tv_sec = wSecs ; - sleeper.tv_nsec = (long)(uSecs * 1000L) ; - nanosleep (&sleeper, NULL) ; - } + /**/ if (howLong == 0) + return; + else if (howLong < 100) + delayMicrosecondsHard(howLong); + else + { + sleeper.tv_sec = wSecs; + sleeper.tv_nsec = (long)(uSecs * 1000L); + nanosleep(&sleeper, NULL); + } } #endif + +void LinuxPlatform::setupUniCast(uint32_t addr, uint16_t port, uint8_t type) +{ + if (_unicastSocketFd >= 0) + closeUniCast(); + + _unicastAddr = addr; + _unicastPort = port; + _unicastType = type; + + 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); + + int socketType = 0; + if (type == IPV4_UDP) + socketType = SOCK_DGRAM; + else + socketType = SOCK_STREAM; + + _unicastSocketFd = socket(AF_INET, socketType, 0); + if (_unicastSocketFd == -1) + { + perror("socket()"); + fatalError(); + } + + /* Mehr Prozessen erlauben, denselben Port zu nutzen */ + loop = 1; + if (setsockopt(_unicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0) + { + perror("setsockopt:SO_REUSEADDR"); + fatalError(); + } + + if (bind(_unicastSocketFd, (struct sockaddr*)&sin, sizeof(sin)) < 0) + { + perror("bind"); + fatalError(); + } + + uint32_t flags = fcntl(_unicastSocketFd, F_GETFL); + flags |= O_NONBLOCK; + fcntl(_unicastSocketFd, F_SETFL, flags); +} + +void LinuxPlatform::closeUniCast() +{ + close(_unicastSocketFd); + _unicastSocketFd = -1; +} + +bool LinuxPlatform::sendBytesUniCast(uint8_t* buffer, uint16_t len) +{ + struct sockaddr_in address = {0}; + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(_unicastAddr); + address.sin_port = htons(_unicastPort); + + ssize_t retVal = 0; + do + { + retVal = sendto(_unicastSocketFd, 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; +} + +int LinuxPlatform::readBytesUniCast(uint8_t* buffer, + uint16_t maxLen) +{ + uint32_t sin_len; + struct sockaddr_in sin; + + sin_len = sizeof(sin); + ssize_t len = recvfrom(_unicastSocketFd, buffer, maxLen, 0, (struct sockaddr*)&sin, &sin_len); + // if (len > 0) + // printHex("->", buffer, len); + + return len; +} + +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; +} diff --git a/src/linux_platform.h b/src/linux_platform.h index bbee364..90250b1 100644 --- a/src/linux_platform.h +++ b/src/linux_platform.h @@ -26,11 +26,23 @@ public: void restart() override; void fatalError() override; + // ip config + uint32_t currentIpAddress() override; + uint32_t currentSubnetMask() override; + uint32_t currentDefaultGateway() override; + void macAddress(uint8_t* data) override; + + //multicast void setupMultiCast(uint32_t addr, uint16_t port) override; void closeMultiCast() override; bool sendBytesMultiCast(uint8_t* buffer, uint16_t len) override; int readBytesMultiCast(uint8_t* buffer, uint16_t maxLen) override; + + void setupUniCast(uint32_t addr, uint16_t port, uint8_t type); + void closeUniCast(); + bool sendBytesUniCast(uint8_t* buffer, uint16_t len); + int readBytesUniCast(uint8_t* buffer, uint16_t maxLen); //spi void setupSpi() override; @@ -44,15 +56,25 @@ public: private: uint32_t _multicastAddr = -1; - uint16_t _port = -1; - int _socketFd = -1; + uint16_t _multicastPort = -1; + int _multicastSocketFd = -1; + + uint32_t _unicastAddr = -1; + uint16_t _unicastPort = -1; + int _unicastSocketFd = -1; + uint8_t _unicastType = -1; + void doMemoryMapping(); uint8_t* _mappedFile = 0; int _fd = -1; int _spiFd = -1; - uint8_t* _currentMaxMem = 0; std::string _flashFilePath = "flash.bin"; char** _args = 0; + + uint8_t _macAddress[6] = {0, 0, 0, 0, 0, 0}; + uint32_t _ipAddress = 0; + uint32_t _netmask = 0; + uint32_t _defaultGateway = 0; }; #endif \ No newline at end of file