Skip to content

Commit 740951e

Browse files
Merge pull request COVESA#35 from boschglobal/app/hello-world
Added a hello-world example for Open1722
2 parents 161c3b5 + c96f77d commit 740951e

File tree

4 files changed

+519
-0
lines changed

4 files changed

+519
-0
lines changed

CMakeLists.txt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,16 @@ add_executable(cvf-listener "examples/cvf/cvf-listener.c")
8282
target_include_directories(cvf-listener PRIVATE "examples" "include")
8383
target_link_libraries(cvf-listener open1722 open1722examples)
8484

85+
# Hello-world talker app
86+
add_executable(hello-world-talker "examples/hello-world/hello-world-talker.c")
87+
target_include_directories(hello-world-talker PRIVATE "examples" "include")
88+
target_link_libraries(hello-world-talker open1722 open1722examples)
89+
90+
# Hello-world listener app
91+
add_executable(hello-world-listener "examples/hello-world/hello-world-listener.c")
92+
target_include_directories(hello-world-listener PRIVATE "examples" "include")
93+
target_link_libraries(hello-world-listener open1722 open1722examples)
94+
8595
#### Tests ####################################################################
8696

8797
enable_testing()

examples/hello-world/README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Hello World!
2+
3+
The hello-world applications provide an exemplary set of listener and talker based on the IEEE 1722 protocol.
4+
These applications are based on the Genereal Purpose Control (GPC) subtype of the AVTP Control Formats.
5+
6+
## hello-world-talker
7+
_hello-world-talker_ sends the string "Hello World!" packed in a GPC frame of AVTP Control Format.
8+
The string being sent can be changed using the ```--message``` option.
9+
Options are available to send the IEEE 1722 frame as layer 2 frame or as a UDP segment.
10+
11+
To run over Ethernet
12+
```
13+
$ ./hello-world-talker <Ethernet interface name> <Destination MAC address>
14+
```
15+
16+
To run over UDP
17+
```
18+
$ ./hello-world-talker --udp <destination IP>:<Port>
19+
```
20+
21+
By running wireshark on an appropriate interface, IEEE 1722 frames can be observed.
22+
23+
24+
## hello-world-listener
25+
_hello-world-listener_ receives the message string sent by the talker and prints it out on the console. The listener shall be operated in the same configuration (e.g. layer 2 or UDP) as the talker to ensure compatability.
26+
27+
To run over Ethernet
28+
```
29+
$ ./hello-world-listener <Ethernet interface name>
30+
```
31+
32+
To run over UDP
33+
```
34+
$ ./hello-world-talker --udp <--port=<UDP port>
35+
```
Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
/*
2+
* Copyright (c) 2024, COVESA
3+
*
4+
* Redistribution and use in source and binary forms, with or without
5+
* modification, are permitted provided that the following conditions are met:
6+
*
7+
* * Redistributions of source code must retain the above copyright notice,
8+
* this list of conditions and the following disclaimer.
9+
* * Redistributions in binary form must reproduce the above copyright
10+
* notice, this list of conditions and the following disclaimer in the
11+
* documentation and/or other materials provided with the distribution.
12+
* * Neither the name of COVESA nor the names of its contributors may be
13+
* used to endorse or promote products derived from this software without
14+
* specific prior written permission.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19+
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
20+
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21+
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22+
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23+
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24+
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25+
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26+
*
27+
* SPDX-License-Identifier: BSD-3-Clause
28+
*/
29+
30+
#include <argp.h>
31+
#include <stdlib.h>
32+
#include <linux/if_ether.h>
33+
#include <linux/if_packet.h>
34+
#include <linux/if.h>
35+
#include <stdint.h>
36+
#include <string.h>
37+
#include <unistd.h>
38+
#include <inttypes.h>
39+
40+
#include "common/common.h"
41+
#include "avtp/Udp.h"
42+
#include "avtp/acf/Ntscf.h"
43+
#include "avtp/acf/Tscf.h"
44+
#include "avtp/acf/Common.h"
45+
#include "avtp/acf/Gpc.h"
46+
#include "avtp/CommonHeader.h"
47+
48+
#define MAX_PDU_SIZE 1500
49+
#define MAX_MSG_SIZE 100
50+
51+
static char ifname[IFNAMSIZ];
52+
static uint8_t macaddr[ETH_ALEN];
53+
static uint8_t use_udp;
54+
static uint32_t udp_port = 17220;
55+
56+
static struct argp_option options[] = {
57+
{"port", 'p', "UDP_PORT", 0, "UDP Port to listen on if UDP enabled"},
58+
{"udp", 'u', 0, 0, "Use UDP"},
59+
{"dst-mac-address", 0, 0, OPTION_DOC, "Stream destination MAC address (If Ethernet)"},
60+
{"ifname", 0, 0, OPTION_DOC, "Network interface (If Ethernet)" },
61+
{ 0 }
62+
};
63+
64+
static error_t parser(int key, char *arg, struct argp_state *state)
65+
{
66+
int res;
67+
68+
switch (key) {
69+
case 'p':
70+
udp_port = atoi(arg);
71+
break;
72+
case 'u':
73+
use_udp = 1;
74+
break;
75+
76+
case ARGP_KEY_NO_ARGS:
77+
break;
78+
79+
case ARGP_KEY_ARG:
80+
81+
if(state->argc < 2){
82+
argp_usage(state);
83+
}
84+
85+
if(!use_udp){
86+
87+
strncpy(ifname, arg, sizeof(ifname) - 1);
88+
89+
if(state->next < state->argc)
90+
{
91+
res = sscanf(state->argv[state->next], "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx",
92+
&macaddr[0], &macaddr[1], &macaddr[2],
93+
&macaddr[3], &macaddr[4], &macaddr[5]);
94+
if (res != 6) {
95+
fprintf(stderr, "Invalid MAC address\n\n");
96+
argp_usage(state);
97+
}
98+
state->next += 1;
99+
}
100+
}
101+
102+
break;
103+
}
104+
105+
return 0;
106+
}
107+
108+
static struct argp argp = { options, parser, 0, 0};
109+
110+
int main(int argc, char *argv[])
111+
{
112+
int sk_fd, res;
113+
uint64_t msg_length, proc_bytes = 0, msg_proc_bytes = 0;
114+
uint64_t udp_seq_num, subtype, flag, acf_type, pdu_length;
115+
uint8_t pdu[MAX_PDU_SIZE];
116+
uint8_t *cf_pdu, *acf_pdu, *udp_pdu;
117+
uint64_t gpc_code;
118+
char *recd_msg;
119+
120+
argp_parse(&argp, argc, argv, 0, NULL, NULL);
121+
122+
if (use_udp) {
123+
sk_fd = create_listener_socket_udp(udp_port);
124+
} else {
125+
sk_fd = create_listener_socket(ifname, macaddr, ETH_P_TSN);
126+
}
127+
128+
if (sk_fd < 0)
129+
return 1;
130+
131+
while (1) {
132+
proc_bytes = 0;
133+
134+
res = recv(sk_fd, pdu, MAX_PDU_SIZE, 0);
135+
if (res < 0 || res > MAX_PDU_SIZE) {
136+
perror("Failed to receive data");
137+
goto err;
138+
}
139+
140+
// If UDP is used the packets starts with an encapsulation number
141+
if (use_udp) {
142+
udp_pdu = pdu;
143+
Avtp_Udp_GetField((Avtp_Udp_t *)udp_pdu, AVTP_UDP_FIELD_ENCAPSULATION_SEQ_NO, &udp_seq_num);
144+
cf_pdu = pdu + AVTP_UDP_HEADER_LEN;
145+
proc_bytes += AVTP_UDP_HEADER_LEN;
146+
} else {
147+
cf_pdu = pdu;
148+
}
149+
150+
// Check if the packet is a control format packet (i.e. NTSCF or TSCF)
151+
res = Avtp_CommonHeader_GetField((Avtp_CommonHeader_t*)cf_pdu, AVTP_COMMON_HEADER_FIELD_SUBTYPE, &subtype);
152+
if (res < 0) {
153+
fprintf(stderr, "Failed to get subtype field: %d\n", res);
154+
goto err;
155+
}
156+
if(subtype == AVTP_SUBTYPE_TSCF){
157+
proc_bytes += AVTP_TSCF_HEADER_LEN;
158+
Avtp_Tscf_GetField((Avtp_Tscf_t*)cf_pdu, AVTP_TSCF_FIELD_STREAM_DATA_LENGTH, (uint64_t *) &msg_length);
159+
}else{
160+
proc_bytes += AVTP_NTSCF_HEADER_LEN;
161+
Avtp_Ntscf_GetField((Avtp_Ntscf_t*)cf_pdu, AVTP_NTSCF_FIELD_NTSCF_DATA_LENGTH, (uint64_t *) &msg_length);
162+
}
163+
164+
// Check if the control packet payload is a ACF GPC.
165+
acf_pdu = &pdu[proc_bytes];
166+
Avtp_AcfCommon_GetField((Avtp_AcfCommon_t*)acf_pdu, AVTP_ACF_FIELD_ACF_MSG_TYPE, &acf_type);
167+
if (acf_type != AVTP_ACF_TYPE_GPC) {
168+
fprintf(stderr, "ACF type mismatch: expected %u, got %lu\n",
169+
AVTP_ACF_TYPE_GPC, acf_type);
170+
continue;
171+
}
172+
173+
// Parse the GPC Packet and print contents on the STDOUT
174+
Avtp_Gpc_GetField((Avtp_Gpc_t*)acf_pdu, AVTP_GPC_FIELD_GPC_MSG_ID, &gpc_code);
175+
Avtp_Gpc_GetField((Avtp_Gpc_t*)acf_pdu, AVTP_GPC_FIELD_ACF_MSG_LENGTH, &pdu_length);
176+
if (pdu_length * 4 <= MAX_MSG_SIZE) {
177+
recd_msg = acf_pdu + AVTP_GPC_HEADER_LEN;
178+
printf("%s : GPC Code %ld\n", recd_msg, gpc_code);
179+
}
180+
}
181+
182+
return 0;
183+
184+
err:
185+
close(sk_fd);
186+
return 1;
187+
188+
}

0 commit comments

Comments
 (0)