parent
1078a71fca
commit
56731419b0
@ -0,0 +1,73 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||||
|
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage"> |
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.settings"> |
||||||
|
<cconfiguration id="0.1493500689"> |
||||||
|
<storageModule buildSystemId="org.eclipse.cdt.managedbuilder.core.configurationDataProvider" id="0.1493500689" moduleId="org.eclipse.cdt.core.settings" name="Default"> |
||||||
|
<externalSettings/> |
||||||
|
<extensions> |
||||||
|
<extension id="org.eclipse.cdt.core.GASErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||||
|
<extension id="org.eclipse.cdt.core.GmakeErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||||
|
<extension id="org.eclipse.cdt.core.GLDErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||||
|
<extension id="org.eclipse.cdt.core.VCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||||
|
<extension id="org.eclipse.cdt.core.CWDLocator" point="org.eclipse.cdt.core.ErrorParser"/> |
||||||
|
<extension id="org.eclipse.cdt.core.GCCErrorParser" point="org.eclipse.cdt.core.ErrorParser"/> |
||||||
|
</extensions> |
||||||
|
</storageModule> |
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> |
||||||
|
<configuration buildProperties="" description="" id="0.1493500689" name="Default" parent="org.eclipse.cdt.build.core.prefbase.cfg"> |
||||||
|
<folderInfo id="0.1493500689." name="/" resourcePath=""> |
||||||
|
<toolChain id="org.eclipse.cdt.build.core.prefbase.toolchain.1870777726" name="No ToolChain" resourceTypeBasedDiscovery="false" superClass="org.eclipse.cdt.build.core.prefbase.toolchain"> |
||||||
|
<targetPlatform id="org.eclipse.cdt.build.core.prefbase.toolchain.1870777726.204743302" name=""/> |
||||||
|
<builder id="org.eclipse.cdt.build.core.settings.default.builder.466787059" keepEnvironmentInBuildfile="false" managedBuildOn="false" name="Gnu Make Builder" superClass="org.eclipse.cdt.build.core.settings.default.builder"/> |
||||||
|
<tool id="org.eclipse.cdt.build.core.settings.holder.libs.1222824041" name="holder for library settings" superClass="org.eclipse.cdt.build.core.settings.holder.libs"/> |
||||||
|
<tool id="org.eclipse.cdt.build.core.settings.holder.1644638329" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder"> |
||||||
|
<option id="org.eclipse.cdt.build.core.settings.holder.undef.symbols.113137200" superClass="org.eclipse.cdt.build.core.settings.holder.undef.symbols"/> |
||||||
|
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.776008699" languageId="org.eclipse.cdt.core.assembly" languageName="Assembly" sourceContentType="org.eclipse.cdt.core.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> |
||||||
|
</tool> |
||||||
|
<tool id="org.eclipse.cdt.build.core.settings.holder.2049577207" name="Assembly" superClass="org.eclipse.cdt.build.core.settings.holder"> |
||||||
|
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.982490919" languageId="com.crt.advproject.com.crt.mcu.assembly" languageName="Assembly" sourceContentType="com.crt.advproject.asmSource" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> |
||||||
|
</tool> |
||||||
|
<tool id="org.eclipse.cdt.build.core.settings.holder.1959993364" name="GNU C++" superClass="org.eclipse.cdt.build.core.settings.holder"> |
||||||
|
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.1727849852" languageId="org.eclipse.cdt.core.g++" languageName="GNU C++" sourceContentType="org.eclipse.cdt.core.cxxSource,org.eclipse.cdt.core.cxxHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> |
||||||
|
</tool> |
||||||
|
<tool id="org.eclipse.cdt.build.core.settings.holder.783534498" name="GNU C" superClass="org.eclipse.cdt.build.core.settings.holder"> |
||||||
|
<inputType id="org.eclipse.cdt.build.core.settings.holder.inType.524594272" languageId="org.eclipse.cdt.core.gcc" languageName="GNU C" sourceContentType="org.eclipse.cdt.core.cSource,org.eclipse.cdt.core.cHeader" superClass="org.eclipse.cdt.build.core.settings.holder.inType"/> |
||||||
|
</tool> |
||||||
|
</toolChain> |
||||||
|
</folderInfo> |
||||||
|
</configuration> |
||||||
|
</storageModule> |
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/> |
||||||
|
</cconfiguration> |
||||||
|
</storageModule> |
||||||
|
<storageModule moduleId="cdtBuildSystem" version="4.0.0"> |
||||||
|
<project id="ADIS_Raspi_UDP.null.2080177565" name="ADIS_Raspi_UDP"/> |
||||||
|
</storageModule> |
||||||
|
<storageModule moduleId="scannerConfiguration"> |
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> |
||||||
|
<scannerConfigBuildInfo instanceId="0.1493500689"> |
||||||
|
<autodiscovery enabled="true" problemReportingEnabled="true" selectedProfileId=""/> |
||||||
|
</scannerConfigBuildInfo> |
||||||
|
</storageModule> |
||||||
|
<storageModule moduleId="org.eclipse.cdt.make.core.buildtargets"> |
||||||
|
<buildTargets> |
||||||
|
<target name="all" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> |
||||||
|
<buildCommand>make</buildCommand> |
||||||
|
<buildArguments/> |
||||||
|
<buildTarget>all</buildTarget> |
||||||
|
<stopOnError>true</stopOnError> |
||||||
|
<useDefaultCommand>true</useDefaultCommand> |
||||||
|
<runAllBuilders>true</runAllBuilders> |
||||||
|
</target> |
||||||
|
<target name="clean" path="" targetID="org.eclipse.cdt.build.MakeTargetBuilder"> |
||||||
|
<buildCommand>make</buildCommand> |
||||||
|
<buildArguments/> |
||||||
|
<buildTarget>clean</buildTarget> |
||||||
|
<stopOnError>true</stopOnError> |
||||||
|
<useDefaultCommand>true</useDefaultCommand> |
||||||
|
<runAllBuilders>true</runAllBuilders> |
||||||
|
</target> |
||||||
|
</buildTargets> |
||||||
|
</storageModule> |
||||||
|
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/> |
||||||
|
</cproject> |
||||||
@ -0,0 +1,27 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<projectDescription> |
||||||
|
<name>ADIS_Raspi_UDP</name> |
||||||
|
<comment></comment> |
||||||
|
<projects> |
||||||
|
</projects> |
||||||
|
<buildSpec> |
||||||
|
<buildCommand> |
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name> |
||||||
|
<triggers>clean,full,incremental,</triggers> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
<buildCommand> |
||||||
|
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name> |
||||||
|
<triggers>full,incremental,</triggers> |
||||||
|
<arguments> |
||||||
|
</arguments> |
||||||
|
</buildCommand> |
||||||
|
</buildSpec> |
||||||
|
<natures> |
||||||
|
<nature>org.eclipse.cdt.core.cnature</nature> |
||||||
|
<nature>org.eclipse.cdt.core.ccnature</nature> |
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature> |
||||||
|
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature> |
||||||
|
</natures> |
||||||
|
</projectDescription> |
||||||
@ -0,0 +1,3 @@ |
|||||||
|
*.o |
||||||
|
*.d |
||||||
|
udp_app |
||||||
@ -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" |
||||||
|
|
||||||
@ -0,0 +1,21 @@ |
|||||||
|
/*
|
||||||
|
* delay.c |
||||||
|
* |
||||||
|
* Author: Erich Styger |
||||||
|
* License: PDX-License-Identifier: BSD-3-Clause |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "delay.h" |
||||||
|
#include <unistd.h> /* 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 |
||||||
|
} |
||||||
|
|
||||||
@ -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_ */ |
||||||
@ -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 <linux/gpio.h> |
||||||
|
#include <unistd.h> |
||||||
|
#include <fcntl.h> |
||||||
|
#include <string.h> |
||||||
|
#include <errno.h> |
||||||
|
#include <sys/ioctl.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <stdint.h> |
||||||
|
#include <getopt.h> |
||||||
|
#include <stdlib.h> |
||||||
|
#include <sys/poll.h> |
||||||
|
|
||||||
|
#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; |
||||||
|
} |
||||||
@ -0,0 +1,39 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Erich Styger |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef SRC_GPIO_H_ |
||||||
|
#define SRC_GPIO_H_ |
||||||
|
|
||||||
|
#include <stdbool.h> |
||||||
|
#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_ */ |
||||||
@ -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 <stdio.h> /* printf */ |
||||||
|
#include <string.h> /* memset */ |
||||||
|
#include <stdlib.h> /* for exit(0); */ |
||||||
|
#include <sys/socket.h> |
||||||
|
#include <errno.h> /* For errno - the error number */ |
||||||
|
#include <netdb.h> /* hostent */ |
||||||
|
#include <arpa/inet.h> |
||||||
|
|
||||||
|
/* 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; |
||||||
|
} |
||||||
@ -0,0 +1,15 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Erich Styger |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||||
|
*/ |
||||||
|
|
||||||
|
#ifndef SRC_HOSTNAME_H_ |
||||||
|
#define SRC_HOSTNAME_H_ |
||||||
|
|
||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
/* return for a given hostname the IP address */ |
||||||
|
int hostname_to_ip(const char *hostname, char *ipBuf, size_t ipBufLen); |
||||||
|
|
||||||
|
#endif /* SRC_HOSTNAME_H_ */ |
||||||
@ -0,0 +1,67 @@ |
|||||||
|
/*
|
||||||
|
* main.c |
||||||
|
* |
||||||
|
* Author: Erich Styger |
||||||
|
* License: PDX-License-Identifier: BSD-3-Clause |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "main.h" |
||||||
|
#include <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#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 <server> <port> <txt> : send UDP datagram\n"); |
||||||
|
printf(" --test : test led and navigation switch\n"); |
||||||
|
printf(" --nav <server> <port> : 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; |
||||||
|
} |
||||||
@ -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_ */ |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
/*
|
||||||
|
* Copyright (c) 2022, Erich Styger |
||||||
|
* |
||||||
|
* SPDX-License-Identifier: BSD-3-Clause |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <stdio.h> |
||||||
|
#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"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -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_ */ |
||||||
@ -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 <stdio.h> |
||||||
|
#include <unistd.h> /* 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, <CENTER> 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, <CENTER> 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 */ |
||||||
|
} |
||||||
@ -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_ */ |
||||||
@ -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 <stdlib.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#include <netdb.h> |
||||||
|
#include <sys/socket.h> |
||||||
|
#include <arpa/inet.h> |
||||||
|
#include <unistd.h> |
||||||
|
#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 */ |
||||||
|
} |
||||||
@ -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_ */ |
||||||
Loading…
Reference in new issue