From 56731419b094768ea35fcfddf0e68f62bc2929db Mon Sep 17 00:00:00 2001 From: Simon Frei Date: Thu, 10 Nov 2022 13:47:44 +0100 Subject: [PATCH] add project ADIS_Raspi_UDP --- ADIS_Raspi_UDP/.cproject | 73 +++++++ ADIS_Raspi_UDP/.project | 27 +++ ADIS_Raspi_UDP/obj/.gitignore | 3 + ADIS_Raspi_UDP/readme.txt | 7 + ADIS_Raspi_UDP/src/delay.c | 21 +++ ADIS_Raspi_UDP/src/delay.h | 13 ++ ADIS_Raspi_UDP/src/gpio.c | 345 ++++++++++++++++++++++++++++++++++ ADIS_Raspi_UDP/src/gpio.h | 39 ++++ ADIS_Raspi_UDP/src/hostname.c | 36 ++++ ADIS_Raspi_UDP/src/hostname.h | 15 ++ ADIS_Raspi_UDP/src/main.c | 67 +++++++ ADIS_Raspi_UDP/src/main.h | 13 ++ ADIS_Raspi_UDP/src/platform.c | 21 +++ ADIS_Raspi_UDP/src/platform.h | 15 ++ ADIS_Raspi_UDP/src/robotNav.c | 138 ++++++++++++++ ADIS_Raspi_UDP/src/robotNav.h | 19 ++ ADIS_Raspi_UDP/src/udp.c | 148 +++++++++++++++ ADIS_Raspi_UDP/src/udp.h | 15 ++ 18 files changed, 1015 insertions(+) create mode 100644 ADIS_Raspi_UDP/.cproject create mode 100644 ADIS_Raspi_UDP/.project create mode 100644 ADIS_Raspi_UDP/obj/.gitignore create mode 100644 ADIS_Raspi_UDP/readme.txt create mode 100644 ADIS_Raspi_UDP/src/delay.c create mode 100644 ADIS_Raspi_UDP/src/delay.h create mode 100644 ADIS_Raspi_UDP/src/gpio.c create mode 100644 ADIS_Raspi_UDP/src/gpio.h create mode 100644 ADIS_Raspi_UDP/src/hostname.c create mode 100644 ADIS_Raspi_UDP/src/hostname.h create mode 100644 ADIS_Raspi_UDP/src/main.c create mode 100644 ADIS_Raspi_UDP/src/main.h create mode 100644 ADIS_Raspi_UDP/src/platform.c create mode 100644 ADIS_Raspi_UDP/src/platform.h create mode 100644 ADIS_Raspi_UDP/src/robotNav.c create mode 100644 ADIS_Raspi_UDP/src/robotNav.h create mode 100644 ADIS_Raspi_UDP/src/udp.c create mode 100644 ADIS_Raspi_UDP/src/udp.h diff --git a/ADIS_Raspi_UDP/.cproject b/ADIS_Raspi_UDP/.cproject new file mode 100644 index 0000000..07b1efb --- /dev/null +++ b/ADIS_Raspi_UDP/.cproject @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + make + + all + true + true + true + + + make + + clean + true + true + true + + + + + \ No newline at end of file diff --git a/ADIS_Raspi_UDP/.project b/ADIS_Raspi_UDP/.project new file mode 100644 index 0000000..e2759ea --- /dev/null +++ b/ADIS_Raspi_UDP/.project @@ -0,0 +1,27 @@ + + + ADIS_Raspi_UDP + + + + + + org.eclipse.cdt.managedbuilder.core.genmakebuilder + clean,full,incremental, + + + + + org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder + full,incremental, + + + + + + org.eclipse.cdt.core.cnature + org.eclipse.cdt.core.ccnature + org.eclipse.cdt.managedbuilder.core.managedBuildNature + org.eclipse.cdt.managedbuilder.core.ScannerConfigNature + + diff --git a/ADIS_Raspi_UDP/obj/.gitignore b/ADIS_Raspi_UDP/obj/.gitignore new file mode 100644 index 0000000..dae2c78 --- /dev/null +++ b/ADIS_Raspi_UDP/obj/.gitignore @@ -0,0 +1,3 @@ +*.o +*.d +udp_app diff --git a/ADIS_Raspi_UDP/readme.txt b/ADIS_Raspi_UDP/readme.txt new file mode 100644 index 0000000..a593c70 --- /dev/null +++ b/ADIS_Raspi_UDP/readme.txt @@ -0,0 +1,7 @@ +readme.txt +---------- +This project implements a command line client for UDP on the Raspberry Pi. + +Usage example: + ./udp_app --udp tx ESP32DEVKIT02 1234 "cmd rs status" + diff --git a/ADIS_Raspi_UDP/src/delay.c b/ADIS_Raspi_UDP/src/delay.c new file mode 100644 index 0000000..ac15c0d --- /dev/null +++ b/ADIS_Raspi_UDP/src/delay.c @@ -0,0 +1,21 @@ +/* + * delay.c + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#include "delay.h" +#include /* interface to sleep */ + +void delay_ms(unsigned int ms) { + //sleep(1); /* sleep for 1 second */ + usleep(ms*1000); /* sleep for number of microseconds */ +#if 0 + volatile long i; + for(i=0; i<50000000; i++) { + /* burning time */ + } +#endif +} + diff --git a/ADIS_Raspi_UDP/src/delay.h b/ADIS_Raspi_UDP/src/delay.h new file mode 100644 index 0000000..c7d525d --- /dev/null +++ b/ADIS_Raspi_UDP/src/delay.h @@ -0,0 +1,13 @@ +/* + * delay.h + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_DELAY_H_ +#define SRC_DELAY_H_ + +void delay_ms(unsigned int ms); + +#endif /* SRC_DELAY_H_ */ diff --git a/ADIS_Raspi_UDP/src/gpio.c b/ADIS_Raspi_UDP/src/gpio.c new file mode 100644 index 0000000..2480a81 --- /dev/null +++ b/ADIS_Raspi_UDP/src/gpio.c @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2022, Erich Styger + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* see + * https://blog.lxsang.me/post/id/33 + * https://embeddedbits.org/new-linux-kernel-gpio-user-space-interface/ + * https://www.ics.com/blog/gpio-programming-exploring-libgpiod-library + * https://lloydrochester.com/post/hardware/libgpiod-intro-rpi/ + * */ + +#include "gpio.h" + +/* include API header for the new interface */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GPIO_DEV_NAME "/dev/gpiochip0" + +/* HAT v7 requires pull-ups enabled. In case if using older headers, define locally the new flags */ +#ifndef GPIOHANDLE_REQUEST_BIAS_PULL_UP /* supported with latest libs: if not defined, maybe using older header files? Let's assume the library is a recent one */ + #define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5) + #define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6) + #define GPIOHANDLE_REQUEST_BIAS_DISABLE (1UL << 7) +#endif + +typedef struct { + struct gpiohandle_request rq; /* request data structure */ + struct gpiohandle_data data; +} Gpio_Desc_t; + +static Gpio_Desc_t yellowLED, redLED, greenLED; +#if PL_HAT_VERSION<=6 + static Gpio_Desc_t blueLED; +#endif +static Gpio_Desc_t upBTN, downBTN, leftBTN, rightBTN, centerBTN; + +static void gpio_list(const char *dev_name) { + struct gpiochip_info info; + struct gpioline_info line_info; + int fd, ret; + + fd = open(dev_name, O_RDONLY); + if (fd < 0) { + printf("Unabled to open %s: %s", dev_name, strerror(errno)); + return; + } + ret = ioctl(fd, GPIO_GET_CHIPINFO_IOCTL, &info); + if (ret == -1) { + printf("Unable to get chip info from ioctl: %s", strerror(errno)); + close(fd); + return; + } + printf("Chip name: %s\n", info.name); + printf("Chip label: %s\n", info.label); + printf("Number of lines: %d\n", info.lines); + for (int i = 0; i < info.lines; i++) { + line_info.line_offset = i; + ret = ioctl(fd, GPIO_GET_LINEINFO_IOCTL, &line_info); + if (ret == -1) { + printf("Unable to get line info from offset %d: %s", i, strerror(errno)); + } else { + printf("offset: %d, name: %s, consumer: %s. Flags:\t[%s]\t[%s]\t[%s]\t[%s]\t[%s]\t[%s]\t[%s]\t[%s]\n", + i, + line_info.name, + line_info.consumer, + (line_info.flags & GPIOLINE_FLAG_IS_OUT) ? "OUTPUT" : "INPUT", + (line_info.flags & GPIOLINE_FLAG_ACTIVE_LOW) ? "ACTIVE_LOW" : "ACTIVE_HIGHT", + (line_info.flags & GPIOLINE_FLAG_OPEN_DRAIN) ? "OPEN_DRAIN" : "...", + (line_info.flags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) ? "PULL-UP" : "...", + (line_info.flags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) ? "PULL-DOWN" : "...", + (line_info.flags & GPIOHANDLE_REQUEST_BIAS_DISABLE) ? "PULL-DISABLE" : "...", + (line_info.flags & GPIOLINE_FLAG_OPEN_SOURCE) ? "OPENSOURCE" : "...", + (line_info.flags & GPIOLINE_FLAG_KERNEL) ? "KERNEL" : ""); + } + } + close(fd); +} + +static void gpio_write(const char *dev_name, int offset, uint8_t value) { + struct gpiohandle_request rq; + struct gpiohandle_data data; + int fd, ret; + + printf("Write value %d to GPIO at offset %d (OUTPUT mode) on chip %s\n", value, offset, dev_name); + fd = open(dev_name, O_RDONLY); + if (fd < 0) { + printf("Unabled to open %s: %s", dev_name, strerror(errno)); + return; + } + rq.lineoffsets[0] = offset; + rq.flags = GPIOHANDLE_REQUEST_OUTPUT; + rq.lines = 1; + ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &rq); + close(fd); + if (ret == -1) { + printf("Unable to line handle from ioctl : %s", strerror(errno)); + return; + } + data.values[0] = value; + ret = ioctl(rq.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &data); + if (ret == -1) { + printf("Unable to set line value using ioctl : %s", strerror(errno)); + } else { + usleep(2000000); /* wait 2 sec */ + } + close(rq.fd); +} + +static void writePin(Gpio_Desc_t *io, uint8_t value) { + int ret; + + io->data.values[0] = value; + ret = ioctl(io->rq.fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &io->data); + if (ret == -1) { + printf("Unable to set line value using ioctl : %s", strerror(errno)); + } +} + +static bool readPin(Gpio_Desc_t *io) { + int ret; + bool result = false; + + ret = ioctl(io->rq.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &io->data); + if (ret == -1) { + printf("Unable to get line value using ioctl : %s", strerror(errno)); + result = false; + } else { + result = io->data.values[0]!=0; + } + return result; +} + +static int gpio_read(const char *dev_name, int offset) +{ + struct gpiohandle_request rq; + struct gpiohandle_data data; + int fd, ret; + int result = -1; + + fd = open(dev_name, O_RDONLY); + if (fd < 0) + { + printf("Unabled to open %s: %s", dev_name, strerror(errno)); + return -1; + } + rq.lineoffsets[0] = offset; + rq.flags = GPIOHANDLE_REQUEST_INPUT; + rq.lines = 1; + ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &rq); + close(fd); + if (ret == -1) + { + printf("Unable to get line handle from ioctl : %s", strerror(errno)); + return -1; + } + ret = ioctl(rq.fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &data); + if (ret == -1) + { + printf("Unable to get line value using ioctl : %s", strerror(errno)); + result = -1; + } + else + { + printf("Value of GPIO at offset %d (INPUT mode) on chip %s: %d\n", offset, dev_name, data.values[0]); + result = data.values[0]; + } + close(rq.fd); + return result; +} + +static void gpio_poll(const char *dev_name, int offset) +{ + struct gpioevent_request rq; + struct pollfd pfd; + int fd, ret; + + fd = open(dev_name, O_RDONLY); + if (fd < 0) + { + printf("Unabled to open %s: %s", dev_name, strerror(errno)); + return; + } + rq.lineoffset = offset; + rq.eventflags = GPIOEVENT_EVENT_RISING_EDGE; + ret = ioctl(fd, GPIO_GET_LINEEVENT_IOCTL, &rq); + close(fd); + if (ret == -1) + { + printf("Unable to get line event from ioctl : %s", strerror(errno)); + close(fd); + return; + } + pfd.fd = rq.fd; + pfd.events = POLLIN; + ret = poll(&pfd, 1, -1); + if (ret == -1) + { + printf("Error while polling event from GPIO: %s", strerror(errno)); + } + else if (pfd.revents & POLLIN) + { + printf("Rising edge event on GPIO offset: %d, of %s\n", offset, dev_name); + } + close(rq.fd); +} + +bool Gpio_ReadPin(Gpio_Pins_e pin) { + bool val; + //return gpio_read(GPIO_DEV_NAME, pin); + switch(pin) { + case Gpio_Pins_BTN_UP_BCM: + val = readPin(&upBTN); + break; + case Gpio_Pins_BTN_DOWN_BCM: + val = readPin(&downBTN); + break; + case Gpio_Pins_BTN_LEFT_BCM: + val = readPin(&leftBTN); + break; + case Gpio_Pins_BTN_RIGHT_BCM: + val = readPin(&rightBTN); + break; + case Gpio_Pins_BTN_CENTER_BCM: + val = readPin(¢erBTN); + break; + default: + val = false; + break; + } + return val; +} + +void Gpio_WritePin(Gpio_Pins_e pin, bool val) { + switch(pin) { +#if PL_HAT_VERSION<=6 + case Gpio_Pins_LED_BLUE_PIN_BCM: + writePin(&blueLED, val); + break; +#endif + case Gpio_Pins_LED_RED_PIN_BCM: + writePin(&redLED, val); + break; + case Gpio_Pins_LED_GREEN_PIN_BCM: + writePin(&greenLED, val); + break; + case Gpio_Pins_LED_YELLOW_PIN_BCM: + writePin(&yellowLED, val); + break; + + default: + break; + } +} + +int Gpio_Deinit(void) { +#if PL_HAT_VERSION<=6 + close(blueLED.rq.fd); +#endif + close(redLED.rq.fd); + close(greenLED.rq.fd); + close(yellowLED.rq.fd); + + close(upBTN.rq.fd); + close(downBTN.rq.fd); + close(leftBTN.rq.fd); + close(rightBTN.rq.fd); + close(centerBTN.rq.fd); + return 0; +} + +static int RequestPin(Gpio_Desc_t *desc, Gpio_Pins_e pin, int lineRequestFlags, const char *label) { + int fd, ret; + + fd = open(GPIO_DEV_NAME, O_RDONLY); + if (fd < 0) { + printf("Unabled to open %s: %s", GPIO_DEV_NAME, strerror(errno)); + return -1; + } + desc->rq.lineoffsets[0] = pin; + desc->rq.flags = lineRequestFlags; + memcpy(desc->rq.default_values, &desc->data, sizeof(desc->rq.default_values)); + strcpy(desc->rq.consumer_label, label); + desc->rq.lines = 1; + ret = ioctl(fd, GPIO_GET_LINEHANDLE_IOCTL, &desc->rq); + close(fd); + if (ret == -1) { + printf("Unable to get line handle from ioctl : %s", strerror(errno)); + return -1; + } + return 0; +} + +int Gpio_Init(void) { +#if GPIO_HAT_VERSION<=6 + if (RequestPin(&blueLED, Gpio_Pins_LED_BLUE_PIN_BCM, GPIOHANDLE_REQUEST_OUTPUT, "led_blue")!=0) { + return -1; + } +#endif + if (RequestPin(&redLED, Gpio_Pins_LED_RED_PIN_BCM, GPIOHANDLE_REQUEST_OUTPUT, "led_red")!=0) { + return -1; + } + if (RequestPin(&greenLED, Gpio_Pins_LED_GREEN_PIN_BCM, GPIOHANDLE_REQUEST_OUTPUT, "led_green")!=0) { + return -1; + } + + if (RequestPin(&yellowLED, Gpio_Pins_LED_YELLOW_PIN_BCM, GPIOHANDLE_REQUEST_OUTPUT, "led_yellow")!=0) { + return -1; + } + + int inputPinFlags = GPIOHANDLE_REQUEST_INPUT; +#if PL_HAT_VERSION>6 + inputPinFlags |= GPIOHANDLE_REQUEST_BIAS_PULL_UP; +#endif + if (RequestPin(&upBTN, Gpio_Pins_BTN_UP_BCM, inputPinFlags, "button_up")!=0) { + return -1; + } + if (RequestPin(&downBTN, Gpio_Pins_BTN_DOWN_BCM, inputPinFlags, "button_down")!=0) { + return -1; + } + if (RequestPin(&leftBTN, Gpio_Pins_BTN_LEFT_BCM, inputPinFlags, "button_left")!=0) { + return -1; + } + if (RequestPin(&rightBTN, Gpio_Pins_BTN_RIGHT_BCM, inputPinFlags, "button_right")!=0) { + return -1; + } + if (RequestPin(¢erBTN, Gpio_Pins_BTN_CENTER_BCM, inputPinFlags, "button_center")!=0) { + return -1; + } +#if 0 /* testing only */ + gpio_list(GPIO_DEV_NAME); +#endif + return 0; +} diff --git a/ADIS_Raspi_UDP/src/gpio.h b/ADIS_Raspi_UDP/src/gpio.h new file mode 100644 index 0000000..33ccb7e --- /dev/null +++ b/ADIS_Raspi_UDP/src/gpio.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2022, Erich Styger + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_GPIO_H_ +#define SRC_GPIO_H_ + +#include +#include "platform.h" + +/* Pins with the BCM/Broadcom numbers */ +typedef enum { +#if PL_HAT_VERSION<=6 + Gpio_Pins_LED_BLUE_PIN_BCM = 12, /* wPi 26 */ + Gpio_Pins_LED_GREEN_PIN_BCM = 16, /* wPi 27 */ + Gpio_Pins_LED_YELLOW_PIN_BCM = 20, /* wPi 28 */ + Gpio_Pins_LED_RED_PIN_BCM = 21, /* wPi 29 */ +#else + Gpio_Pins_LED_RED_PIN_BCM = 16, /* wPi 27 */ + Gpio_Pins_LED_GREEN_PIN_BCM = 21, /* wPi 29 */ + Gpio_Pins_LED_YELLOW_PIN_BCM = 20, /* wPi 28 */ +#endif + + Gpio_Pins_BTN_UP_BCM = 5, /* wPi 21 */ + Gpio_Pins_BTN_DOWN_BCM = 6, /* wPi 22 */ + Gpio_Pins_BTN_RIGHT_BCM = 13, /* wPi 23 */ + Gpio_Pins_BTN_LEFT_BCM = 19, /* wPi 24 */ + Gpio_Pins_BTN_CENTER_BCM = 26, /* wPi 25 */ +} Gpio_Pins_e; + +bool Gpio_ReadPin(Gpio_Pins_e pin); +void Gpio_WritePin(Gpio_Pins_e pin, bool val); + +int Gpio_Init(void); +int Gpio_Deinit(void); + +#endif /* SRC_GPIO_H_ */ diff --git a/ADIS_Raspi_UDP/src/hostname.c b/ADIS_Raspi_UDP/src/hostname.c new file mode 100644 index 0000000..4f9b634 --- /dev/null +++ b/ADIS_Raspi_UDP/src/hostname.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2021, Erich Styger + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +/* taken from https://www.binarytides.com/hostname-to-ip-address-c-sockets-linux/ */ +#include "hostname.h" /* own interface */ +#include /* printf */ +#include /* memset */ +#include /* for exit(0); */ +#include +#include /* For errno - the error number */ +#include /* hostent */ +#include + +/* Get ip from domain name */ +int hostname_to_ip(const char *hostname, char *ipBuf, size_t ipBufLen) { + struct hostent *he; + struct in_addr **addr_list; + int i; + + if ((he = gethostbyname(hostname)) == NULL) { + /* get the host info */ + herror("gethostbyname"); + return -1; + } + addr_list = (struct in_addr **) he->h_addr_list; + for(i = 0; addr_list[i]!=NULL; i++) { + /* Return the first one */ + strncpy(ipBuf, inet_ntoa(*addr_list[i]), ipBufLen); + ipBuf[ipBufLen-1] = '\0'; /* terminate string */ + return 0; + } + return -1; +} diff --git a/ADIS_Raspi_UDP/src/hostname.h b/ADIS_Raspi_UDP/src/hostname.h new file mode 100644 index 0000000..9c45e02 --- /dev/null +++ b/ADIS_Raspi_UDP/src/hostname.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2021, Erich Styger + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_HOSTNAME_H_ +#define SRC_HOSTNAME_H_ + +#include + +/* return for a given hostname the IP address */ +int hostname_to_ip(const char *hostname, char *ipBuf, size_t ipBufLen); + +#endif /* SRC_HOSTNAME_H_ */ diff --git a/ADIS_Raspi_UDP/src/main.c b/ADIS_Raspi_UDP/src/main.c new file mode 100644 index 0000000..3798abb --- /dev/null +++ b/ADIS_Raspi_UDP/src/main.c @@ -0,0 +1,67 @@ +/* + * main.c + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#include "main.h" +#include +#include +#include +#include "delay.h" +#include "udp.h" +#include "robotNav.h" +#include "platform.h" + +#define VERSION_INFO "v1.2" + +static void printHelp(void) { + printf("Usage:\n"); + printf(" --help : prints this list\n"); + printf(" --udp tx : send UDP datagram\n"); + printf(" --test : test led and navigation switch\n"); + printf(" --nav : navigation with UDP server using joystick\n"); +} + +int main(int argc, char *argv[]) { + int res; + + printf("UDP application, %s, use --help for a list of options\n", VERSION_INFO); + if (argc > 1) { +#if 0 /* debugging only */ + int count; + + printf ("This program was called with \"%s\".\n",argv[0]); + printf("nof arguments: %d\n", argc); + for (count = 1; count < argc; count++) { + printf("nof: %d, argv[%d] = %s\n", argc, count, argv[count]); + } +#endif + } else { + printHelp(); + return 0; + } + + PL_Init(); + if (argc==2 && strcmp(argv[1], "--help")==0) { + printHelp(); + } else if (argc==6 && strcmp(argv[1], "--udp")==0 && strcmp(argv[2], "tx")==0) { + udp_send(argv[3], atoi(argv[4]), argv[5]); + } else if (argc==2 && strcmp(argv[1], "--test")==0) { + res = ROBONAV_Init(); + if (res==0) { + ROBONAV_test(); + ROBONAV_Deinit(); + } + } else if (argc==4 && strcmp(argv[1], "--nav")==0) { + res = ROBONAV_Init(); + if (res==0) { + ROBONAV_navigate(argv[2], atoi(argv[3])); /* pass server and port */ + ROBONAV_Deinit(); + } + } else { /* unknown command */ + printHelp(); + } + return 0; +} diff --git a/ADIS_Raspi_UDP/src/main.h b/ADIS_Raspi_UDP/src/main.h new file mode 100644 index 0000000..ee9bbc7 --- /dev/null +++ b/ADIS_Raspi_UDP/src/main.h @@ -0,0 +1,13 @@ +/* + * main.h + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_MAIN_H_ +#define SRC_MAIN_H_ + +int main(int argc, char *argv[]); + +#endif /* SRC_MAIN_H_ */ diff --git a/ADIS_Raspi_UDP/src/platform.c b/ADIS_Raspi_UDP/src/platform.c new file mode 100644 index 0000000..d450712 --- /dev/null +++ b/ADIS_Raspi_UDP/src/platform.c @@ -0,0 +1,21 @@ +/* + * Copyright (c) 2022, Erich Styger + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include "platform.h" +#include "gpio.h" + +void PL_Deinit(void) { + Gpio_Deinit(); +} + +void PL_Init(void) { + printf("using libgpiod with HAT version %d\n", PL_HAT_VERSION); + if (Gpio_Init()<0) { + printf("failed Gpio_Init()!\n"); + } +} + diff --git a/ADIS_Raspi_UDP/src/platform.h b/ADIS_Raspi_UDP/src/platform.h new file mode 100644 index 0000000..8149a50 --- /dev/null +++ b/ADIS_Raspi_UDP/src/platform.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) 2022, Erich Styger + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_PLATFORM_H_ +#define SRC_PLATFORM_H_ + +#define PL_HAT_VERSION (6) /* HAT version used, e.g. 4, 5, 6 or 7 */ + +void PL_Deinit(void); +void PL_Init(void); + +#endif /* SRC_PLATFORM_H_ */ diff --git a/ADIS_Raspi_UDP/src/robotNav.c b/ADIS_Raspi_UDP/src/robotNav.c new file mode 100644 index 0000000..3b7d27e --- /dev/null +++ b/ADIS_Raspi_UDP/src/robotNav.c @@ -0,0 +1,138 @@ +/* + * robotNav.c + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#include "robotNav.h" +#include "gpio.h" +#include "udp.h" +#include +#include /* interface to sleep */ + +static void BlinkLed(Gpio_Pins_e led) { + Gpio_WritePin(led, true); /* on */ + usleep(100*1000); + Gpio_WritePin(led, false); /* off */ +} + +int ROBONAV_test(void) { + bool buttonPressed; + + printf("Use NAV switch on HAT,
for > 1 sec to exit.\n"); + for(;;) { + buttonPressed = false; + if (Gpio_ReadPin(Gpio_Pins_BTN_LEFT_BCM)==0) { + printf("left\n"); + printf("green\n"); BlinkLed(Gpio_Pins_LED_GREEN_PIN_BCM); + } + if (Gpio_ReadPin(Gpio_Pins_BTN_RIGHT_BCM)==0) { + printf("right\n"); + printf("red\n"); BlinkLed(Gpio_Pins_LED_RED_PIN_BCM); + } + if (Gpio_ReadPin(Gpio_Pins_BTN_UP_BCM)==0) { + printf("up\n"); + printf("blue\n"); BlinkLed(Gpio_Pins_LED_BLUE_PIN_BCM); + } + if (Gpio_ReadPin(Gpio_Pins_BTN_DOWN_BCM)==0) { + printf("down\n"); + printf("yellow\n"); BlinkLed(Gpio_Pins_LED_YELLOW_PIN_BCM); + } + if (Gpio_ReadPin(Gpio_Pins_BTN_CENTER_BCM)==0) { + printf("center\n"); + + int timeMs = 0; + while(Gpio_ReadPin(Gpio_Pins_BTN_CENTER_BCM)==0 && timeMs <= 1000) { + usleep(100*1000); + timeMs += 100; + } + if (Gpio_ReadPin(Gpio_Pins_BTN_CENTER_BCM)==0) { /* still pressed? */ + printf("exit program\n"); + break; /* break for loop and return */ + } + } + usleep(100*1000); + } /* for */ + return 0; /* ok */ +} + +int ROBONAV_navigate(const char *server, int port) { + unsigned int buttons; /* mask of buttons pressed */ + #define BTN_LEFT_MASK (1<<0) + #define BTN_RIGHT_MASK (1<<1) + #define BTN_UP_MASK (1<<2) + #define BTN_DOWN_MASK (1<<3) + #define BTN_CENTER_MASK (1<<4) + #define ALL_BUTTONS_MASK (BTN_LEFT_MASK|BTN_RIGHT_MASK|BTN_UP_MASK|BTN_DOWN_MASK|BTN_CENTER_MASK) + + printf("Use NAV switch on HAT to navigate robot,
for > 1 sec to exit.\n"); + udp_send(server, port, "test"); + for(;;) { + buttons = 0; + if (Gpio_ReadPin(Gpio_Pins_BTN_LEFT_BCM)==0) { + buttons |= BTN_LEFT_MASK; + } + if (Gpio_ReadPin(Gpio_Pins_BTN_RIGHT_BCM)==0) { + buttons |= BTN_RIGHT_MASK; + } + if (Gpio_ReadPin(Gpio_Pins_BTN_UP_BCM)==0) { + buttons |= BTN_UP_MASK; + } + if (Gpio_ReadPin(Gpio_Pins_BTN_DOWN_BCM)==0) { + buttons |= BTN_DOWN_MASK; + } + if (Gpio_ReadPin(Gpio_Pins_BTN_CENTER_BCM)==0) { + buttons |= BTN_CENTER_MASK; + } + if ((buttons&ALL_BUTTONS_MASK)==(BTN_LEFT_MASK|BTN_UP_MASK)) { + printf("left-up\n"); + udp_send(server, port, "nav_left-up"); + } else if ((buttons&ALL_BUTTONS_MASK)==BTN_LEFT_MASK) { + printf("left\n"); + udp_send(server, port, "nav_left"); + } else if ((buttons&ALL_BUTTONS_MASK)==(BTN_RIGHT_MASK|BTN_UP_MASK)) { + printf("right-up\n"); + udp_send(server, port, "nav_right-up"); + } else if ((buttons&ALL_BUTTONS_MASK)==BTN_RIGHT_MASK) { + printf("right\n"); + udp_send(server, port, "nav_right"); + } else if ((buttons&ALL_BUTTONS_MASK)==BTN_UP_MASK) { + printf("up\n"); + udp_send(server, port, "nav_up"); + } else if ((buttons&ALL_BUTTONS_MASK)==(BTN_LEFT_MASK|BTN_DOWN_MASK)) { + printf("left-down\n"); + udp_send(server, port, "nav_down"); + } else if ((buttons&ALL_BUTTONS_MASK)==(BTN_RIGHT_MASK|BTN_DOWN_MASK)) { + printf("left-down\n"); + udp_send(server, port, "nav_down"); + } else if ((buttons&ALL_BUTTONS_MASK)==BTN_DOWN_MASK) { + printf("down\n"); + udp_send(server, port, "nav_down"); + } else if ((buttons&ALL_BUTTONS_MASK)==BTN_CENTER_MASK) { + printf("center\n"); + udp_send(server, port, "nav_center"); + + int timeMs = 0; + while(Gpio_ReadPin(Gpio_Pins_BTN_CENTER_BCM)==0 && timeMs <= 1000) { + usleep(100*1000); + timeMs += 100; + } + if (Gpio_ReadPin(Gpio_Pins_BTN_CENTER_BCM)==0) { /* still pressed? */ + printf("exit program\n"); + udp_send(server, port, "exit"); + break; /* break for loop and return */ + } + } + usleep(100*1000); + } /* for */ + return 0; +} + +int ROBONAV_Init(void) { + return 0; /* ok */ +} + +int ROBONAV_Deinit(void) { + return 0; /* ok */ +} diff --git a/ADIS_Raspi_UDP/src/robotNav.h b/ADIS_Raspi_UDP/src/robotNav.h new file mode 100644 index 0000000..a608cea --- /dev/null +++ b/ADIS_Raspi_UDP/src/robotNav.h @@ -0,0 +1,19 @@ +/* + * robotNav.h + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_ROBOTNAV_H_ +#define SRC_ROBOTNAV_H_ + +int ROBONAV_navigate(const char *server, int port); + +int ROBONAV_test(void); + +int ROBONAV_Deinit(void); + +int ROBONAV_Init(void); + +#endif /* SRC_ROBOTNAV_H_ */ diff --git a/ADIS_Raspi_UDP/src/udp.c b/ADIS_Raspi_UDP/src/udp.c new file mode 100644 index 0000000..6744248 --- /dev/null +++ b/ADIS_Raspi_UDP/src/udp.c @@ -0,0 +1,148 @@ +/* + * udp.c + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + * + * UDP example code by Paul Krzyzanowski, see + * https://www.cs.rutgers.edu/~pxk/417/notes/sockets/udp.html + */ + +#include +#include +#include +#include +#include +#include +#include +#include "hostname.h" +#include "platform.h" + +#define BUFSIZE (64) + +int udp_receive(int port) { + struct sockaddr_in myaddr; /* our address */ + struct sockaddr_in remaddr; /* remote address */ + socklen_t addrlen = sizeof(remaddr); /* length of addresses */ + int recvlen; /* # bytes received */ + int fd; /* our socket */ + int msgcnt = 0; /* count # of messages we received */ + static unsigned char buf[BUFSIZE]; /* receive buffer */ + + /* create a UDP socket */ + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + perror("cannot create socket\n"); + return 0; + } + + /* bind the socket to any valid IP address and a specific port */ + memset((char *)&myaddr, 0, sizeof(myaddr)); + myaddr.sin_family = AF_INET; + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + myaddr.sin_port = htons(port); + + if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { + perror("bind failed"); + return 0; + } + + /* now loop, receiving data and printing what we received */ + for (;;) { + printf("waiting on port %d\n", port); + recvlen = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, &addrlen); + if (recvlen > 0) { + buf[recvlen] = 0; + printf("received message: \"%s\" (%d bytes)\n", buf, recvlen); + } else { + printf("uh oh - something went wrong!\n"); + } + sprintf((char*)buf, "ack %d", msgcnt++); + printf("sending response \"%s\"\n", buf); + if (sendto(fd, buf, strlen((char*)buf), 0, (struct sockaddr *)&remaddr, addrlen) < 0) { + perror("sendto"); + } + } + /* never exits */ +} + + +/* send a UDP datagram. Parameters are strings, e.g. + * host IP, e.g. "10.180.254.51" + * port number, e.g. "1234" + * msg message string to send, e.g. "hello" + * \return negative value in case of failure + */ +int udp_send(const char *host, int port, const char *msg) { + struct sockaddr_in myaddr, remaddr; + int fd, i; + socklen_t slen=sizeof(remaddr); + static char buf[BUFSIZE]; /* message buffer */ + int recvlen; /* # bytes in acknowledgement message */ + int portNumber; + char ipBuf[64]; /* in case 'host' is a hostname and not an IP address, this will hold the IP address */ + + /* hostname to IP transformation */ + if (*host >='0' && *host<='9') { /* IP address */ + printf("IP: %s\n", host); + } else { + if (hostname_to_ip(host, ipBuf, sizeof(ipBuf))==0) { + printf("hostname '%s' -> IP: '%s'\n", host, ipBuf); + host = ipBuf; /* point to transformed IP address */ + } else { + perror("hostname_to_ip() failed"); + return -1; + } + } + + /* create a socket */ + if ((fd=socket(AF_INET, SOCK_DGRAM, 0))==-1) { + printf("socket created\n"); + } + + /* bind it to all local addresses and pick any port number */ + memset((char *)&myaddr, 0, sizeof(myaddr)); + myaddr.sin_family = AF_INET; + myaddr.sin_addr.s_addr = htonl(INADDR_ANY); + myaddr.sin_port = htons(0); + + if (bind(fd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { + perror("bind failed"); + return -1; + } + + /* now define remaddr, the address to whom we want to send messages */ + /* For convenience, the host address is expressed as a numeric IP address */ + /* that we will convert to a binary format via inet_aton */ + memset((char *) &remaddr, 0, sizeof(remaddr)); + remaddr.sin_family = AF_INET; + remaddr.sin_port = htons(port); + if (inet_aton(host, &remaddr.sin_addr)==0) { + fprintf(stderr, "inet_aton() failed\n"); + exit(1); + } + + /* set socket timeout */ + struct timeval tv; + tv.tv_sec = 5; + tv.tv_usec = 0; + if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO,&tv,sizeof(tv)) < 0) { + perror("Error"); + } + /* now let's send the messages */ + printf("Sending datagram '%s' to '%s' on port %d\n", msg, host, port); + if (sendto(fd, msg, strlen(msg), 0, (struct sockaddr *)&remaddr, slen)==-1) { + perror("sendto"); + exit(1); + } + + /* now receive an acknowledgment from the server */ + recvlen = recvfrom(fd, buf, sizeof(buf), 0, (struct sockaddr *)&remaddr, &slen); + if (recvlen >= 0) { + buf[recvlen] = '\0'; /* expect a printable string - terminate it */ + printf("response: \n%s\n", buf); + } else { /* timeout */ + printf("socket receive timeout\n"); + } + close(fd); + return 0; /* ok */ +} diff --git a/ADIS_Raspi_UDP/src/udp.h b/ADIS_Raspi_UDP/src/udp.h new file mode 100644 index 0000000..4f29bbf --- /dev/null +++ b/ADIS_Raspi_UDP/src/udp.h @@ -0,0 +1,15 @@ +/* + * udp.h + * + * Author: Erich Styger + * License: PDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SRC_UDP_H_ +#define SRC_UDP_H_ + +void udp_receive(void); + +int udp_send(const char *server, int port, const char *msg); + +#endif /* SRC_UDP_H_ */