diff --git a/examples/tcp_ipc_client/Kconfig b/examples/tcp_ipc_client/Kconfig new file mode 100644 index 000000000..df7d04e99 --- /dev/null +++ b/examples/tcp_ipc_client/Kconfig @@ -0,0 +1,31 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_TCP_IPC_CLIENT + bool "Client for TCP IPC NuttX" + default n + depends on NET_TCP + depends on NET_SOCKOPTS + select NET_LOOPBACK + ---help--- + Enable the Client for TCP IPC NuttX example + +config EXAMPLES_TCP_IPC_CLIENT_PROGNAME + string "Program name" + default "CLIENT" + depends on EXAMPLES_TCP_IPC_CLIENT + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_TCP_IPC_CLIENT_PRIORITY + int "CLIENT task priority" + default 100 + depends on EXAMPLES_TCP_IPC_CLIENT + +config EXAMPLES_TCP_IPC_CLIENT_STACKSIZE + int "CLIENT stack size" + default 8192 + depends on EXAMPLES_TCP_IPC_CLIENT diff --git a/examples/tcp_ipc_client/Make.defs b/examples/tcp_ipc_client/Make.defs new file mode 100644 index 000000000..6895bf78a --- /dev/null +++ b/examples/tcp_ipc_client/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/hello/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_TCP_IPC_CLIENT),) +CONFIGURED_APPS += $(APPDIR)/examples/tcp_ipc_client +endif diff --git a/examples/tcp_ipc_client/Makefile b/examples/tcp_ipc_client/Makefile new file mode 100644 index 000000000..0356ffa0b --- /dev/null +++ b/examples/tcp_ipc_client/Makefile @@ -0,0 +1,34 @@ +############################################################################ +# apps/examples/CLIENTE/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# CLIENT built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_TCP_IPC_CLIENT_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_TCP_IPC_CLIENT_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_TCP_IPC_CLIENT_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_TCP_IPC_CLIENT) + +# CLIENT Example + +MAINSRC = tcp_ipc_client_main.c + +include $(APPDIR)/Application.mk diff --git a/examples/tcp_ipc_client/README.md b/examples/tcp_ipc_client/README.md new file mode 100644 index 000000000..14710ee6c --- /dev/null +++ b/examples/tcp_ipc_client/README.md @@ -0,0 +1,26 @@ +# Client TCP + +## What's this? + +This program consists of a client socket & custom messages that send data (hex-string formatted data) to a server (tcp_ipc_server). +Then, tcp_ipc_server send this data over LoraWAN (using Radioenge LoRaWAN module). It means using TCP/IP sockets as IPC channel to ensure controlled access to LoRaWAN connectivity. +The goals of using this approach to send LoRaWAN data are: + +* Having a solid and reliable infrastructure to ensure IPC works fine for multiple applications simultaneously +* Having the possibility to host different IoT projects and solutions that use LPWAN in a single ESP32 +* Having the possibility to validate, test and debug multiple IoT projects and solutions at the same time, under the same connectivity conditions (same signal strength, same antenna, same modem/transceiver, etc.) + +Both client and server work on local network scope. + + +## How do I use this? + +In order to test tcp_ipc_client & tcp_ipc_server together, there are two ways to proceed: + +1) Init server manually (command: SERVER &), and after successfull server init, also init client manually (CLIENT 127.0.0.1) +2) init server automatically after boot using NuttShell start up scripts (check: https://nuttx.apache.org/docs/latest/applications/nsh/installation.html#nuttshell-start-up-scripts ) + +## Additional info + +Both tcp_ipc_client and tcp_ipc_server examples have been full covered in NuttX International Workshop 2022. You can watch the full presentation here: https://www.youtube.com/watch?v=hr0OfTt1KeY +The tcp_ipc_server and tcp_ipc_client examples have been developed by Flavio Ipirranga and Pedro Bertoleti from Instituto de Pesquisas Eldorado (IPE) in Brazil. \ No newline at end of file diff --git a/examples/tcp_ipc_client/protocol.h b/examples/tcp_ipc_client/protocol.h new file mode 100644 index 000000000..ecd546bc0 --- /dev/null +++ b/examples/tcp_ipc_client/protocol.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_client/protocol.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_TCP_IPC_CLIENT_PROTOCOL_H +#define __APPS_EXAMPLES_TCP_IPC_CLIENT_PROTOCOL_H + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct +{ + unsigned char opcode; + unsigned char msg_size; + unsigned char msg[12]; +} protocolo_ipc; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void send_msg_to_lpwan (unsigned char *msg, protocolo_ipc *pt_protocol); + +#endif /* __APPS_EXAMPLES_TCP_IPC_CLIENT_PROTOCOL_H */ \ No newline at end of file diff --git a/examples/tcp_ipc_client/tcp_ipc_client_main.c b/examples/tcp_ipc_client/tcp_ipc_client_main.c new file mode 100644 index 000000000..c534f75a9 --- /dev/null +++ b/examples/tcp_ipc_client/tcp_ipc_client_main.c @@ -0,0 +1,201 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_client/tcp_ipc_client_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This program consists of a client socket & custom messages that send + * data (hex-string formatted data) to a server (server_tcp). Then, + * server_tcp send this data over LoraWAN (using Radioenge LoRaWAn module) + * Both client and server work on local network. + * IMPORTANT NOTE: + * In order to test client_tcp & server_tcp together, there are two + * ways to proceed: + * 1) Init server manually (command: SERVER &), and after successfull + * server init, also init client manually (CLIENT 127.0.0.1) + * 2) Init server automatically after boot using NuttShell start up scripts. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void show_usage(FAR const char *progname) +{ + fprintf(stderr, "USAGE: %s \n", progname); + fprintf(stderr, " %s -h\n", progname); + fprintf(stderr, "Where:\n"); + fprintf(stderr, "\t<: IP of server TCP/IP socket for IPC.\n"); +} + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define SOCKET_PORT 5000 +#define TCP_DATA_RCV_WITHOUT_FLAGS 0 +#define RCV_BUFFER_SIZE 520 +#define SEND_BUFFER_SIZE 500 +#define TIME_SECONDS_TO_SEND_NEXT_DATA 15 + +/**************************************************************************** + * Client_tcp_main + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + int socket_client = 0; + char rcv_buffer[RCV_BUFFER_SIZE]; + char buffer_to_send[SEND_BUFFER_SIZE]; + int bytes_read_from_server = 0; + struct sockaddr_in serv_addr; + protocolo_ipc tprotocol; + int ndx; + + /* Check if there are sufficient arguments passed to this program */ + + if (argc != 2) + { + printf("\nNot enough parameters: %s.\n", argv[0]); + return 1; + } + + ndx = 1; + if (strcmp(argv[1], "-h") == 0) + { + show_usage(argv[0]); + return EXIT_FAILURE; + } + + /* Create client socket */ + + memset(rcv_buffer, 0x00, sizeof(rcv_buffer)); + socket_client = socket(AF_INET, SOCK_STREAM, 0); + if (socket_client < 0) + { + perror("Failed to create client socket"); + exit(EXIT_FAILURE); + } + + /* Connect to server socket */ + + memset(&serv_addr, 0x00, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_port = htons(SOCKET_PORT); + + if (inet_pton(AF_INET, argv[1], &serv_addr.sin_addr) <= 0) + { + perror("Failed when executing inet_pton()"); + exit(EXIT_FAILURE); + } + + if (connect(socket_client, (struct sockaddr *)&serv_addr, + sizeof(serv_addr)) < 0) + { + perror("Failed to connect to server socket"); + exit(EXIT_FAILURE); + } + + /* Countinuosly send server data to be forwarded to LPWAN transceiver */ + + while (1) + { + /* Formats message to be sent to server (opcode, message size + * and message content) + */ + + tprotocol.opcode = 'U'; + tprotocol.msg_size = 4; + snprintf((char *)tprotocol.msg, sizeof(tprotocol.msg), "0102"); + + /* Send message to server */ + + memcpy(buffer_to_send, (unsigned char *)&tprotocol, + sizeof(protocolo_ipc)); + write(socket_client, buffer_to_send, strlen(buffer_to_send)); + printf("Message sent to server!\n\n"); + + /* Waits for server response */ + + bytes_read_from_server = recv(socket_client, rcv_buffer, + sizeof(protocolo_ipc), + TCP_DATA_RCV_WITHOUT_FLAGS); + + if (bytes_read_from_server < 0) + { + perror("Failed to get server response"); + exit(EXIT_FAILURE); + } + else + { + /* Server response successfully received. Print it on the screen */ + + memcpy((unsigned char *)&tprotocol, rcv_buffer, + sizeof(protocolo_ipc)); + printf("Protocol: opcode: %c\n", tprotocol.opcode); + printf("Protocol: message size: %d\n", tprotocol.msg_size); + printf("Protocol: message: %s\n", tprotocol.msg); + } + + /* Wait to send again */ + + sleep(TIME_SECONDS_TO_SEND_NEXT_DATA); + } + + return 0; +} diff --git a/examples/tcp_ipc_server/Kconfig b/examples/tcp_ipc_server/Kconfig new file mode 100644 index 000000000..a0a56add7 --- /dev/null +++ b/examples/tcp_ipc_server/Kconfig @@ -0,0 +1,31 @@ +# +# For a description of the syntax of this configuration file, +# see the file kconfig-language.txt in the NuttX tools repository. +# + +config EXAMPLES_TCP_IPC_SERVER + bool "Server for TCP IPC NuttX" + default n + depends on NET_TCP + depends on NET_SOCKOPTS + select NET_LOOPBACK + ---help--- + Enable the TCP SERVER example + +config EXAMPLES_TCP_IPC_SERVER_PROGNAME + string "Program name" + default "SERVER" + depends on EXAMPLES_TCP_IPC_SERVER + ---help--- + This is the name of the program that will be used when the NSH ELF + program is installed. + +config EXAMPLES_TCP_IPC_SERVER_PRIORITY + int "SERVER task priority" + default 100 + depends on EXAMPLES_TCP_IPC_SERVER + +config EXAMPLES_TCP_IPC_SERVER_STACKSIZE + int "SERVER stack size" + default DEFAULT_TASK_STACKSIZE + depends on EXAMPLES_TCP_IPC_SERVER diff --git a/examples/tcp_ipc_server/Make.defs b/examples/tcp_ipc_server/Make.defs new file mode 100644 index 000000000..1089ce849 --- /dev/null +++ b/examples/tcp_ipc_server/Make.defs @@ -0,0 +1,23 @@ +############################################################################ +# apps/examples/hello/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +ifneq ($(CONFIG_EXAMPLES_TCP_IPC_SERVER),) +CONFIGURED_APPS += $(APPDIR)/examples/tcp_ipc_server +endif diff --git a/examples/tcp_ipc_server/Makefile b/examples/tcp_ipc_server/Makefile new file mode 100644 index 000000000..1744d121d --- /dev/null +++ b/examples/tcp_ipc_server/Makefile @@ -0,0 +1,36 @@ +############################################################################ +# apps/examples/SERVIDOR/Make.defs +# +# Licensed to the Apache Software Foundation (ASF) under one or more +# contributor license agreements. See the NOTICE file distributed with +# this work for additional information regarding copyright ownership. The +# ASF licenses this file to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance with the +# License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +############################################################################ + +include $(APPDIR)/Make.defs + +# SERVIDOR built-in application info + +PROGNAME = $(CONFIG_EXAMPLES_TCP_IPC_SERVER_PROGNAME) +PRIORITY = $(CONFIG_EXAMPLES_TCP_IPC_SERVER_PRIORITY) +STACKSIZE = $(CONFIG_EXAMPLES_TCP_IPC_SERVER_STACKSIZE) +MODULE = $(CONFIG_EXAMPLES_TCP_IPC_SERVER) + +# SERVIDOR Example +CFLAGS += ${shell $(INCDIR) "$(CC)" $(APPDIR)/examples/server_tcp/lorawan} +CSRCS = uart_lorawan_layer.c protocol.c + +MAINSRC = tcp_ipc_server_main.c + +include $(APPDIR)/Application.mk diff --git a/examples/tcp_ipc_server/README.md b/examples/tcp_ipc_server/README.md new file mode 100644 index 000000000..97baddd61 --- /dev/null +++ b/examples/tcp_ipc_server/README.md @@ -0,0 +1,28 @@ +# Server TCP + +## What's this? + +This program consists of a server socket & custom messages to establish IPC for multiple applications (client_tcp) and one process that controls LoRaWAN connectivity (server_tcp). +For more details about client side, please see client_tcp example. + +This approach using TCP/IP sockets as IPC channel ensures controlled access to LoRaWAN connectivity. +The goals of using this approach are: + +* Having a solid and reliable infrastructure to ensure IPC works fine for multiple applications simultaneously +* Having the possibility to host different IoT projects and solutions that use LPWAN in a single ESP32 +* Having the possibility to validate, test and debug multiple IoT projects and solutions at the same time, under the same connectivity conditions (same signal strength, same antenna, same modem/transceiver, etc.) + +Both client and server work on local network scope. + + +## How do I use this? + +In order to test client_tcp & server_tcp together, there are two ways to proceed: + +1) Init server manually (command: SERVER &), and after successfull server init, also init client manually (CLIENT 127.0.0.1) +2) init server automatically after boot using NuttShell start up scripts (check: https://nuttx.apache.org/docs/latest/applications/nsh/installation.html#nuttshell-start-up-scripts ) + +## Additional info + +Both client_tcp and server_tcp examples have been full covered in NuttX International Workshop 2022. You can watch the full presentation here: https://www.youtube.com/watch?v=hr0OfTt1KeY +The server_tcp and client_tcp examples have been developed by Flavio Ipirranga and Pedro Bertoleti from Instituto de Pesquisas Eldorado (IPE) in Brazil. \ No newline at end of file diff --git a/examples/tcp_ipc_server/lorawan/uart_lorawan_layer.h b/examples/tcp_ipc_server/lorawan/uart_lorawan_layer.h new file mode 100644 index 000000000..f45053a31 --- /dev/null +++ b/examples/tcp_ipc_server/lorawan/uart_lorawan_layer.h @@ -0,0 +1,57 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_server/lorawan/uart_lorawan_layer.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_TCP_IPC_SERVER_LORAWAN_H +#define __APPS_EXAMPLES_TCP_IPC_SERVER_LORAWAN_H + +/**************************************************************************** + * Definitions + ****************************************************************************/ +#define APP_SESSION_KEY_SIZE 60 +#define NW_SESSION_KEY_SIZE 60 +#define APP_EUI_SIZE 30 +#define DEVICE_ADDRESS_SIZE 15 +#define CHANNEL_MASK_SIZE 35 + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct +{ + char application_session_key[APP_SESSION_KEY_SIZE]; + char network_session_key[NW_SESSION_KEY_SIZE]; + char application_eui[APP_EUI_SIZE]; + char device_address[DEVICE_ADDRESS_SIZE]; + char channel_mask[CHANNEL_MASK_SIZE]; +} config_lorawan_radioenge_t; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void lorawan_radioenge_init(config_lorawan_radioenge_t config_lorawan); +int lorawan_radioenge_send_msg(unsigned char * pt_payload_uplink_hexstring, + int size_uplink, + unsigned char * pt_payload_downlink_hexstring, + int max_size_downlink, + int time_to_wait_ms); + +#endif /* __APPS_EXAMPLES_TCP_IPC_SERVER_LORAWAN_H */ \ No newline at end of file diff --git a/examples/tcp_ipc_server/protocol.c b/examples/tcp_ipc_server/protocol.c new file mode 100644 index 000000000..ec0fe3423 --- /dev/null +++ b/examples/tcp_ipc_server/protocol.c @@ -0,0 +1,117 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_server/protocol.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include "lorawan/uart_lorawan_layer.h" +#include "protocol.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define LORAWAN_DOWNLINK_TIME_MS 10000 +#define MAX_MESSAGE_SIZE 12 +#define SEND_MESSAGE 'U' +#define DOWNLINK_RESPONSE 'D' + +/**************************************************************************** + * Name: send_msg_to_lpwan + * Description: function that parses received message from a client and + * sends a message to UART LoRaWAN layer based on parsed + * data. + * Parameters: - pointer to char array containing received message from + * client + * - pointer to a protocol structure variable, which will contain + * the response to be sent back to client + * Return: nothing + ****************************************************************************/ + +void send_msg_to_lpwan(unsigned char *msg, protocolo_ipc *pt_protocol) +{ + protocolo_ipc tprotocol; + unsigned char buf_recv_downlink[13]; + int bytes_recv = 0; + + memcpy((unsigned char *)&tprotocol, msg, sizeof(protocolo_ipc)); + + /* Parse message accordingly to received opcode */ + + switch (tprotocol.opcode) + { + case SEND_MESSAGE: + /* A client wants to send a LoRaWAN message. Here, the message is + * forwarded to LoRaWAN transceiver + */ + + memset(buf_recv_downlink, 0x00, sizeof(buf_recv_downlink)); + bytes_recv = lorawan_radioenge_send_msg(tprotocol.msg, + tprotocol.msg_size, + buf_recv_downlink, + sizeof(buf_recv_downlink), + LORAWAN_DOWNLINK_TIME_MS); + printf("Number of Downlink bytes received: %d\n\n", bytes_recv); + + if (bytes_recv < MAX_MESSAGE_SIZE) + { + pt_protocol->opcode = DOWNLINK_RESPONSE; + pt_protocol->msg_size = (unsigned char) bytes_recv; + snprintf((char *)pt_protocol->msg, MAX_MESSAGE_SIZE, "%s", + buf_recv_downlink); + } + break; + + default: + break; + } +} diff --git a/examples/tcp_ipc_server/protocol.h b/examples/tcp_ipc_server/protocol.h new file mode 100644 index 000000000..a49cae10e --- /dev/null +++ b/examples/tcp_ipc_server/protocol.h @@ -0,0 +1,41 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_server/protocol.h + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +#ifndef __APPS_EXAMPLES_SERVER_TCP_PROTOCOL_H +#define __APPS_EXAMPLES_SERVER_TCP_PROTOCOL_H + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef struct +{ + unsigned char opcode; + unsigned char msg_size; + unsigned char msg[12]; +} protocolo_ipc; + +/**************************************************************************** + * Public Function Prototypes + ****************************************************************************/ + +void send_msg_to_lpwan (unsigned char *msg, protocolo_ipc *pt_protocol); + +#endif /* __APPS_EXAMPLES_SERVER_TCP_PROTOCOL_H */ \ No newline at end of file diff --git a/examples/tcp_ipc_server/tcp_ipc_server_main.c b/examples/tcp_ipc_server/tcp_ipc_server_main.c new file mode 100644 index 000000000..7f00715c2 --- /dev/null +++ b/examples/tcp_ipc_server/tcp_ipc_server_main.c @@ -0,0 +1,276 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_server/tcp_ipc_server_main.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/* This program consists of a server socket & custom messages to establish + * IPC for multiple applications (clients) and one process that controls + * LoRaWAN connectivity (server). Both client and server work on local + * network. + * For more details about client side, see client-tcp example. + * + * IMPORTANT NOTE: + * In order to test client_tcp & server_tcp together, there are two + * ways to proceed: + * 1) Init server manually (command: SERVER &), and after successfull + * server init, also init client manually (CLIENT 127.0.0.1) + * 2) init server automatically after boot using NuttShell start up scripts. + */ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "protocol.h" +#include "lorawan/uart_lorawan_layer.h" + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +static int socket_clients_counter; + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void *thread_socket_client(void *arg); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define SOCKET_PORT 5000 +#define TX_BUFFER_SIZE 200 +#define RX_BUFFER_SIZE 150 +#define TCP_NO_FLAGS_WHEN_SENDING_DATA 0 +#define IP_SERVER "127.0.0.1" +#define MAX_PENDING_SOCKET_CONNECTIONS 20 +#define TIME_TO_CHECK_FOR_NEW_CLIENTS 500000 + +/**************************************************************************** + * Name: thread_socket_client + * Description: socket client thread. Each sonnected cleint socket will + * instantiate a thread, which handles all data traffic between + * this client and server. + * Parameters: thread arguments (in this case, file descriptor of client + * socket) + * Return: nothing + ****************************************************************************/ + +static void *thread_socket_client(void *arg) +{ + int socket_client_fd = *((int *)arg); + char tx_buffer[TX_BUFFER_SIZE]; + unsigned char rx_buffer[RX_BUFFER_SIZE]; + int bytes_read_from_server = 0; + int ret_send = 0; + protocolo_ipc tprotocol; + + memset(tx_buffer, 0x00, sizeof(tx_buffer)); + memset(rx_buffer, 0x00, sizeof(rx_buffer)); + + while (1) + { + bytes_read_from_server = read(socket_client_fd, + rx_buffer, + RX_BUFFER_SIZE); + + if (bytes_read_from_server == 0) + { + /* Socket disconnection has been detected. + * This thread will be terminated. + */ + + printf("\n\rDisconnection has been detected.\n\r"); + break; + } + else + { + printf("Client request received! Comm. with client...\n"); + send_msg_to_lpwan (rx_buffer, &tprotocol); + if (tprotocol.msg_size >= 0) + { + memcpy(tx_buffer, + (unsigned char *)&tprotocol, + sizeof(protocolo_ipc)); + ret_send = send(socket_client_fd, + tx_buffer, + sizeof(protocolo_ipc), + TCP_NO_FLAGS_WHEN_SENDING_DATA); + + if (ret_send > 0) + { + printf("\r\nSucess: %d bytes sent to client\r\n", + ret_send); + } + else + { + printf("\r\nError: fail to send %d bytes to client\r\n", + strlen(tx_buffer)); + } + } + else + { + printf("ERROR: invalid message size (<0)\n"); + } + } + } + + /* Terminate this thread */ + + close(socket_client_fd); + socket_clients_counter--; + pthread_exit(NULL); +} + +/**************************************************************************** + * Server_tcp_main + ****************************************************************************/ + +int main(int argc, char *argv[]) +{ + int socket_server_fd = 0; + int new_socket_client_fd = 0; + int ret_bind = 0; + struct sockaddr_in server_add; + struct sockaddr_storage server_storage; + socklen_t addr_size; + pthread_t tid[MAX_PENDING_SOCKET_CONNECTIONS]; + config_lorawan_radioenge_t lora_config; + + socket_clients_counter = 0; + + /* Configuring LoRaWAN credentials */ + + snprintf(lora_config.application_session_key, APP_SESSION_KEY_SIZE, + "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"); + snprintf(lora_config.network_session_key, NW_SESSION_KEY_SIZE, + "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00"); + snprintf(lora_config.application_eui, APP_EUI_SIZE, + "00:00:00:00:00:00:00:00"); + snprintf(lora_config.device_address, DEVICE_ADDRESS_SIZE, + "00:00:00:00"); + snprintf(lora_config.channel_mask, CHANNEL_MASK_SIZE, + "00FF:0000:0000:0000:0000:0000"); + lorawan_radioenge_init(lora_config); + + /* Create socket (server) */ + + socket_server_fd = socket(PF_INET, SOCK_STREAM, 0); + if (socket_server_fd == 0) + { + perror("Failed to create server socket"); + exit(EXIT_FAILURE); + } + + /* Fill addr structure and do socket bind operation */ + + server_add.sin_family = AF_INET; + server_add.sin_port = htons(SOCKET_PORT); + server_add.sin_addr.s_addr = inet_addr(IP_SERVER); + memset(server_add.sin_zero, '\0', sizeof server_add.sin_zero); + + ret_bind = bind(socket_server_fd, (struct sockaddr *)&server_add, + sizeof(server_add)); + if (ret_bind < 0) + { + perror("Failed to do socket bind operation"); + exit(EXIT_FAILURE); + } + + /* Initiate listening process for client sockets connection requests. + * The maximum number client sockets pending connection is + * defined by MAX_PENDING_SOCKET_CONNECTIONS + */ + + if (listen(socket_server_fd, MAX_PENDING_SOCKET_CONNECTIONS) == 0) + { + printf("Listening for clients connections...\n"); + } + else + { + perror("Failed to listen for clients connections"); + } + + while (1) + { + /* Wait for a new client socket connection */ + + addr_size = sizeof server_storage; + new_socket_client_fd = accept(socket_server_fd, + (struct sockaddr *)&server_storage, + &addr_size); + + if (new_socket_client_fd < 0) + { + perror("Failed to accept new client socket connection"); + exit(EXIT_FAILURE); + } + + /* For each connected client socket, a new client thread + * is instantiated. + */ + + if (pthread_create(&tid[socket_clients_counter++], NULL, + thread_socket_client, &new_socket_client_fd) != 0) + { + perror("Failed to instantiate a thread for new client socket\n"); + } + + if (socket_clients_counter <= MAX_PENDING_SOCKET_CONNECTIONS) + { + pthread_join(tid[socket_clients_counter++], NULL); + socket_clients_counter++; + } + + usleep(TIME_TO_CHECK_FOR_NEW_CLIENTS); + } + + return 0; +} diff --git a/examples/tcp_ipc_server/uart_lorawan_layer.c b/examples/tcp_ipc_server/uart_lorawan_layer.c new file mode 100644 index 000000000..dae2efa02 --- /dev/null +++ b/examples/tcp_ipc_server/uart_lorawan_layer.c @@ -0,0 +1,493 @@ +/**************************************************************************** + * apps/examples/tcp_ipc_server/uart_lorawan_layer.c + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. The + * ASF licenses this file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "lorawan/uart_lorawan_layer.h" + +/* Useful links: + * + * LoRaWAN module used here: Radioenge LoRaWAN module + * Radioenge LoRaWAN module page: + * https://www.radioenge.com.br/produto/modulo-lorawan/ + * Radioenge LoRaWAN module datasheet: + * https://www.radioenge.com.br/storage/2021/08/Manual_LoRaWAN_Jun2022.pdf + */ + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#ifndef CONFIG_ESP32_UART1 +# error "CONFIG_ESP32_UART1 needs to be defined in order to compile this program." +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static void clear_uart_rx_buffer(void); +static int send_uart_lorawan_at_commands(unsigned char * ptr_at_cmd, + int size_at_cmd); +static int read_uart_lorawan_resp(unsigned char * ptr_response_buffer, + int size_response_buffer, + int time_to_wait_ms); + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Definitions + ****************************************************************************/ + +#define PATH_TO_UART1 "/dev/ttyS1" +#define FULL_AT_CMD_MAX_SIZE 200 +#define TIME_BETWEEN_AT_CMDS 1 //s + +/**************************************************************************** + * Public variables + ****************************************************************************/ + +static int fd_uart = 0; +static bool is_lorawan_busy = false; + +/**************************************************************************** + * Name: clear_uart_rx_buffer + * Description: clean UART RX buffer + * Parameters: nothing + * Return: nothing + ****************************************************************************/ + +static void clear_uart_rx_buffer(void) +{ + char rcv_byte_uart = 0x00; + + if (fd_uart <= -1) + { + /* invalid UART file descriptor */ + + return; + } + else + { + while (read(fd_uart, &rcv_byte_uart, 1) > 0); + } +} + +/**************************************************************************** + * Name: send_uart_lorawan_at_commands + * Description: send AT commands to LoRaWAN module via UART + * Parameters: - pointer to array containing AT command to send + * - AT command size + * Return: number of bytes written to UART + ****************************************************************************/ + +static int send_uart_lorawan_at_commands(unsigned char * ptr_at_cmd, + int size_at_cmd) +{ + int bytes_written_uart = 0; + + if (fd_uart <= -1) + { + /* invalid UART file descriptor */ + + goto END_UART_SEND_AT_CMD; + } + + /* Send AT command to LoRaWAN module */ + + bytes_written_uart = write(fd_uart, ptr_at_cmd, size_at_cmd); + +END_UART_SEND_AT_CMD: + return bytes_written_uart; +} + +/**************************************************************************** + * Name: read_uart_LoRaWAN_AT_command_response + * Description: read AT command response via UART + * Parameters: - pointer to array containing response buffer + * - response buffer size + * - time to wait for UART response + * Return: number of bytes read from UART + ****************************************************************************/ + +static int read_uart_lorawan_resp(unsigned char * ptr_response_buffer, + int size_response_buffer, + int time_to_wait_ms) +{ + int total_bytes_read_uart = 0; + int total_bytes_downlink_msg = 0; + int bytes_read_uart = 0; + bool keep_reading = true; + useconds_t time_to_wait_us = 0; + char full_response[50]; + char *pos_msg_downlink; + + memset(full_response, 0x00, sizeof(full_response)); + + if (fd_uart <= -1) + { + /* invalid UART file descriptor */ + + goto END_UART_READ_AT_CMD; + } + + /* Wait for UART response */ + + time_to_wait_us = time_to_wait_ms * 1000; + usleep(time_to_wait_us); + + do + { + bytes_read_uart = read(fd_uart, + full_response + total_bytes_read_uart, + 1); + + if (bytes_read_uart > 0) + { + ptr_response_buffer++; + total_bytes_read_uart++; + } + else + { + /* No more bytes to read */ + + keep_reading = false; + } + + if (total_bytes_read_uart >= 50) + { + keep_reading = false; + } + } + while (keep_reading == true); + + /* Check if response is a downlink message */ + + pos_msg_downlink = strstr(full_response, "RX:"); + + if (pos_msg_downlink == NULL) + { + total_bytes_downlink_msg = 0; + } + else + { + snprintf((char *)ptr_response_buffer, size_response_buffer, "%s", + pos_msg_downlink + 3); + total_bytes_downlink_msg = strlen((char *)ptr_response_buffer); + } + +END_UART_READ_AT_CMD: + return total_bytes_downlink_msg; +} + +/**************************************************************************** + * Name: LoRaWAN_Radioenge_init + * Description: init LoRaWAN module + * Parameters: LoRaWAN module config structure + * Return: nothing + ****************************************************************************/ + +void lorawan_radioenge_init(config_lorawan_radioenge_t config_lorawan) +{ + int bytes_written_at_cmd = 0; + unsigned char full_at_cmd[FULL_AT_CMD_MAX_SIZE]; + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + + /* Open UART communication with LoRaWAN module */ + + fd_uart = open(PATH_TO_UART1, O_RDWR | O_NONBLOCK); + + if (fd_uart <= -1) + { + perror("Cannot open UART communication with LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + /* Configuration: LoRaWAN channel mask */ + + memset(full_at_cmd, 0x00, FULL_AT_CMD_MAX_SIZE); + snprintf((char *)full_at_cmd, FULL_AT_CMD_MAX_SIZE, "AT+CHMASK=%s\n\r", + config_lorawan.channel_mask); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting Channel Mask to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] Channel mask configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: join mode (ABP) */ + + memset(full_at_cmd, 0x00, FULL_AT_CMD_MAX_SIZE); + snprintf((char *)full_at_cmd, FULL_AT_CMD_MAX_SIZE, "AT+NJM=0\n\r"); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting Join Mode to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] NJM configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: device address */ + + memset(full_at_cmd, 0x00, FULL_AT_CMD_MAX_SIZE); + snprintf((char *)full_at_cmd, FULL_AT_CMD_MAX_SIZE, "AT+DADDR=%s\n\r", + config_lorawan.device_address); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting device address to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] Device address configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: Application EUI */ + + memset(full_at_cmd, 0x00, FULL_AT_CMD_MAX_SIZE); + snprintf((char *)full_at_cmd, FULL_AT_CMD_MAX_SIZE, "AT+APPEUI=%s\n\r", + config_lorawan.application_eui); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting application EUI to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] APP EUI configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: Application Session Key */ + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + snprintf((char *)full_at_cmd, sizeof(full_at_cmd), "AT+APPSKEY=%s\n\r", + config_lorawan.application_session_key); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting application session key" + "to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] APPSKEY configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: Network Session Key */ + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + snprintf((char *)full_at_cmd, sizeof(full_at_cmd), "AT+NWKSKEY=%s\n\r", + config_lorawan.network_session_key); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting network session key" + "to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] NWSKEY configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: ADR */ + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + snprintf((char *)full_at_cmd, sizeof(full_at_cmd), "AT+ADR=0\n\r"); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting ADR configuration to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] ADR configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: DR */ + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + snprintf((char *)full_at_cmd, sizeof(full_at_cmd), "AT+DR=0\n\r"); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting DR configuration to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] DR configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: LoRaWAN class */ + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + snprintf((char *)full_at_cmd, sizeof(full_at_cmd), "AT+CLASS=A\n\r"); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting LoRaWAN class to LoRaWAN module"); + goto END_UART_LORAWAN_MODULE_INIT; + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] LoRaWAN class A configured\r\n"); + clear_uart_rx_buffer(); + + /* Configuration: send confirmation */ + + memset(full_at_cmd, 0x00, sizeof(full_at_cmd)); + snprintf((char *)full_at_cmd, sizeof(full_at_cmd), "AT+CFM=1\n\r"); + bytes_written_at_cmd = send_uart_lorawan_at_commands(full_at_cmd, + strlen((char *)full_at_cmd)); + + if (bytes_written_at_cmd <= 0) + { + perror("Error when writting send confirmation to LoRaWAN module"); + } + + sleep(TIME_BETWEEN_AT_CMDS); + printf("\n\r[LORAWAN] CFM configured\r\n"); + clear_uart_rx_buffer(); + +END_UART_LORAWAN_MODULE_INIT: + return; +} + +/**************************************************************************** + * Name: lorawan_radioenge_send_msg + * Description: send LoRaWAN message with waiting for a downlink message + * Parameters: - pointer to array containing uplink message (in Hex-String + * format) + * - uplink message size + * - pointer to array containing downlink message + * - downlink message array size + * - Time to wait for the downlink message (ms) + * Return: nothing + ****************************************************************************/ + +int lorawan_radioenge_send_msg(unsigned char * pt_uplink_hexstring, + int size_uplink, + unsigned char * pt_downlink_hexstring, + int max_size_downlink, + int time_to_wait_ms) +{ + int bytes_rcv_downlink_message = 0; + unsigned char at_cmd_send_message[FULL_AT_CMD_MAX_SIZE]; + + memset(at_cmd_send_message, 0x00, sizeof(at_cmd_send_message)); + + while (is_lorawan_busy == true); + is_lorawan_busy = true; + + /* Clear RX UART buffer before sending a new command + * (to clean all messages received from previous AT commands + */ + + clear_uart_rx_buffer(); + + /* Compose AT command */ + + snprintf((char *)at_cmd_send_message, + FULL_AT_CMD_MAX_SIZE, + "AT+SENDB=5:%s\n\r", + pt_uplink_hexstring); + printf("\n\r\[LORAWAN] AT CMD: %s\n\r", at_cmd_send_message); + + /* Send uplink message */ + + if (send_uart_lorawan_at_commands(at_cmd_send_message, + strlen((char *)at_cmd_send_message)) <= 0) + { + printf("\n\r\Error when sending uplink message.\n\r"); + goto END_SEND_MSG_WITH_DOWNLINK; + } + + /* Get downlink message */ + + bytes_rcv_downlink_message = read_uart_lorawan_resp(pt_downlink_hexstring, + max_size_downlink, + time_to_wait_ms); + + if (bytes_rcv_downlink_message == 0) + { + printf("\n\rNo downlink message has been received.\n\r"); + } + +END_SEND_MSG_WITH_DOWNLINK: + is_lorawan_busy = false; + return bytes_rcv_downlink_message; +}