knx
ETS configurable knx-stack
linux_platform.cpp
Go to the documentation of this file.
1 #include "linux_platform.h"
2 #ifdef __linux__
3 #include <cstdio>
4 #include <string>
5 #include <cstring>
6 #include <cstdlib>
7 #include <stdexcept>
8 #include <cmath>
9 
10 #include <unistd.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 #include <sys/mman.h>
14 #include <fcntl.h>
15 #include <sys/socket.h>
16 #include <netinet/in.h>
17 #include <arpa/inet.h>
18 #include <sys/ioctl.h>
19 #include <net/if.h>
20 #include <net/if_arp.h>
21 #include <netdb.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <termios.h>
25 
26 #include <sys/ioctl.h> // Needed for SPI port
27 #include <linux/spi/spidev.h> // Needed for SPI port
28 #include <poll.h> // Needed for GPIO edge detection
29 #include <sys/time.h> // Needed for delayMicroseconds()
30 
31 #include "knx/device_object.h"
37 #include "knx/bits.h"
39 
40 #define MAX_MEM 4096
41 
43 {
44  int socketMac = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP);
45 
46  if (socketMac < 0)
47  {
48  printf("Lookup socket creation failed");
49  return;
50  }
51 
52  struct ifreq ifr;
53 
54  struct ifconf ifc;
55 
56  char buf[1024];
57 
58  ifc.ifc_len = sizeof(buf);
59 
60  ifc.ifc_buf = buf;
61 
62  if (ioctl(socketMac, SIOCGIFCONF, &ifc) < 0)
63  return;
64 
65  struct ifreq* it = ifc.ifc_req;
66  const struct ifreq* const end = it + (ifc.ifc_len / sizeof(struct ifreq));
67 
68  for (; it != end; ++it)
69  {
70  strcpy(ifr.ifr_name, it->ifr_name);
71 
72  if (ioctl(socketMac, SIOCGIFFLAGS, &ifr))
73  continue;
74 
75  if (ifr.ifr_flags & IFF_LOOPBACK) // don't count loopback
76  continue;
77 
78  if (ioctl(socketMac, SIOCGIFHWADDR, &ifr))
79  continue;
80 
81  if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
82  continue;
83 
84  memcpy(_macAddress, ifr.ifr_hwaddr.sa_data, IFHWADDRLEN);
85 
86  ioctl(socketMac, SIOCGIFADDR, &ifr);
87 
88  struct sockaddr_in* ipaddr = (struct sockaddr_in*)&ifr.ifr_addr;
89  _ipAddress = ntohl(ipaddr->sin_addr.s_addr);
90 
91  //printf("IP address: %s\n", inet_ntoa(ipaddr->sin_addr));
92  ioctl(socketMac, SIOCGIFNETMASK, &ifr);
93  struct sockaddr_in* netmask = (struct sockaddr_in*)&ifr.ifr_netmask;
94  _netmask = ntohl(netmask->sin_addr.s_addr);
95  //printf("Netmask: %s\n", inet_ntoa(ipaddr->sin_addr));
96  break;
97  }
98 
99  close(socketMac);
100 
101  // default GW
102  FILE* f;
103  char line[100], *p, *c, *g, *saveptr;
104 
105  f = fopen("/proc/net/route", "r");
106 
107  while (fgets(line, 100, f))
108  {
109  p = strtok_r(line, " \t", &saveptr);
110  c = strtok_r(NULL, " \t", &saveptr);
111  g = strtok_r(NULL, " \t", &saveptr);
112 
113  if (p != NULL && c != NULL)
114  {
115  if (strcmp(c, "00000000") == 0)
116  {
117  //printf("Default interface is : %s \n" , p);
118  if (g)
119  {
120  char* pEnd;
121  _defaultGateway = ntohl(strtol(g, &pEnd, 16));
122  }
123 
124  break;
125  }
126  }
127  }
128 
129  fclose(f);
130 }
131 
133 {
134  delete[] _args;
135 }
136 
137 uint32_t millis()
138 {
139  struct timespec spec;
140 
141  clock_gettime(CLOCK_MONOTONIC, &spec);
142  return spec.tv_sec * 1000 + round(spec.tv_nsec / 1.0e6);
143 }
144 
145 void delay(uint32_t millis)
146 {
147  struct timespec ts;
148  ts.tv_sec = millis / 1000;
149  ts.tv_nsec = (millis % 1000) * 1000000;
150  nanosleep(&ts, NULL);
151 }
152 
154 {
155  execv(_args[0], _args);
156 }
157 
159 {
160  printf("A fatal error occured. Stopping.\n");
161 
162  while (true)
163  sleep(1);
164 }
165 
166 void LinuxPlatform::setupMultiCast(uint32_t addr, uint16_t port)
167 {
168  if (_multicastSocketFd >= 0)
169  closeMultiCast();
170 
171  _multicastAddr = addr;
172  _multicastPort = port;
173 
174  struct ip_mreq command;
175  uint32_t loop = 1;
176 
177  struct sockaddr_in sin;
178  memset(&sin, 0, sizeof(sin));
179  sin.sin_family = AF_INET;
180  sin.sin_addr.s_addr = htonl(INADDR_ANY);
181  sin.sin_port = htons(port);
182 
183  _multicastSocketFd = socket(AF_INET, SOCK_DGRAM, 0);
184 
185  if (_multicastSocketFd == -1)
186  {
187  perror("socket()");
188  fatalError();
189  }
190 
191  /* Mehr Prozessen erlauben, denselben Port zu nutzen */
192  loop = 1;
193 
194  if (setsockopt(_multicastSocketFd, SOL_SOCKET, SO_REUSEADDR, &loop, sizeof(loop)) < 0)
195  {
196  perror("setsockopt:SO_REUSEADDR");
197  fatalError();
198  }
199 
200  if (bind(_multicastSocketFd, (struct sockaddr*)&sin, sizeof(sin)) < 0)
201  {
202  perror("bind");
203  fatalError();
204  }
205 
206  /* loopback */
207  loop = 0;
208 
209  if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_MULTICAST_LOOP, &loop, sizeof(loop)) < 0)
210  {
211  perror("setsockopt:IP_MULTICAST_LOOP");
212  fatalError();
213  }
214 
215  /* Join the broadcast group: */
216  command.imr_multiaddr.s_addr = htonl(addr);
217  command.imr_interface.s_addr = htonl(INADDR_ANY);
218 
219  if (setsockopt(_multicastSocketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &command, sizeof(command)) < 0)
220  {
221  perror("setsockopt:IP_ADD_MEMBERSHIP");
222  fatalError();
223  }
224 
225  uint32_t flags = fcntl(_multicastSocketFd, F_GETFL);
226  flags |= O_NONBLOCK;
227  fcntl(_multicastSocketFd, F_SETFL, flags);
228 }
229 
231 {
232  struct ip_mreq command;
233  command.imr_multiaddr.s_addr = htonl(_multicastAddr);
234  command.imr_interface.s_addr = htonl(INADDR_ANY);
235 
236  if (setsockopt(_multicastSocketFd,
237  IPPROTO_IP,
238  IP_DROP_MEMBERSHIP,
239  &command, sizeof(command)) < 0)
240  {
241  perror("setsockopt:IP_DROP_MEMBERSHIP");
242  }
243 
244  close(_multicastSocketFd);
245  _multicastSocketFd = -1;
246 }
247 
248 bool LinuxPlatform::sendBytesMultiCast(uint8_t* buffer, uint16_t len)
249 {
250  struct sockaddr_in address = {0};
251  address.sin_family = AF_INET;
252  address.sin_addr.s_addr = htonl(_multicastAddr);
253  address.sin_port = htons(_multicastPort);
254 
255  ssize_t retVal = 0;
256 
257  do
258  {
259  retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address));
260 
261  if (retVal == -1)
262  {
263  if (errno != EAGAIN && errno != EWOULDBLOCK)
264  return false;
265  }
266  } while (retVal == -1);
267 
268  // printHex("<-", buffer, len);
269  return true;
270 }
271 
272 int LinuxPlatform::readBytesMultiCast(uint8_t* buffer, uint16_t maxLen)
273 {
274  uint32_t sin_len;
275  struct sockaddr_in sin;
276 
277  sin_len = sizeof(sin);
278  ssize_t len = recvfrom(_multicastSocketFd, buffer, maxLen, 0, (struct sockaddr*)&sin, &sin_len);
279  // if (len > 0)
280  // printHex("->", buffer, len);
281 
282  return len;
283 }
284 
285 uint8_t* LinuxPlatform::getEepromBuffer(uint32_t size)
286 {
287  if (_fd < 0)
288  doMemoryMapping();
289 
290  return _mappedFile + 2;
291 }
292 
294 {
295  if (_fd < 0)
296  doMemoryMapping();
297 
298  fsync(_fd);
299 }
300 
301 #define FLASHSIZE 0x10000
302 void LinuxPlatform::doMemoryMapping()
303 {
304  _fd = open(_flashFilePath.c_str(), O_RDWR | O_CREAT, S_IRWXU | S_IRGRP | S_IROTH);
305 
306  if (_fd < 0)
307  {
308  puts("Error in file opening");
309  //exit(-1);
310  }
311 
312  struct stat st;
313 
314  uint32_t ret = fstat(_fd, &st);
315 
316  if (ret < 0)
317  {
318  puts("Error in fstat");
319  //exit(-1);
320  }
321 
322  size_t len_file = st.st_size;
323 
324  if (len_file < FLASHSIZE)
325  {
326  if (ftruncate(_fd, FLASHSIZE) != 0)
327  {
328  puts("Error extending file");
329  //exit(-1);
330  }
331 
332  len_file = FLASHSIZE;
333  }
334 
335  unsigned char* addr = (unsigned char*)mmap(NULL, len_file, PROT_READ | PROT_WRITE, MAP_SHARED, _fd, 0);
336 
337  if (addr[0] != 0xAF || addr[1] != 0xFE)
338  {
339  memset(addr, 0, FLASHSIZE);
340  addr[0] = 0xAF;
341  addr[1] = 0xFE;
342  }
343 
344  if (addr == MAP_FAILED)
345  {
346  puts("Error in mmap");
347  //exit(-1);
348  }
349 
350  _mappedFile = addr;
351 }
352 
354 {
355  close(_spiFd);
356  printf("SPI device closed.\r\n");
357 }
358 
359 int LinuxPlatform::readWriteSpi(uint8_t* data, size_t len)
360 {
361  uint16_t spiDelay = 0;
362  uint32_t spiSpeed = 8000000; // 4 MHz SPI speed
363  uint8_t spiBPW = 8; // Bits per word
364 
365  struct spi_ioc_transfer spi;
366 
367  // Mentioned in spidev.h but not used in the original kernel documentation
368  // test program )-:
369 
370  memset(&spi, 0, sizeof(spi));
371 
372  spi.tx_buf = (uint64_t)data;
373  spi.rx_buf = (uint64_t)data;
374  spi.len = len;
375  spi.delay_usecs = spiDelay;
376  spi.speed_hz = spiSpeed;
377  spi.bits_per_word = spiBPW;
378 
379  return ioctl(_spiFd, SPI_IOC_MESSAGE(1), &spi);
380 }
381 
383 {
384  if ((_spiFd = open("/dev/spidev0.0", O_RDWR)) < 0)
385  {
386  printf("ERROR: SPI setup failed! Could not open SPI device!\r\n");
387  return;
388  }
389 
390  // Set SPI parameters.
391  int mode = 0; // Mode 0
392  uint8_t spiBPW = 8; // Bits per word
393  int speed = 8000000; // 4 MHz SPI speed
394 
395  if (ioctl(_spiFd, SPI_IOC_WR_MODE, &mode) < 0)
396  {
397  printf("ERROR: SPI Mode Change failure: %s\n", strerror(errno));
398  close(_spiFd);
399  return;
400  }
401 
402  if (ioctl(_spiFd, SPI_IOC_WR_BITS_PER_WORD, &spiBPW) < 0)
403  {
404  printf("ERROR: SPI BPW Change failure: %s\n", strerror(errno));
405  close(_spiFd);
406  return;
407  }
408 
409  if (ioctl(_spiFd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0)
410  {
411  printf("ERROR: SPI Speed Change failure: %s\n", strerror(errno));
412  close(_spiFd);
413  return;
414  }
415 
416  printf("SPI device setup ok.\r\n");
417 }
418 
419 void LinuxPlatform::flashFilePath(const std::string path)
420 {
421  _flashFilePath = path;
422 }
423 
425 {
426  return _flashFilePath;
427 }
428 
429 
430 
431 size_t LinuxPlatform::readBytesUart(uint8_t* buffer, size_t length)
432 {
433  return read(_uartFd, buffer, length);
434 }
435 
437 {
438  uint8_t x ;
439 
440  if (read(_uartFd, &x, 1) != 1)
441  {
442  return -1;
443  }
444 
445  return ((int)x) & 0xFF ;
446 }
447 
448 size_t LinuxPlatform::writeUart(const uint8_t* buffer, size_t size)
449 {
450  return write(_uartFd, buffer, size) ;
451 }
452 
453 size_t LinuxPlatform::writeUart(const uint8_t data)
454 {
455  return write(_uartFd, &data, 1) ;
456 }
457 
459 {
460  int result ;
461 
462  if (ioctl(_uartFd, FIONREAD, &result) == -1)
463  {
464  return -1;
465  }
466 
467  return result ;
468 }
469 
471 {
472  if (_uartFd >= 0)
473  {
474  close(_uartFd);
475  }
476 }
477 
479 {
480  /*
481  * 19200,8E1, no handshake
482  */
483  struct termios options; /* Schnittstellenoptionen */
484 
485  /* Port oeffnen - read/write, kein "controlling tty", Status von DCD ignorieren */
486  _uartFd = open("/dev/ttyUSB0", O_RDWR | O_NOCTTY | O_NDELAY);
487 
488  if (_uartFd >= 0)
489  {
490  /* get the current options */
491  fcntl(_uartFd, F_SETFL, 0);
492 
493  if (tcgetattr(_uartFd, &options) != 0)
494  {
495  close(_uartFd);
496  _uartFd = -1;
497  return;
498  }
499 
500  memset(&options, 0, sizeof(options)); /* Structur loeschen, ggf. vorher sichern
501  und bei Programmende wieder restaurieren */
502  /* Baudrate setzen */
503  cfsetispeed(&options, B19200);
504  cfsetospeed(&options, B19200);
505 
506  /* setze Optionen */
507  options.c_cflag |= PARENB; /* Enable Paritybit */
508  options.c_cflag &= ~PARODD; /* Even parity */
509  options.c_cflag &= ~CSTOPB; /* 1 Stoppbit */
510  options.c_cflag &= ~CSIZE; /* 8 Datenbits */
511  options.c_cflag |= CS8;
512 
513  /* 19200 bps, 8 Datenbits, CD-Signal ignorieren, Lesen erlauben */
514  options.c_cflag |= (CLOCAL | CREAD);
515 
516  /* Kein Echo, keine Steuerzeichen, keine Interrupts */
517  options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
518  options.c_iflag = IGNPAR; /* Parity-Fehler ignorieren */
519  options.c_oflag &= ~OPOST; /* setze "raw" Input */
520  options.c_cc[VMIN] = 0; /* warten auf min. 0 Zeichen */
521  options.c_cc[VTIME] = 10; /* Timeout 1 Sekunde */
522  tcflush(_uartFd, TCIOFLUSH); /* Puffer leeren */
523 
524  if (tcsetattr(_uartFd, TCSAFLUSH, &options) != 0)
525  {
526  close(_uartFd);
527  _uartFd = -1;
528  return;
529  }
530  }
531 }
532 
533 #ifndef KNX_NO_PRINT
534 void printUint64(uint64_t value, int base = DEC)
535 {
536  char buf[8 * sizeof(uint64_t) + 1];
537  char* str = &buf[sizeof(buf) - 1];
538  *str = '\0';
539 
540  uint64_t n = value;
541 
542  do
543  {
544  char c = n % base;
545  n /= base;
546 
547  *--str = c < 10 ? c + '0' : c + 'A' - 10;
548  } while (n > 0);
549 
550  print(str);
551 }
552 
553 void print(const char* s)
554 {
555  printf("%s", s);
556 }
557 void print(char c)
558 {
559  printf("%c", c);
560 }
561 
562 void print(unsigned char num)
563 {
564  print(num, DEC);
565 }
566 
567 void print(unsigned char num, int base)
568 {
569  if (base == HEX)
570  printf("%X", num);
571  else
572  printf("%d", num);
573 }
574 
575 void print(int num)
576 {
577  print(num, DEC);
578 }
579 
580 void print(int num, int base)
581 {
582  if (base == HEX)
583  printf("%X", num);
584  else
585  printf("%d", num);
586 }
587 
588 void print(unsigned int num)
589 {
590  print(num, DEC);
591 }
592 
593 void print(unsigned int num, int base)
594 {
595  if (base == HEX)
596  printf("%X", num);
597  else
598  printf("%d", num);
599 }
600 
601 void print(long num)
602 {
603  print(num, DEC);
604 }
605 
606 void print(long num, int base)
607 {
608  if (base == HEX)
609  printf("%lX", num);
610  else
611  printf("%ld", num);
612 }
613 
614 void print(unsigned long num)
615 {
616  print(num, DEC);
617 }
618 
619 void print(unsigned long num, int base)
620 {
621  if (base == HEX)
622  printf("%lX", num);
623  else
624  printf("%ld", num);
625 }
626 
627 void print(unsigned long long num)
628 {
629  printUint64(num);
630 }
631 
632 void print(unsigned long long num, int base)
633 {
634  printUint64(num, base);
635 }
636 
637 void print(double num)
638 {
639  printf("%f", num);
640 }
641 
642 void println(const char* s)
643 {
644  printf("%s\n", s);
645 }
646 void println(char c)
647 {
648  printf("%c\n", c);
649 }
650 
651 void println(unsigned char num)
652 {
653  println(num, DEC);
654 }
655 
656 void println(unsigned char num, int base)
657 {
658  if (base == HEX)
659  printf("%X\n", num);
660  else
661  printf("%d\n", num);
662 }
663 
664 void println(int num)
665 {
666  println(num, DEC);
667 }
668 
669 void println(int num, int base)
670 {
671  if (base == HEX)
672  printf("%X\n", num);
673  else
674  printf("%d\n", num);
675 }
676 
677 void println(unsigned int num)
678 {
679  println(num, DEC);
680 }
681 
682 void println(unsigned int num, int base)
683 {
684  if (base == HEX)
685  printf("%X\n", num);
686  else
687  printf("%d\n", num);
688 }
689 
690 void println(long num)
691 {
692  println(num, DEC);
693 }
694 
695 void println(long num, int base)
696 {
697  if (base == HEX)
698  printf("%lX\n", num);
699  else
700  printf("%ld\n", num);
701 }
702 
703 void println(unsigned long num)
704 {
705  println(num, DEC);
706 }
707 
708 void println(unsigned long num, int base)
709 {
710  if (base == HEX)
711  printf("%lX\n", num);
712  else
713  printf("%ld\n", num);
714 }
715 
716 void println(unsigned long long num)
717 {
718  printUint64(num);
719  println("");
720 }
721 
722 void println(unsigned long long num, int base)
723 {
724  printUint64(num, base);
725  println("");
726 }
727 
728 void println(double num)
729 {
730  printf("%f\n", num);
731 }
732 
733 void println(double num, int places)
734 {
735  printf("%f\n", num);
736 }
737 
738 void println(void)
739 {
740  printf("\n");
741 }
742 #endif // KNX_NO_PRINT
743 
744 void pinMode(uint32_t dwPin, uint32_t dwMode)
745 {
746  gpio_export(dwPin);
747  gpio_direction(dwPin, dwMode);
748 }
749 
750 void digitalWrite(uint32_t dwPin, uint32_t dwVal)
751 {
752  gpio_write(dwPin, dwVal);
753 }
754 
755 uint32_t digitalRead(uint32_t dwPin)
756 {
757  return gpio_read(dwPin);
758 }
759 
760 typedef void (*voidFuncPtr)(void);
761 void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
762 {
763 }
764 
765 void LinuxPlatform::cmdLineArgs(int argc, char** argv)
766 {
767  if (_args)
768  delete[] _args;
769 
770  _args = new char* [argc + 1];
771  memcpy(_args, argv, argc * sizeof(char*));
772  _args[argc] = 0;
773 }
774 
775 /* Buffer size for string operations (e.g. snprintf())*/
776 #define MAX_STRBUF_SIZE 100
777 #define MAX_NUM_GPIO 64
778 
779 static int gpioFds[MAX_NUM_GPIO] =
780 {
781  -1,
782  -1,
783  -1,
784  -1,
785  -1,
786  -1,
787  -1,
788  -1,
789  -1,
790  -1,
791  -1,
792  -1,
793  -1,
794  -1,
795  -1,
796  -1,
797  -1,
798  -1,
799  -1,
800  -1,
801  -1,
802  -1,
803  -1,
804  -1,
805  -1,
806  -1,
807  -1,
808  -1,
809  -1,
810  -1,
811  -1,
812  -1,
813  -1,
814  -1,
815  -1,
816  -1,
817  -1,
818  -1,
819  -1,
820  -1,
821  -1,
822  -1,
823  -1,
824  -1,
825  -1,
826  -1,
827  -1,
828  -1,
829  -1,
830  -1,
831  -1,
832  -1,
833  -1,
834  -1,
835  -1,
836  -1,
837  -1,
838  -1,
839  -1,
840  -1,
841  -1,
842  -1,
843  -1,
844  -1,
845  };
846 
847 /* Activate GPIO-Pin
848  * Write GPIO pin number to /sys/class/gpio/export
849  * Result: 0 = success, -1 = error
850  */
851 int gpio_export(int pin)
852 {
853  char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */
854  ssize_t bytes; /* Used Buffer length */
855  int fd; /* Filedescriptor */
856  int res; /* Result from write() */
857 
858  fprintf(stderr, "Export GPIO pin %d\n", pin);
859 
860  fd = open("/sys/class/gpio/export", O_WRONLY);
861 
862  if (fd < 0)
863  {
864  perror("Could not export GPIO pin(open)!\n");
865  return (-1);
866  }
867 
868  bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin);
869  res = write(fd, buffer, bytes);
870 
871  if (res < 0)
872  {
873  perror("Could not export GPIO pin(write)!\n");
874  return (-1);
875  }
876 
877  close(fd);
878  delay(100);
879 
880  return (0);
881 }
882 
883 /* Deactivate GPIO pin
884  * Write GPIO pin number to /sys/class/gpio/unexport
885  * Result: 0 = success, -1 = error
886  */
887 int gpio_unexport(int pin)
888 {
889  char buffer[MAX_STRBUF_SIZE]; /* Output Buffer */
890  ssize_t bytes; /* Used Buffer length */
891  int fd; /* Filedescriptor */
892  int res; /* Result from write() */
893 
894  fprintf(stderr, "Unexport GPIO pin %d\n", pin);
895 
896  close(gpioFds[pin]);
897 
898  fd = open("/sys/class/gpio/unexport", O_WRONLY);
899 
900  if (fd < 0)
901  {
902  perror("Could not unexport GPIO pin(open)!\n");
903  return (-1);
904  }
905 
906  bytes = snprintf(buffer, MAX_STRBUF_SIZE, "%d", pin);
907  res = write(fd, buffer, bytes);
908 
909  if (res < 0)
910  {
911  perror("Could not unexport GPIO pin(write)!\n");
912  return (-1);
913  }
914 
915  close(fd);
916  return (0);
917 }
918 
919 /* Set GPIO pin mode (input/output)
920  * Write GPIO pin number to /sys/class/gpioXX/direction
921  * Direction: 0 = input, 1 = output
922  * Result: 0 = success, -1 = error
923  */
924 int gpio_direction(int pin, int dir)
925 {
926  char path[MAX_STRBUF_SIZE]; /* Buffer for path */
927  int fd; /* Filedescriptor */
928  int res; /* Result from write() */
929 
930  fprintf(stderr, "Set GPIO direction for pin %d to %s\n", pin, (dir == INPUT) ? "INPUT" : "OUTPUT");
931 
932  snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/direction", pin);
933  fd = open(path, O_WRONLY);
934 
935  if (fd < 0)
936  {
937  perror("Could not set mode for GPIO pin(open)!\n");
938  return (-1);
939  }
940 
941  switch (dir)
942  {
943  case INPUT:
944  res = write(fd, "in", 2);
945  break;
946 
947  case OUTPUT:
948  res = write(fd, "out", 3);
949  break;
950 
951  default:
952  res = -1;
953  break;
954  }
955 
956  if (res < 0)
957  {
958  perror("Could not set mode for GPIO pin(write)!\n");
959  return (-1);
960  }
961 
962  close(fd);
963  return (0);
964 }
965 
966 /* Read from GPIO pin
967  * Result: -1 = error, 0/1 = GPIO pin state
968  */
969 int gpio_read(int pin)
970 {
971  char path[MAX_STRBUF_SIZE]; /* Buffer for path */
972  char c;
973 
974  snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin);
975 
976  if (gpioFds[pin] < 0)
977  gpioFds[pin] = open(path, O_RDWR);
978 
979  if (gpioFds[pin] < 0)
980  {
981  perror("Could not read from GPIO(open)!\n");
982  return (-1);
983  }
984 
985  lseek(gpioFds[pin], 0L, SEEK_SET);
986 
987  if (read(gpioFds[pin], &c, 1) < 0)
988  {
989  perror("Could not read from GPIO(read)!\n");
990  return (-1);
991  }
992 
993  return (c == '0') ? LOW : HIGH;
994 }
995 
996 /* Write to GPIO pin
997  * Result: -1 = error, 0 = success
998  */
999 int gpio_write(int pin, int value)
1000 {
1001  char path[MAX_STRBUF_SIZE]; /* Buffer for path */
1002  int res; /* Result from write()*/
1003 
1004  snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin);
1005 
1006  if (gpioFds[pin] < 0)
1007  gpioFds[pin] = open(path, O_RDWR);
1008 
1009  if (gpioFds[pin] < 0)
1010  {
1011  perror("Could not write to GPIO(open)!\n");
1012  return (-1);
1013  }
1014 
1015  switch (value)
1016  {
1017  case LOW:
1018  res = write(gpioFds[pin], "0\n", 2);
1019  break;
1020 
1021  case HIGH:
1022  res = write(gpioFds[pin], "1\n", 2);
1023  break;
1024 
1025  default:
1026  res = -1;
1027  break;
1028  }
1029 
1030  if (res < 0)
1031  {
1032  perror("Could not write to GPIO(write)!\n");
1033  return (-1);
1034  }
1035 
1036  return (0);
1037 }
1038 
1039 /* Set GPIO pin edge detection
1040  * 'r' (rising)
1041  * 'f' (falling)
1042  * 'b' (both)
1043  */
1044 int gpio_edge(unsigned int pin, char edge)
1045 {
1046  char path[MAX_STRBUF_SIZE]; /* Buffer for path */
1047  int fd; /* Filedescriptor */
1048 
1049  snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/edge", pin);
1050 
1051  fd = open(path, O_WRONLY | O_NONBLOCK);
1052 
1053  if (fd < 0)
1054  {
1055  perror("Could not set GPIO edge detection(open)!\n");
1056  return (-1);
1057  }
1058 
1059  switch (edge)
1060  {
1061  case 'r':
1062  strncpy(path, "rising", 8);
1063  break;
1064 
1065  case 'f':
1066  strncpy(path, "falling", 8);
1067  break;
1068 
1069  case 'b':
1070  strncpy(path, "both", 8);
1071  break;
1072 
1073  case 'n':
1074  strncpy(path, "none", 8);
1075  break;
1076 
1077  default:
1078  close(fd);
1079  return (-2);
1080  }
1081 
1082  write(fd, path, strlen(path) + 1);
1083 
1084  close(fd);
1085  return 0;
1086 }
1087 
1088 /* Wait for edge on GPIO pin
1089  * timeout in milliseconds
1090  * Result: <0: error, 0: poll() Timeout,
1091  * 1: edge detected, GPIO pin reads "0"
1092  * 2: edge detected, GPIO pin reads "1"
1093  */
1094 int gpio_wait(unsigned int pin, int timeout)
1095 {
1096  char path[MAX_STRBUF_SIZE]; /* Buffer for path */
1097  int fd; /* Filedescriptor */
1098  struct pollfd polldat[1]; /* Variable for poll() */
1099  char buf[MAX_STRBUF_SIZE]; /* Read buffer */
1100  int rc; /* Result */
1101 
1102  /* Open GPIO pin */
1103  snprintf(path, MAX_STRBUF_SIZE, "/sys/class/gpio/gpio%d/value", pin);
1104  fd = open(path, O_RDONLY | O_NONBLOCK);
1105 
1106  if (fd < 0)
1107  {
1108  perror("Could not wait for GPIO edge(open)!\n");
1109  return (-1);
1110  }
1111 
1112  /* prepare poll() */
1113  memset((void*)buf, 0, sizeof(buf));
1114  memset((void*)polldat, 0, sizeof(polldat));
1115  polldat[0].fd = fd;
1116  polldat[0].events = POLLPRI;
1117 
1118  /* clear any existing detected edges before */
1119  lseek(fd, 0, SEEK_SET);
1120  rc = read(fd, buf, MAX_STRBUF_SIZE - 1);
1121 
1122  rc = poll(polldat, 1, timeout);
1123 
1124  if (rc < 0)
1125  {
1126  /* poll() failed! */
1127  perror("Could not wait for GPIO edge(poll)!\n");
1128  close(fd);
1129  return (-1);
1130  }
1131 
1132  if (rc == 0)
1133  {
1134  /* poll() timeout! */
1135  close(fd);
1136  return (0);
1137  }
1138 
1139  if (polldat[0].revents & POLLPRI)
1140  {
1141  if (rc < 0)
1142  {
1143  /* read() failed! */
1144  perror("Could not wait for GPIO edge(read)!\n");
1145  close(fd);
1146  return (-2);
1147  }
1148 
1149  /* printf("poll() GPIO %d interrupt occurred: %s\n", pin, buf); */
1150  close(fd);
1151  return (1 + atoi(buf));
1152  }
1153 
1154  close(fd);
1155  return (-1);
1156 }
1157 
1158 void delayMicrosecondsHard(unsigned int howLong)
1159 {
1160  struct timeval tNow, tLong, tEnd;
1161 
1162  gettimeofday(&tNow, NULL);
1163  tLong.tv_sec = howLong / 1000000;
1164  tLong.tv_usec = howLong % 1000000;
1165  timeradd(&tNow, &tLong, &tEnd);
1166 
1167  while (timercmp(&tNow, &tEnd, < ))
1168  gettimeofday(&tNow, NULL);
1169 }
1170 
1171 void delayMicroseconds(unsigned int howLong)
1172 {
1173  struct timespec sleeper;
1174  unsigned int uSecs = howLong % 1000000;
1175  unsigned int wSecs = howLong / 1000000;
1176 
1177  if (howLong == 0)
1178  return;
1179  else if (howLong < 100)
1180  delayMicrosecondsHard(howLong);
1181  else
1182  {
1183  sleeper.tv_sec = wSecs;
1184  sleeper.tv_nsec = (long)(uSecs * 1000L);
1185  nanosleep(&sleeper, NULL);
1186  }
1187 }
1188 
1189 bool LinuxPlatform::sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t* buffer, uint16_t len)
1190 {
1191  struct sockaddr_in address = {0};
1192  address.sin_family = AF_INET;
1193  address.sin_addr.s_addr = htonl(addr);
1194  address.sin_port = htons(port);
1195 
1196  ssize_t retVal = 0;
1197 
1198  do
1199  {
1200  retVal = sendto(_multicastSocketFd, buffer, len, 0, (struct sockaddr*)&address, sizeof(address));
1201 
1202  if (retVal == -1)
1203  {
1204  if (errno != EAGAIN && errno != EWOULDBLOCK)
1205  return false;
1206  }
1207  } while (retVal == -1);
1208 
1209  // printHex("<-", buffer, len);
1210  return true;
1211 }
1212 
1213 void LinuxPlatform::macAddress(uint8_t* mac_address)
1214 {
1215  memcpy(mac_address, _macAddress, IFHWADDRLEN);
1216 }
1217 
1219 {
1220  return _ipAddress;
1221 }
1222 
1224 {
1225  return _netmask;
1226 }
1227 
1229 {
1230  return _defaultGateway;
1231 }
1232 #endif
size_t write(uint8_t c)
void sleep(uint32_t sec)
void closeMultiCast() override
void commitToEeprom() override
int readWriteSpi(uint8_t *data, size_t len) override
void macAddress(uint8_t *data) override
bool sendBytesMultiCast(uint8_t *buffer, uint16_t len) override
void setupMultiCast(uint32_t addr, uint16_t port) override
uint32_t currentDefaultGateway() override
uint32_t currentIpAddress() override
void setupSpi() override
void closeUart() override
void closeSpi() override
int readBytesMultiCast(uint8_t *buffer, uint16_t maxLen) override
void setupUart() override
std::string flashFilePath()
uint32_t currentSubnetMask() override
uint8_t * getEepromBuffer(uint32_t size) override
bool sendBytesUniCast(uint32_t addr, uint16_t port, uint8_t *buffer, uint16_t len) override
void fatalError() override
void cmdLineArgs(int argc, char **argv)
int readUart() override
size_t writeUart(const uint8_t data) override
virtual ~LinuxPlatform()
size_t readBytesUart(uint8_t *buffer, size_t length) override
int uartAvailable() override
void restart() override
void printUint64(uint64_t value, int base=DEC)
int gpio_read(int pin)
void digitalWrite(uint32_t dwPin, uint32_t dwVal)
int gpio_wait(unsigned int pin, int timeout)
int gpio_write(int pin, int value)
void attachInterrupt(uint32_t pin, voidFuncPtr callback, uint32_t mode)
int gpio_export(int pin)
void print(const char *s)
void delayMicrosecondsHard(unsigned int howLong)
int gpio_direction(int pin, int dir)
void println(const char *s)
int gpio_edge(unsigned int pin, char edge)
void pinMode(uint32_t dwPin, uint32_t dwMode)
void delay(uint32_t millis)
uint32_t millis()
int gpio_unexport(int pin)
void delayMicroseconds(unsigned int howLong)
uint32_t digitalRead(uint32_t dwPin)
void(* voidFuncPtr)(void)