ON Semiconductor / mbed-os

Dependents:   mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mbed_client.c Source File

mbed_client.c

00001 /*
00002  * Copyright (c) 2015 ARM Limited. All rights reserved.
00003  * SPDX-License-Identifier: Apache-2.0
00004  * Licensed under the Apache License, Version 2.0 (the License); you may
00005  * not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  * http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an AS IS BASIS, WITHOUT
00012  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 
00017 #include <arpa/inet.h>
00018 #include <netinet/in.h>
00019 #include <stdio.h>
00020 #include <stdlib.h>
00021 #include <string.h>
00022 #include <sys/socket.h>
00023 #include <signal.h> /* For SIGIGN and SIGINT */
00024 #include <unistd.h>
00025 #include <errno.h>
00026 #include <pthread.h>
00027 #include "sn_nsdl.h"
00028 #include "sn_coap_header.h"
00029 #include "sn_coap_protocol.h"
00030 #include "sn_nsdl_lib.h"
00031 #include "ns_list.h"
00032 #include "sn_grs.h"
00033 #include "arguments.h"
00034 #include "resource_generation_help.h"
00035 
00036 #define BUFLEN 1024
00037 
00038 /* Resource paths and values */
00039 static uint8_t res_manufacturer[] = {"3/0/0"};
00040 static uint8_t res_manufacturer_val[] = {"ARM"};
00041 static uint8_t res_model_number[] = {"3/0/1"};
00042 static uint8_t res_model_number_val[] = {"1.00"};
00043 
00044 static uint8_t res_temp[] = {"3303/0/temp"};
00045 static uint8_t res_type_test[] = {"t"};
00046 
00047 struct thread_data_struct {
00048     struct nsdl_s *handle;
00049     struct sockaddr_in sa_dst;
00050     struct sockaddr_in sa_src;
00051     int sock_server;
00052     socklen_t slen_sa_dst;
00053     int thread_id;
00054     sn_nsdl_ep_parameters_s *endpoint_ptr;
00055     sn_nsdl_addr_s received_packet_address;
00056     ns_list_link_t link;
00057     bool registered;
00058     uint32_t ns_system_time;
00059     uint8_t delayed_token[8];
00060     uint8_t delayed_token_len;
00061     sn_coap_msg_type_e delayed_msg_type;
00062     uint8_t delayed_response_cnt;
00063     uint8_t res_temp_val[16];
00064 };
00065 typedef struct thread_data_struct thread_data_struct_s;
00066 
00067 extern void stop_pgm();
00068 extern void *own_alloc(uint16_t size);
00069 extern void own_free(void* ptr);
00070 
00071 /* Function templates */
00072 int register_endpoint(int port, sn_nsdl_ep_parameters_s *endpoint, int thread_id);
00073 uint8_t tx_function(struct nsdl_s *handle, sn_nsdl_capab_e protocol , uint8_t *data, uint16_t len, sn_nsdl_addr_s *address);
00074 uint8_t rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_header, sn_nsdl_addr_s *address);
00075 static void ctrl_c_handle_function();
00076 typedef void (*signalhandler_t)(int);
00077 void coap_exec_poll_function(int thread_id);
00078 int16_t receive_msg(thread_data_struct_s *data_item, uint8_t *buf);
00079 uint8_t general_resource_cb(struct nsdl_s *handle, sn_coap_hdr_s *coap_ptr, sn_nsdl_addr_s *address, sn_nsdl_capab_e protocol);
00080 int8_t compare_uripaths(sn_coap_hdr_s *coap_header, const uint8_t *uri_path_to_compare);
00081 void send_ack(struct nsdl_s *handle, sn_coap_hdr_s *received_coap_ptr, sn_nsdl_addr_s *address);
00082 
00083 /* CoAP related globals*/
00084 uint8_t text_plain = COAP_CT_TEXT_PLAIN;
00085 uint8_t link_format = COAP_CT_LINK_FORMAT;
00086 
00087 /* Resource related globals*/
00088 uint8_t *reg_location = 0;
00089 int8_t reg_location_len;
00090 
00091 /* List containing thread specific data */
00092 typedef NS_LIST_HEAD(thread_data_struct_s, link) thread_data_struct_t;
00093 static thread_data_struct_t NS_LIST_NAME_INIT(data_list);
00094 
00095 /*****************************************************/
00096 /* This is called from main to start the CoAP server */
00097 /*****************************************************/
00098 int register_endpoint(int port, sn_nsdl_ep_parameters_s *endpoint, int thread_id)
00099 {
00100     printf("Register endpoint, port: %d, thread id: %d\n", port, thread_id);
00101     thread_data_struct_s *data_item = NULL;
00102     uint8_t nsp_addr[16];
00103     pthread_t coap_exec_thread;
00104     uint8_t received_address[4];
00105     uint8_t buf[BUFLEN];
00106     int16_t rcv_size=0;
00107 
00108     data_item = malloc(sizeof(thread_data_struct_s));
00109     data_item->slen_sa_dst = sizeof(data_item->sa_dst);
00110     memset(&data_item->received_packet_address, 0, sizeof(sn_nsdl_addr_s));
00111     memset(&data_item->sa_dst, 0, sizeof(struct sockaddr_in));
00112     memset(&data_item->sa_src, 0, sizeof(struct sockaddr_in));
00113     data_item->received_packet_address.addr_ptr = received_address;
00114     data_item->endpoint_ptr = endpoint;
00115     data_item->registered = false;
00116     data_item->thread_id = thread_id;
00117     data_item->ns_system_time = 1;
00118     data_item->delayed_token_len = 0;
00119     data_item->delayed_response_cnt = 0;
00120 
00121     /* Initial values for temperature */
00122     char temp[10];
00123     if (thread_id >= 9) {
00124         sprintf(temp, "25.%d", thread_id);
00125     } else {
00126         sprintf(temp, "2%d.0", thread_id);
00127     }
00128     strcpy(data_item->res_temp_val,temp);
00129 
00130     sn_nsdl_resource_info_s *resource_ptr = 0;
00131 
00132     if (signal(SIGINT, (signalhandler_t)ctrl_c_handle_function) == SIG_ERR) {
00133         printf("Error with SIGINT: %s\n", strerror(errno));
00134         return -1;
00135     }
00136 
00137     /* Open the server socket*/
00138     if ((data_item->sock_server=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) ==-1 ) {
00139         stop_pgm("socket() error");
00140     }
00141 
00142     /* Init the listen port addr*/
00143     memset((char *) &data_item->sa_src, 0, sizeof(data_item->sa_src));
00144     data_item->sa_src.sin_family = AF_INET;
00145     data_item->sa_src.sin_port = htons(port);
00146 
00147     /* Listen to the port */
00148     data_item->sa_src.sin_addr.s_addr = INADDR_ANY;
00149     if (bind(data_item->sock_server, (struct sockaddr *) &data_item->sa_src, sizeof(data_item->sa_src) ) == -1) {
00150         stop_pgm("bind() error");
00151     }
00152 
00153     data_item->handle = sn_nsdl_init(&tx_function, &rx_function, &own_alloc, &own_free);
00154     inet_pton(AF_INET, arg_dst, &nsp_addr);
00155 
00156     set_NSP_address(data_item->handle, nsp_addr, arg_dport, SN_NSDL_ADDRESS_TYPE_IPV4);
00157     ns_list_add_to_start(&data_list, data_item);
00158 
00159     pthread_create(&coap_exec_thread, NULL, (void *)coap_exec_poll_function, data_item->thread_id);
00160 
00161     resource_ptr = own_alloc(sizeof(sn_nsdl_resource_info_s));
00162     if(!resource_ptr) {
00163         return 0;
00164     }
00165 
00166     memset(resource_ptr, 0, sizeof(sn_nsdl_resource_info_s));
00167     resource_ptr->resource_parameters_ptr = own_alloc(sizeof(sn_nsdl_resource_parameters_s));
00168     if(!resource_ptr->resource_parameters_ptr) {
00169         own_free(resource_ptr);
00170         return 0;
00171     }
00172     memset(resource_ptr->resource_parameters_ptr, 0, sizeof(sn_nsdl_resource_parameters_s));
00173 
00174     /* Create resources */
00175     CREATE_STATIC_RESOURCE(resource_ptr, sizeof(res_manufacturer)-1, (uint8_t*) res_manufacturer, sizeof(res_type_test)-1,
00176                            (uint8_t*)res_type_test,  (uint8_t*) res_manufacturer_val,
00177                            sizeof(res_manufacturer_val)-1, data_item->handle);
00178 
00179     CREATE_STATIC_RESOURCE(resource_ptr, sizeof(res_model_number)-1, (uint8_t*) res_model_number, sizeof(res_type_test)-1,
00180                            (uint8_t*)res_type_test, (uint8_t*) res_model_number_val,
00181                            sizeof(res_model_number_val)-1, data_item->handle);
00182 
00183     CREATE_DYNAMIC_RESOURCE(resource_ptr, sizeof(res_temp)-1, (uint8_t*) res_temp, sizeof(res_type_test)-1,
00184                             (uint8_t*)res_type_test, 0, &general_resource_cb, data_item->handle)
00185 
00186     /* Start registration */
00187     if(sn_nsdl_register_endpoint(data_item->handle, data_item->endpoint_ptr) == SN_NSDL_FAILURE) {
00188         printf("NSP registration failed, thread:%d\n", data_item->thread_id);
00189     }
00190 
00191     /* Free resource_ptr */
00192     if(resource_ptr->resource_parameters_ptr) {
00193         own_free(resource_ptr->resource_parameters_ptr);
00194     }
00195     if(resource_ptr) {
00196         own_free(resource_ptr);
00197     }
00198 
00199     /*              Main loop.              */
00200     /* Listen and process incoming messages */
00201     while (1)
00202     {
00203         usleep(100);
00204         memset(buf, 0, BUFLEN);
00205         rcv_size = receive_msg(data_item,buf);
00206         if(rcv_size > 0) {
00207             sn_nsdl_process_coap(data_item->handle, buf, rcv_size, &data_item->received_packet_address);
00208         }
00209     }
00210     return 0;
00211 }
00212 
00213 int16_t receive_msg(thread_data_struct_s *data_item, uint8_t *buf)
00214 {
00215     char rcv_in_addr[32];
00216     int16_t rcv_size=0;
00217 
00218     memset(rcv_in_addr,0,32);
00219 
00220     if ((rcv_size=recvfrom(data_item->sock_server, buf, BUFLEN, 0,
00221                            (struct sockaddr *)&data_item->sa_dst, (socklen_t*)&data_item->slen_sa_dst))==-1) {
00222         stop_pgm("recvfrom()");
00223     }
00224     else {
00225         inet_ntop(AF_INET, &(data_item->sa_dst.sin_addr),rcv_in_addr,INET_ADDRSTRLEN);
00226         data_item->received_packet_address.port = ntohs(data_item->sa_dst.sin_port);
00227         data_item->received_packet_address.type = SN_NSDL_ADDRESS_TYPE_IPV4;
00228         data_item->received_packet_address.addr_len = 4;
00229         memcpy(data_item->received_packet_address.addr_ptr, &data_item->sa_dst.sin_addr, 4);
00230         printf("\nRX %s.%d [%d B] - thread id: %d\n", rcv_in_addr, ntohs(data_item->sa_dst.sin_port), rcv_size, data_item->thread_id);
00231     }
00232     return rcv_size;
00233 }
00234 
00235 /* Function needed for libCoap protocol. */
00236 uint8_t tx_function(struct nsdl_s *handle, sn_nsdl_capab_e protocol,
00237                     uint8_t *data, uint16_t len, sn_nsdl_addr_s *address)
00238 {
00239     /* Set NSP address and port */
00240     thread_data_struct_s *data_item = NULL;
00241     ns_list_foreach(thread_data_struct_s, item, &data_list) {
00242         if (item->handle == handle) {
00243             data_item = item;
00244             break;
00245         }
00246     }
00247 
00248     if (data_item != NULL) {
00249         printf("TX function - thread id: %d\n", data_item->thread_id);
00250         ns_list_remove(&data_list, data_item);
00251         data_item->sa_dst.sin_family = AF_INET;
00252         data_item->sa_dst.sin_port = htons(address->port);
00253         memcpy(&data_item->sa_dst.sin_addr, address->addr_ptr, address->addr_len);
00254         ns_list_add_to_end(&data_list, data_item);
00255 
00256         int ret = sendto(data_item->sock_server,
00257                          data,
00258                          len,
00259                          0,
00260                          (const struct sockaddr *)&data_item->sa_dst,
00261                          data_item->slen_sa_dst);
00262         if (ret == -1) {
00263             stop_pgm("sendto() failed");
00264         }
00265     }
00266     return 1;
00267 }
00268 
00269 /* RX function for libNsdl. Passes CoAP responses sent from application to this function. Also response to registration message */
00270 uint8_t rx_function(struct nsdl_s *handle, sn_coap_hdr_s *coap_header, sn_nsdl_addr_s *address)
00271 {
00272     if(!coap_header)
00273         return 0;
00274 
00275     thread_data_struct_s *data_item = NULL;
00276     ns_list_foreach(thread_data_struct_s, item, &data_list) {
00277         if (item->handle == handle) {
00278             data_item = item;
00279             break;
00280         }
00281     }
00282     if (!data_item)
00283         return 0;
00284     printf("\nRX callback mid:%d, thread id: %d\n", coap_header->msg_id, data_item->thread_id);
00285 
00286     /* If message is response to NSP registration */
00287     if(coap_header->msg_code == COAP_MSG_CODE_RESPONSE_CREATED &&
00288             !data_item->registered) {
00289         reg_location_len = coap_header->options_list_ptr->location_path_len;
00290         if(reg_location)
00291             free(reg_location);
00292         reg_location = malloc(reg_location_len);
00293 
00294         if(!reg_location) {
00295             return 0;
00296         }
00297 
00298         memcpy(reg_location, coap_header->options_list_ptr->location_path_ptr, reg_location_len);
00299         printf("Registered to NSP: ");
00300         for(int i = 0; i < reg_location_len; i++)
00301             printf("%c", *(reg_location+i));
00302         printf("\n");
00303 
00304         data_item->registered = true;
00305     }
00306     return 0;
00307 }
00308 
00309 static void ctrl_c_handle_function()
00310 {
00311     printf("Pressed ctrl-c\n");
00312     ns_list_foreach(thread_data_struct_s, item, &data_list) {
00313         if (item->handle) {
00314             sn_nsdl_unregister_endpoint(item->handle);
00315         }
00316     }
00317     if(reg_location)
00318         own_free(reg_location);
00319     exit(1);
00320 }
00321 
00322 void coap_exec_poll_function(int thread_id)
00323 {
00324     uint8_t i = 0;
00325     sn_coap_hdr_s coap_header;
00326 
00327     while(1)
00328     {
00329         sleep(1);
00330         thread_data_struct_s *data_item = NULL;
00331         ns_list_foreach(thread_data_struct_s, item, &data_list) {
00332             if (item->thread_id == thread_id) {
00333                 data_item = item;
00334                 break;
00335             }
00336         }
00337         if (data_item) {
00338             /* nsdl execution function, must be called at least once / second. System time must be increased every second. */
00339             /* Cleans saved and unused data from libraries. Recommend to run this in same thread with other nsdl - functions */
00340             sn_nsdl_exec(data_item->handle, data_item->ns_system_time);
00341             data_item->ns_system_time++;
00342 
00343             /* Check if reregistration needed */
00344             if(!(data_item->ns_system_time % (uint32_t)30) && data_item->ns_system_time)
00345             {
00346                 printf("Update registration - thread id: %d\n", data_item->thread_id);
00347                 sn_nsdl_update_registration(data_item->handle, data_item->endpoint_ptr->lifetime_ptr, data_item->endpoint_ptr->lifetime_len);
00348             }
00349 
00350             /* Send delayed response to request */
00351             /* This is just example. When receiving request to sen/temp, application send ack and after few seconds value for this resource */
00352             if(data_item->delayed_response_cnt == 1) {
00353                 printf("Delayed response - thread: %d\n", data_item->thread_id);
00354                 memset(&coap_header, 0, sizeof(sn_coap_hdr_s));
00355 
00356                 if(data_item->delayed_msg_type == COAP_MSG_TYPE_CONFIRMABLE)
00357                     coap_header.msg_type = COAP_MSG_TYPE_CONFIRMABLE;
00358                 else if(data_item->delayed_msg_type == COAP_MSG_TYPE_NON_CONFIRMABLE)
00359                     coap_header.msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE;
00360 
00361                 coap_header.msg_code = COAP_MSG_CODE_RESPONSE_CONTENT;
00362 
00363                 if(data_item->delayed_token_len)
00364                 {
00365                     coap_header.token_len = data_item->delayed_token_len;
00366                     coap_header.token_ptr = data_item->delayed_token;
00367                     data_item->delayed_token_len = 0;
00368                 }
00369 
00370                 coap_header.payload_len = sizeof(data_item->res_temp_val) - 1;
00371                 coap_header.payload_ptr = data_item->res_temp_val;
00372 
00373                 sn_nsdl_send_coap_message(data_item->handle, &data_item->received_packet_address, &coap_header);
00374 
00375                 data_item->delayed_response_cnt = 0;
00376 
00377             }
00378             else if(data_item->delayed_response_cnt > 1) {
00379                 data_item->delayed_response_cnt--;
00380             }
00381         }
00382     }
00383 }
00384 
00385 /* This is callback for other DYNAMIC resources */
00386 uint8_t general_resource_cb(struct nsdl_s *handle, sn_coap_hdr_s *received_coap_ptr,
00387                             sn_nsdl_addr_s *address, sn_nsdl_capab_e protocol)
00388 {
00389     sn_coap_hdr_s *coap_res_ptr = 0;
00390     thread_data_struct_s *data_item = NULL;
00391     ns_list_foreach(thread_data_struct_s, item, &data_list) {
00392         if (item->handle == handle) {
00393             data_item = item;
00394             break;
00395         }
00396     }
00397     if (!data_item) {
00398         return 0;
00399     }
00400 
00401     if (received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET) {
00402         printf("\nGeneral callback - thread id: %d\n", data_item->thread_id);
00403         coap_res_ptr = sn_nsdl_build_response(data_item->handle, received_coap_ptr, COAP_MSG_CODE_RESPONSE_CONTENT);
00404         coap_res_ptr->accept = COAP_CT_TEXT_PLAIN;
00405 
00406         /* Temperature resource */
00407         /* This makes delayed response, first ack and after that real value */
00408         if(compare_uripaths(received_coap_ptr, res_temp))
00409         {
00410             send_ack(data_item->handle,received_coap_ptr, &data_item->received_packet_address);
00411             if(coap_res_ptr->token_ptr) {
00412                 own_free(coap_res_ptr->token_ptr);
00413             }
00414             if(coap_res_ptr->options_list_ptr) {
00415                 own_free(coap_res_ptr->options_list_ptr);
00416             }
00417             own_free(coap_res_ptr);
00418             return 0;
00419         }
00420         sn_nsdl_send_coap_message(data_item->handle, address, coap_res_ptr);
00421     }
00422     else if (received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_PUT) {
00423         if (received_coap_ptr->payload_ptr && received_coap_ptr->payload_len < 16) {
00424             ns_list_remove(&data_list, data_item);
00425             memcpy(data_item->res_temp_val,received_coap_ptr->payload_ptr, received_coap_ptr->payload_len);
00426             printf("Update resource value to %s, thread id: %d\n", data_item->res_temp_val, data_item->thread_id);
00427             ns_list_add_to_end(&data_list, data_item);
00428         }
00429         coap_res_ptr = sn_nsdl_build_response(data_item->handle, received_coap_ptr, COAP_MSG_CODE_RESPONSE_CHANGED);
00430         sn_nsdl_send_coap_message(data_item->handle, address, coap_res_ptr);
00431     }
00432     /* Method not supported */
00433     else {
00434         printf("Method not supported\n");
00435         coap_res_ptr = sn_coap_build_response(handle->grs->coap, received_coap_ptr, COAP_MSG_CODE_RESPONSE_METHOD_NOT_ALLOWED);
00436         sn_nsdl_send_coap_message(handle, address, coap_res_ptr);
00437     }
00438 
00439     if(coap_res_ptr->token_ptr) {
00440         own_free(coap_res_ptr->token_ptr);
00441     }
00442 
00443     if(coap_res_ptr->options_list_ptr) {
00444         own_free(coap_res_ptr->options_list_ptr);
00445     }
00446     own_free(coap_res_ptr);
00447 
00448     return 0;
00449 }
00450 
00451 int8_t compare_uripaths(sn_coap_hdr_s *coap_header, const uint8_t *uri_path_to_compare)
00452 {
00453     if(memcmp(coap_header->uri_path_ptr,&uri_path_to_compare[0], coap_header->uri_path_len) == 0)
00454     {
00455         return 1;
00456     }
00457     return 0;
00458 }
00459 
00460 void send_ack(struct nsdl_s *handle, sn_coap_hdr_s *received_coap_ptr, sn_nsdl_addr_s *address/*,  sn_nsdl_addr_s *received_packet_address*/)
00461 {
00462     printf("Send acknowledgement\n");
00463     sn_coap_hdr_s *coap_res_ptr = 0;
00464     uint16_t message_len = 0;
00465     uint8_t *message_ptr;
00466     thread_data_struct_s *data_item = NULL;
00467     ns_list_foreach(thread_data_struct_s, item, &data_list) {
00468         if (item->handle == handle) {
00469             data_item = item;
00470             break;
00471         }
00472     }
00473     if (data_item) {
00474         if (received_coap_ptr->msg_code == COAP_MSG_CODE_REQUEST_GET)
00475         {
00476             if (received_coap_ptr->msg_type == COAP_MSG_TYPE_CONFIRMABLE) {
00477                 coap_res_ptr = own_alloc(sizeof(sn_coap_hdr_s));
00478                 if(!coap_res_ptr) {
00479                     return;
00480                 }
00481                 memset(coap_res_ptr, 0x00, sizeof(sn_coap_hdr_s));
00482                 coap_res_ptr->msg_type = COAP_MSG_TYPE_ACKNOWLEDGEMENT;
00483                 coap_res_ptr->msg_code = COAP_MSG_CODE_EMPTY;
00484                 coap_res_ptr->msg_id = received_coap_ptr->msg_id;
00485                 data_item->delayed_msg_type = COAP_MSG_TYPE_CONFIRMABLE;
00486             }
00487             else {
00488                 data_item->delayed_msg_type = COAP_MSG_TYPE_NON_CONFIRMABLE;
00489             }
00490 
00491             if(received_coap_ptr->token_len) {
00492                 memset(data_item->delayed_token, 0, 8);
00493                 data_item->delayed_token_len = received_coap_ptr->token_len;
00494                 memcpy(data_item->delayed_token, received_coap_ptr->token_ptr, received_coap_ptr->token_len);
00495             }
00496             data_item->delayed_response_cnt = 1;
00497         }
00498     }
00499 
00500     if(coap_res_ptr) {
00501         message_len = sn_coap_builder_calc_needed_packet_data_size(coap_res_ptr);
00502         message_ptr = own_alloc(message_len);
00503         if(!message_ptr) {
00504             return;
00505         }
00506 
00507         sn_coap_builder(message_ptr, coap_res_ptr);
00508         tx_function(handle,SN_NSDL_PROTOCOL_COAP, message_ptr, message_len, address);
00509 
00510         /* Free memory */
00511         if(coap_res_ptr) {
00512             own_free(coap_res_ptr);
00513         }
00514         own_free(message_ptr);
00515     }
00516     return;
00517 }