Kenji Arai / mbed-os_TYBLE16

Dependents:   TYBLE16_simple_data_logger TYBLE16_MP3_Air

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ethernet_tasklet.c Source File

ethernet_tasklet.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 <string.h> //memset
00018 #include "eventOS_event_timer.h"
00019 #include "common_functions.h"
00020 #include "net_interface.h"
00021 #include "ip6string.h"  //ip6tos
00022 #include "nsdynmemLIB.h"
00023 #include "include/mesh_system.h"
00024 #include "ns_event_loop.h"
00025 #include "mesh_interface_types.h"
00026 #include "eventOS_event.h"
00027 #include "enet_tasklet.h"
00028 
00029 // For tracing we need to define flag, have include and define group
00030 #include "ns_trace.h"
00031 #define TRACE_GROUP  "IPV6"
00032 
00033 #include "ethernet_mac_api.h"
00034 
00035 #define INTERFACE_NAME   "eth0"
00036 
00037 // Tasklet timer events
00038 #define TIMER_EVENT_START_BOOTSTRAP   1
00039 
00040 #define INVALID_INTERFACE_ID        (-1)
00041 
00042 #define STR_HELPER(x) #x
00043 #define STR(x) STR_HELPER(x)
00044 
00045 /*
00046  * Mesh tasklet states.
00047  */
00048 typedef enum {
00049     TASKLET_STATE_CREATED = 0,
00050     TASKLET_STATE_INITIALIZED,
00051     TASKLET_STATE_BOOTSTRAP_STARTED,
00052     TASKLET_STATE_BOOTSTRAP_FAILED,
00053     TASKLET_STATE_BOOTSTRAP_READY
00054 } tasklet_state_t;
00055 
00056 /*
00057  * Mesh tasklet data structure.
00058  */
00059 typedef struct {
00060     void (*mesh_api_cb)(mesh_connection_status_t nwk_status);
00061     tasklet_state_t tasklet_state;
00062     mesh_connection_status_t connection_status;
00063     timeout_t *poll_network_status_timeout;
00064     int8_t node_main_tasklet_id;
00065     int8_t network_interface_id;
00066     int8_t tasklet;
00067     uint8_t ip[16];
00068 } tasklet_data_str_t;
00069 
00070 /* Tasklet data */
00071 static tasklet_data_str_t *tasklet_data_ptr = NULL;
00072 static eth_mac_api_t *eth_mac_api = NULL;
00073 typedef void (*mesh_interface_cb)(mesh_connection_status_t mesh_status);
00074 
00075 
00076 /* private function prototypes */
00077 static void enet_tasklet_main(arm_event_s *event);
00078 static void enet_tasklet_network_state_changed(mesh_connection_status_t status);
00079 static void enet_tasklet_parse_network_event(arm_event_s *event);
00080 static void enet_tasklet_configure_and_connect_to_network(void);
00081 static void enet_tasklet_poll_network_status(void *param);
00082 static void enet_tasklet_generate_event(uint8_t link_status, mesh_connection_status_t mesh_status);
00083 /*
00084  * \brief A function which will be eventually called by NanoStack OS when ever the OS has an event to deliver.
00085  * @param event, describes the sender, receiver and event type.
00086  *
00087  * NOTE: Interrupts requested by HW are possible during this function!
00088  */
00089 void enet_tasklet_main(arm_event_s *event)
00090 {
00091     arm_library_event_type_e event_type;
00092     event_type = (arm_library_event_type_e) event->event_type;
00093 
00094     switch (event_type) {
00095         case ARM_LIB_NWK_INTERFACE_EVENT:
00096             /* This event is delivered every and each time when there is new
00097              * information of network connectivity.
00098              */
00099             enet_tasklet_parse_network_event(event);
00100             break;
00101 
00102         case ARM_LIB_TASKLET_INIT_EVENT:
00103             /* Event with type EV_INIT is an initializer event of NanoStack OS.
00104              * The event is delivered when the NanoStack OS is running fine.
00105              * This event should be delivered ONLY ONCE.
00106              */
00107             tasklet_data_ptr->node_main_tasklet_id = event->receiver;
00108             mesh_system_send_connect_event(tasklet_data_ptr->tasklet);
00109             break;
00110 
00111         case ARM_LIB_SYSTEM_TIMER_EVENT:
00112             eventOS_event_timer_cancel(event->event_id,
00113                                        tasklet_data_ptr->node_main_tasklet_id);
00114 
00115             if (event->event_id == TIMER_EVENT_START_BOOTSTRAP) {
00116                 tr_debug("Restart bootstrap");
00117                 enet_tasklet_configure_and_connect_to_network();
00118             }
00119             break;
00120 
00121         case APPLICATION_EVENT:
00122             if (event->event_id == APPL_EVENT_CONNECT) {
00123                 enet_tasklet_configure_and_connect_to_network();
00124             } else if (event->event_id == APPL_BACKHAUL_LINK_UP
00125                        && tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_STARTED) {
00126                 // Ethernet cable has been plugged in
00127                 arm_nwk_interface_configure_ipv6_bootstrap_set(
00128                     tasklet_data_ptr->network_interface_id, NET_IPV6_BOOTSTRAP_AUTONOMOUS, NULL);
00129                 enet_tasklet_configure_and_connect_to_network();
00130 
00131                 if (tasklet_data_ptr->poll_network_status_timeout != NULL) {
00132                     // Restart poll timer
00133                     eventOS_timeout_cancel(tasklet_data_ptr->poll_network_status_timeout);
00134                 }
00135                 tasklet_data_ptr->poll_network_status_timeout =
00136                     eventOS_timeout_every_ms(enet_tasklet_poll_network_status, 2000, NULL);
00137             } else if (event->event_id == APPL_BACKHAUL_LINK_DOWN) {
00138                 // Ethernet cable has been removed
00139                 arm_nwk_interface_down(tasklet_data_ptr->network_interface_id);
00140                 eventOS_timeout_cancel(tasklet_data_ptr->poll_network_status_timeout);
00141                 tasklet_data_ptr->poll_network_status_timeout = NULL;
00142                 memset(tasklet_data_ptr->ip, 0x0, 16);
00143                 enet_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
00144             } else if (event->event_id == APPL_BACKHAUL_INTERFACE_PHY_DOWN) {
00145                 // disconnect called
00146                 if (tasklet_data_ptr != NULL) {
00147                     if (tasklet_data_ptr->network_interface_id != INVALID_INTERFACE_ID) {
00148                         if (tasklet_data_ptr->connection_status != MESH_BOOTSTRAP_STARTED) {
00149                             arm_nwk_interface_down(tasklet_data_ptr->network_interface_id);
00150                         }
00151                         tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
00152                         enet_tasklet_network_state_changed(MESH_DISCONNECTED);
00153                     }
00154                     tasklet_data_ptr->mesh_api_cb = NULL;
00155                     eventOS_timeout_cancel(tasklet_data_ptr->poll_network_status_timeout);
00156                 }
00157             }
00158             break;
00159 
00160         default:
00161             break;
00162     } // switch(event_type)
00163 }
00164 
00165 /**
00166  * \brief Network state event handler.
00167  * \param event show network start response or current network state.
00168  *
00169  * - ARM_NWK_BOOTSTRAP_READY: Save NVK persistent data to NVM and Net role
00170  * - ARM_NWK_NWK_SCAN_FAIL: Link Layer Active Scan Fail, Stack is Already at Idle state
00171  * - ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL: No ND Router at current Channel Stack is Already at Idle state
00172  * - ARM_NWK_NWK_CONNECTION_DOWN: Connection to Access point is lost wait for Scan Result
00173  * - ARM_NWK_NWK_PARENT_POLL_FAIL: Host should run net start without any PAN-id filter and all channels
00174  * - ARM_NWK_AUHTENTICATION_FAIL: Pana Authentication fail, Stack is Already at Idle state
00175  */
00176 void enet_tasklet_parse_network_event(arm_event_s *event)
00177 {
00178     arm_nwk_interface_status_type_e status = (arm_nwk_interface_status_type_e) event->event_data;
00179     tr_debug("app_parse_network_event() %d", status);
00180     switch (status) {
00181         case ARM_NWK_BOOTSTRAP_READY:
00182             /* Network is ready and node is connected to Access Point */
00183             if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
00184                 tr_info("IPv6 bootstrap ready");
00185                 tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_READY;
00186                 enet_tasklet_poll_network_status(NULL);
00187             }
00188             break;
00189         case ARM_NWK_IP_ADDRESS_ALLOCATION_FAIL:
00190             /* No ND Router at current Channel Stack is Already at Idle state */
00191             tr_info("Bootstrap fail");
00192             tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
00193             enet_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
00194             break;
00195         case ARM_NWK_NWK_CONNECTION_DOWN:
00196             /* Connection to Access point is lost wait for Scan Result */
00197             tr_info("Connection lost");
00198             tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
00199             enet_tasklet_network_state_changed(MESH_BOOTSTRAP_FAILED);
00200             break;
00201         default:
00202             tr_warn("Unknown event %d", status);
00203             break;
00204     }
00205 
00206     if (tasklet_data_ptr->tasklet_state != TASKLET_STATE_BOOTSTRAP_READY) {
00207         // Set 5s timer for new network scan
00208         eventOS_event_timer_request(TIMER_EVENT_START_BOOTSTRAP,
00209                                     ARM_LIB_SYSTEM_TIMER_EVENT,
00210                                     tasklet_data_ptr->node_main_tasklet_id,
00211                                     5000);
00212     }
00213 }
00214 
00215 static void enet_tasklet_poll_network_status(void *param)
00216 {
00217     /* Check if we do have an IP */
00218     uint8_t temp_ipv6[16];
00219     if (arm_net_address_get(tasklet_data_ptr->network_interface_id, ADDR_IPV6_GP, temp_ipv6) == 0) {
00220         /* Check if this is link local address or not */
00221         if (memcmp(temp_ipv6, tasklet_data_ptr->ip, 16) == 0) {
00222             return;
00223         } else {
00224             memcpy(tasklet_data_ptr->ip, temp_ipv6, 16);
00225             uint8_t temp_ipv6_local[16];
00226             if (arm_net_address_get(tasklet_data_ptr->network_interface_id, ADDR_IPV6_LL, temp_ipv6_local) == 0
00227                     && (memcmp(temp_ipv6, temp_ipv6_local, 16) != 0)) {
00228                 enet_tasklet_network_state_changed(MESH_CONNECTED_GLOBAL);
00229             } else {
00230                 enet_tasklet_network_state_changed(MESH_CONNECTED_LOCAL);;
00231             }
00232         }
00233     } else {
00234         if (tasklet_data_ptr->connection_status != MESH_DISCONNECTED &&
00235                 tasklet_data_ptr->connection_status != MESH_BOOTSTRAP_STARTED) {
00236             enet_tasklet_network_state_changed(MESH_DISCONNECTED);
00237         }
00238     }
00239 }
00240 
00241 /*
00242  * \brief Configure and establish network connection
00243  *
00244  */
00245 void enet_tasklet_configure_and_connect_to_network(void)
00246 {
00247     int8_t status;
00248 
00249     status = arm_nwk_interface_up(tasklet_data_ptr->network_interface_id);
00250     if (status >= 0) {
00251         tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_STARTED;
00252         tr_info("Start Bootstrap");
00253         enet_tasklet_network_state_changed(MESH_BOOTSTRAP_STARTED);
00254     } else {
00255         tasklet_data_ptr->tasklet_state = TASKLET_STATE_BOOTSTRAP_FAILED;
00256         tr_err("Bootstrap start failed, %d", status);
00257         enet_tasklet_network_state_changed(MESH_BOOTSTRAP_START_FAILED);
00258     }
00259 }
00260 
00261 /*
00262  * Inform application about network state change
00263  */
00264 void enet_tasklet_network_state_changed(mesh_connection_status_t status)
00265 {
00266     tasklet_data_ptr->connection_status = status;
00267     if (tasklet_data_ptr->mesh_api_cb) {
00268         (tasklet_data_ptr->mesh_api_cb)(status);
00269     }
00270 }
00271 
00272 /* Public functions */
00273 int8_t enet_tasklet_connect(mesh_interface_cb callback, int8_t nwk_interface_id)
00274 {
00275     int8_t re_connecting = true;
00276     int8_t tasklet_id = tasklet_data_ptr->tasklet;
00277 
00278     if (tasklet_data_ptr->tasklet_state == TASKLET_STATE_CREATED) {
00279         re_connecting = false;
00280     }
00281 
00282     memset(tasklet_data_ptr, 0, sizeof(tasklet_data_str_t));
00283     tasklet_data_ptr->mesh_api_cb = callback;
00284     tasklet_data_ptr->network_interface_id = nwk_interface_id;
00285     tasklet_data_ptr->tasklet_state = TASKLET_STATE_INITIALIZED;
00286     tasklet_data_ptr->poll_network_status_timeout =
00287         eventOS_timeout_every_ms(enet_tasklet_poll_network_status, 2000, NULL);
00288 
00289     if (re_connecting == false) {
00290         tasklet_data_ptr->tasklet = eventOS_event_handler_create(&enet_tasklet_main,
00291                                                                  ARM_LIB_TASKLET_INIT_EVENT);
00292         if (tasklet_data_ptr->tasklet < 0) {
00293             // -1 handler already used by other tasklet
00294             // -2 memory allocation failure
00295             return tasklet_data_ptr->tasklet;
00296         }
00297     } else {
00298         tasklet_data_ptr->tasklet = tasklet_id;
00299         mesh_system_send_connect_event(tasklet_data_ptr->tasklet);
00300     }
00301 
00302     return 0;
00303 }
00304 
00305 int8_t enet_tasklet_disconnect(bool send_cb)
00306 {
00307     enet_tasklet_generate_event(APPL_BACKHAUL_INTERFACE_PHY_DOWN, MESH_DISCONNECTED);
00308     return 0;
00309 }
00310 
00311 void enet_tasklet_init(void)
00312 {
00313     if (tasklet_data_ptr == NULL) {
00314         tasklet_data_ptr = ns_dyn_mem_alloc(sizeof(tasklet_data_str_t));
00315         tasklet_data_ptr->tasklet_state = TASKLET_STATE_CREATED;
00316         tasklet_data_ptr->network_interface_id = INVALID_INTERFACE_ID;
00317     }
00318 }
00319 
00320 int8_t enet_tasklet_network_init(int8_t device_id)
00321 {
00322     if (tasklet_data_ptr->network_interface_id != -1) {
00323         tr_debug("Interface already at active state\n");
00324         return tasklet_data_ptr->network_interface_id;
00325     }
00326     if (!eth_mac_api) {
00327         eth_mac_api = ethernet_mac_create(device_id);
00328     }
00329 
00330     tasklet_data_ptr->network_interface_id = arm_nwk_interface_ethernet_init(eth_mac_api, "eth0");
00331 
00332     tr_debug("interface ID: %d", tasklet_data_ptr->network_interface_id);
00333     arm_nwk_interface_configure_ipv6_bootstrap_set(
00334         tasklet_data_ptr->network_interface_id, NET_IPV6_BOOTSTRAP_AUTONOMOUS, NULL);
00335     return tasklet_data_ptr->network_interface_id;
00336 }
00337 
00338 /* For now, to enable to compile without Nanostack interface changes, enables Nanostack PPP
00339    interface only if default stack is Nanostack and interface cellular. After Nanostack
00340    with updated interface call arm_nwk_interface_ppp_init() is integrated to mbed-os, this
00341    flagging can be removed.
00342 */
00343 #define NANOSTACK   0x11991199
00344 #define CELLULAR    0x22992299
00345 #if MBED_CONF_NSAPI_DEFAULT_STACK == NANOSTACK && MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE == CELLULAR
00346 #define ENABLE_NANOSTACK_PPP
00347 #endif
00348 #undef NANOSTACK
00349 #undef CELLULAR
00350 
00351 int8_t enet_tasklet_ppp_network_init(int8_t device_id)
00352 {
00353 #ifdef ENABLE_NANOSTACK_PPP
00354     if (tasklet_data_ptr->network_interface_id != -1) {
00355         tr_debug("Interface already at active state\n");
00356         return tasklet_data_ptr->network_interface_id;
00357     }
00358     if (!eth_mac_api) {
00359         eth_mac_api = ethernet_mac_create(device_id);
00360     }
00361 
00362     tasklet_data_ptr->network_interface_id = arm_nwk_interface_ppp_init(eth_mac_api, "ppp0");
00363 
00364     tr_debug("interface ID: %d", tasklet_data_ptr->network_interface_id);
00365     arm_nwk_interface_configure_ipv6_bootstrap_set(
00366         tasklet_data_ptr->network_interface_id, NET_IPV6_BOOTSTRAP_AUTONOMOUS, NULL);
00367     return tasklet_data_ptr->network_interface_id;
00368 #else
00369     return -1;
00370 #endif
00371 }
00372 
00373 void enet_tasklet_link_state_changed(bool up)
00374 {
00375     if (up) {
00376         enet_tasklet_generate_event(APPL_BACKHAUL_LINK_UP, MESH_BOOTSTRAP_STARTED);
00377     } else {
00378         enet_tasklet_generate_event(APPL_BACKHAUL_LINK_DOWN, MESH_BOOTSTRAP_STARTED);
00379     }
00380 }
00381 
00382 static void enet_tasklet_generate_event(uint8_t link_status, mesh_connection_status_t mesh_status)
00383 {
00384     arm_event_s event = {
00385         .receiver = tasklet_data_ptr->tasklet,
00386         .sender =  tasklet_data_ptr->tasklet,
00387         .event_type = APPLICATION_EVENT,
00388         .priority = ARM_LIB_LOW_PRIORITY_EVENT,
00389         .event_id = link_status,
00390         .event_data = mesh_status
00391     };
00392     eventOS_event_send(&event);
00393 }