SmartMesh QSL for STM32F4 version

Fork of COG-AD4050_QSL by APS Lab

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers dn_fsm.c Source File

dn_fsm.c

00001 /*
00002 Copyright (c) 2016, Dust Networks. All rights reserved.
00003 
00004 Finite State Machine for the QuickStart Library.
00005 
00006 \license See attached DN_LICENSE.txt.
00007 */
00008 
00009 #include "dn_fsm.h"
00010 #include "dn_ipmt.h"
00011 #include "dn_time.h"
00012 #include "dn_watchdog.h"
00013 #include "dn_qsl_api.h"
00014 #include "dn_debug.h"
00015 
00016 //=========================== variables =======================================
00017 
00018 typedef struct
00019 {
00020     // FSM
00021     uint32_t fsmEventScheduled_ms;
00022     uint16_t fsmDelay_ms;
00023     bool fsmArmed;
00024     uint8_t state;
00025     // C Library API
00026     dn_fsm_reply_cbt replyCb;
00027     dn_fsm_timer_cbt fsmCb;
00028     uint8_t replyBuf[MAX_FRAME_LENGTH];
00029     uint8_t notifBuf[MAX_FRAME_LENGTH];
00030     // Connection
00031     uint8_t socketId;
00032     uint16_t networkId;
00033     uint8_t joinKey[DN_JOIN_KEY_LEN];
00034     uint16_t srcPort;
00035     uint32_t service_ms;
00036     uint8_t payloadBuf[DN_DEFAULT_PAYLOAD_SIZE_LIMIT];
00037     uint8_t payloadSize;
00038     uint8_t destIPv6[DN_IPv6ADDR_LEN];
00039     uint16_t destPort;
00040     dn_inbox_t inbox;
00041 } dn_fsm_vars_t;
00042 
00043 static dn_fsm_vars_t dn_fsm_vars;
00044 
00045 
00046 //=========================== prototypes ======================================
00047 // FSM
00048 static void dn_fsm_run(void);
00049 static void dn_fsm_scheduleEvent(uint16_t delay, dn_fsm_timer_cbt cb);
00050 static void dn_fsm_cancelEvent(void);
00051 static void dn_fsm_setReplyCallback(dn_fsm_reply_cbt cb);
00052 static void dn_fsm_enterState(uint8_t newState, uint16_t spesificDelay);
00053 static bool dn_fsm_cmd_timeout(uint32_t cmdStart_ms, uint32_t cmdTimeout_ms);
00054 // C Library API
00055 static void dn_ipmt_notif_cb(uint8_t cmdId, uint8_t subCmdId);
00056 static void dn_ipmt_reply_cb(uint8_t cmdId);
00057 static void dn_event_responseTimeout(void);
00058 static void dn_event_reset(void);
00059 static void dn_reply_reset(void);
00060 static void dn_event_disconnect(void);
00061 static void dn_reply_disconnect(void);
00062 static void dn_event_getMoteStatus(void);
00063 static void dn_reply_getMoteStatus(void);
00064 static void dn_event_openSocket(void);
00065 static void dn_reply_openSocket(void);
00066 static void dn_event_bindSocket(void);
00067 static void dn_reply_bindSocket(void);
00068 static void dn_event_setJoinKey(void);
00069 static void dn_reply_setJoinKey(void);
00070 static void dn_event_setNetworkId(void);
00071 static void dn_reply_setNetworkId(void);
00072 static void dn_event_search(void);
00073 static void dn_reply_search(void);
00074 static void dn_event_join(void);
00075 static void dn_reply_join(void);
00076 static void dn_event_requestService(void);
00077 static void dn_reply_requestService(void);
00078 static void dn_event_getServiceInfo(void);
00079 static void dn_reply_getServiceInfo(void);
00080 static void dn_event_sendTo(void);
00081 static void dn_reply_sendTo(void);
00082 // helpers
00083 static dn_err_t checkAndSaveNetConfig(uint16_t netID, const uint8_t* joinKey, uint16_t srcPort, uint32_t req_service_ms);
00084 static uint8_t getPayloadLimit(uint16_t destPort);
00085 
00086 //=========================== public ==========================================
00087 
00088 //========== QSL API
00089 
00090 bool dn_qsl_init(void)
00091 {
00092     //debug("QSL: Init");
00093     // Reset local variables
00094     memset(&dn_fsm_vars, 0, sizeof (dn_fsm_vars));
00095 
00096     // Initialize the ipmt module
00097     dn_ipmt_init // Should be augmented with return value to know if successful...
00098             (
00099             dn_ipmt_notif_cb,
00100             dn_fsm_vars.notifBuf,
00101             sizeof (dn_fsm_vars.notifBuf),
00102             dn_ipmt_reply_cb
00103             );
00104 
00105     dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00106     return TRUE;
00107 }
00108 
00109 bool dn_qsl_isConnected(void)
00110 {
00111     //debug("QSL: isConnected");
00112     return dn_fsm_vars.state == DN_FSM_STATE_CONNECTED;
00113 }
00114 
00115 bool dn_qsl_connect(uint16_t netID, const uint8_t* joinKey, uint16_t srcPort, uint32_t req_service_ms)
00116 {
00117     uint32_t cmdStart_ms = dn_time_ms();
00118     dn_err_t err;
00119     //debug("QSL: Connect");
00120     switch (dn_fsm_vars.state)
00121     {
00122     case DN_FSM_STATE_NOT_INITIALIZED:
00123         //log_warn("Can't connect; not initialized");
00124         return FALSE;
00125     case DN_FSM_STATE_DISCONNECTED:
00126         err = checkAndSaveNetConfig(netID, joinKey, srcPort, req_service_ms);
00127         if (err != DN_ERR_NONE)
00128         {
00129             return FALSE;
00130         }
00131         //debug("Starting connect process...");
00132         dn_fsm_enterState(DN_FSM_STATE_PRE_JOIN, 0);
00133         break;
00134     case DN_FSM_STATE_CONNECTED:
00135         if ((netID > 0 && netID != dn_fsm_vars.networkId)
00136                 || (joinKey != NULL && memcmp(joinKey, dn_fsm_vars.joinKey, DN_JOIN_KEY_LEN) != 0)
00137                 || (srcPort > 0 && srcPort != dn_fsm_vars.srcPort))
00138         {
00139             err = checkAndSaveNetConfig(netID, joinKey, srcPort, req_service_ms);
00140             if (err != DN_ERR_NONE)
00141             {
00142                 return FALSE;
00143             }
00144             //debug("New network ID, join key and/or source port; reconnecting...");
00145             dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
00146         } else if (req_service_ms > 0 && req_service_ms != dn_fsm_vars.service_ms)
00147         {
00148             //debug("New service request");
00149             dn_fsm_vars.service_ms = req_service_ms;
00150             dn_fsm_enterState(DN_FSM_STATE_REQ_SERVICE, 0);
00151         } else
00152         {
00153             //debug("Already connected");
00154             // Nothing to do
00155         }
00156         break;
00157     default:
00158         //log_err("Unexpected state");
00159         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00160         return FALSE;
00161     }
00162 
00163     // Drive FSM until connect success/failure or timeout
00164     while (dn_fsm_vars.state != DN_FSM_STATE_CONNECTED
00165             && dn_fsm_vars.state != DN_FSM_STATE_DISCONNECTED
00166             && !dn_fsm_cmd_timeout(cmdStart_ms, DN_CONNECT_TIMEOUT_S * 1000))
00167     {
00168         dn_watchdog_feed();
00169         dn_fsm_run();
00170     }
00171 
00172     return dn_fsm_vars.state == DN_FSM_STATE_CONNECTED;
00173 }
00174 
00175 bool dn_qsl_send(const uint8_t* payload, uint8_t payloadSize_B, uint16_t destPort)
00176 {
00177     uint32_t cmdStart_ms = dn_time_ms();
00178     uint8_t maxPayloadSize;
00179     //debug("QSL: Send");
00180     switch (dn_fsm_vars.state)
00181     {
00182     case DN_FSM_STATE_CONNECTED:
00183         maxPayloadSize = getPayloadLimit(destPort);
00184 
00185         if (payloadSize_B > maxPayloadSize)
00186         {
00187             //log_warn("Payload size (%u) exceeds limit (%u)", payloadSize_B, maxPayloadSize);
00188             return FALSE;
00189         }
00190         // Store outbound payload and parameters
00191         memcpy(dn_fsm_vars.payloadBuf, payload, payloadSize_B);
00192         dn_fsm_vars.payloadSize = payloadSize_B;
00193         memcpy(dn_fsm_vars.destIPv6, DN_DEST_IP, DN_IPv6ADDR_LEN);
00194         dn_fsm_vars.destPort = (destPort > 0) ? destPort : DN_DEFAULT_DEST_PORT;
00195         // Start send process
00196         dn_fsm_enterState(DN_FSM_STATE_SENDING, 0);
00197         break;
00198     default:
00199         //log_warn("Can't send; not connected");
00200         return FALSE;
00201     }
00202 
00203     // Drive FSM until send success/failure or timeout
00204     while (dn_fsm_vars.state == DN_FSM_STATE_SENDING
00205             && !dn_fsm_cmd_timeout(cmdStart_ms, DN_SEND_TIMEOUT_MS))
00206     {
00207         dn_watchdog_feed();
00208         dn_fsm_run();
00209     }
00210 
00211     // Catch send failure
00212     if (dn_fsm_vars.state == DN_FSM_STATE_SEND_FAILED)
00213     {
00214         //debug("Send failed");
00215         dn_fsm_enterState(DN_FSM_STATE_CONNECTED, 0);
00216         return FALSE;
00217     }
00218 
00219     return dn_fsm_vars.state == DN_FSM_STATE_CONNECTED;
00220 }
00221 
00222 uint8_t dn_qsl_read(uint8_t* readBuffer)
00223 {
00224     uint8_t bytesRead = 0;
00225     //debug("QSL: Read");
00226     if (dn_fsm_vars.inbox.unreadPackets > 0)
00227     {
00228         // Pop payload at head of inbox
00229         memcpy
00230                 (
00231                 readBuffer,
00232                 dn_fsm_vars.inbox.pktBuf[dn_fsm_vars.inbox.head],
00233                 dn_fsm_vars.inbox.pktSize[dn_fsm_vars.inbox.head]
00234                 );
00235         bytesRead = dn_fsm_vars.inbox.pktSize[dn_fsm_vars.inbox.head];
00236         dn_fsm_vars.inbox.head = (dn_fsm_vars.inbox.head + 1) % DN_INBOX_SIZE;
00237         dn_fsm_vars.inbox.unreadPackets--;
00238         //debug("Read %u bytes from inbox", bytesRead);
00239     } else
00240     {
00241         //debug("Inbox empty");
00242     }
00243     return bytesRead;
00244 }
00245 
00246 //=========================== private =========================================
00247 
00248 //========== FSM
00249 
00250 //===== run
00251 
00252 /**
00253  Check if an event is scheduled and run it if due.
00254  */
00255 static void dn_fsm_run(void)
00256 {
00257     uint32_t timePassed_ms = dn_time_ms() - dn_fsm_vars.fsmEventScheduled_ms; // Handle dn_time_ms wrap around
00258     if (dn_fsm_vars.fsmArmed && (timePassed_ms > dn_fsm_vars.fsmDelay_ms))
00259     {
00260         // Scheduled event is due; execute it
00261         dn_fsm_vars.fsmArmed = FALSE;
00262         if (dn_fsm_vars.fsmCb != NULL)
00263         {
00264             dn_fsm_vars.fsmCb();
00265         }
00266     } else
00267     {
00268         // Sleep to save CPU power
00269         dn_sleep_ms(DN_FSM_RUN_INTERVAL_MS);
00270     }
00271 }
00272 
00273 //===== scheduleEvent
00274 
00275 /**
00276  Schedule function to be called after a given delay.
00277  */
00278 static void dn_fsm_scheduleEvent(uint16_t delay_ms, dn_fsm_timer_cbt cb)
00279 {
00280     dn_fsm_vars.fsmEventScheduled_ms = dn_time_ms();
00281     dn_fsm_vars.fsmDelay_ms = delay_ms;
00282     dn_fsm_vars.fsmCb = cb;
00283     dn_fsm_vars.fsmArmed = TRUE;
00284 }
00285 
00286 //===== cancelEvent
00287 
00288 /**
00289  Cancel currently scheduled event.
00290  */
00291 static void dn_fsm_cancelEvent(void)
00292 {
00293     dn_fsm_vars.fsmDelay_ms = 0;
00294     dn_fsm_vars.fsmCb = NULL;
00295     dn_fsm_vars.fsmArmed = FALSE;
00296 }
00297 
00298 //===== setReplyCallback
00299 
00300 /**
00301  Set the callback function that the C Library will execute when the next reply
00302  is received and the reply buffer is ready to be parsed.
00303  */
00304 static void dn_fsm_setReplyCallback(dn_fsm_reply_cbt cb)
00305 {
00306     dn_fsm_vars.replyCb = cb;
00307 }
00308 
00309 //===== enterState
00310 
00311 /**
00312  Transition FSM to new state and schedule any default entry events.
00313  */
00314 static void dn_fsm_enterState(uint8_t newState, uint16_t spesificDelay)
00315 {
00316     uint32_t now = dn_time_ms();
00317     uint16_t delay = DN_CMD_PERIOD_MS;
00318     static uint32_t lastTransition = 0;
00319     if (lastTransition == 0)
00320         lastTransition = now;
00321 
00322     // Use default delay if none given
00323     if (spesificDelay > 0)
00324         delay = spesificDelay;
00325 
00326     // Schedule default events for transition into states
00327     switch (newState)
00328     {
00329     case DN_FSM_STATE_PRE_JOIN:
00330         dn_fsm_scheduleEvent(delay, dn_event_getMoteStatus);
00331         break;
00332     case DN_FSM_STATE_PROMISCUOUS:
00333         dn_fsm_scheduleEvent(delay, dn_event_search);
00334         break;
00335     case DN_FSM_STATE_JOINING:
00336         dn_fsm_scheduleEvent(delay, dn_event_join);
00337         break;
00338     case DN_FSM_STATE_REQ_SERVICE:
00339         dn_fsm_scheduleEvent(delay, dn_event_requestService);
00340         break;
00341     case DN_FSM_STATE_RESETTING:
00342         if (DN_MOTE_DISCONNECT_BEFORE_RESET)
00343             dn_fsm_scheduleEvent(delay, dn_event_disconnect); // More graceful
00344         else
00345             dn_fsm_scheduleEvent(delay, dn_event_reset); // Faster
00346         break;
00347     case DN_FSM_STATE_SENDING:
00348         /*
00349          Send is scheduled immediately because it is the users responsibility
00350          to implement the necessary backoff and not exceed the granted bandwidth.
00351          */
00352         dn_fsm_scheduleEvent(0, dn_event_sendTo);
00353         break;
00354     case DN_FSM_STATE_SEND_FAILED:
00355     case DN_FSM_STATE_DISCONNECTED:
00356     case DN_FSM_STATE_CONNECTED:
00357         // These states have no default entry events
00358         break;
00359     default:
00360         //log_warn("Attempt at entering unexpected state %#.2x", newState);
00361         return;
00362     }
00363 
00364     //debug("FSM state transition: %#.2x --> %#.2x (%u ms)",
00365             //dn_fsm_vars.state, newState, (uint32_t)(now - lastTransition));
00366     lastTransition = now;
00367     dn_fsm_vars.state = newState;
00368 }
00369 
00370 //===== cmdTimeout
00371 
00372 /**
00373  Correctly abort the current API command if time passed since the given start
00374  has exceeded the given timeout.
00375  */
00376 static bool dn_fsm_cmd_timeout(uint32_t cmdStart_ms, uint32_t cmdTimeout_ms)
00377 {
00378     uint32_t timePassed_ms = dn_time_ms() - cmdStart_ms; // Handle dn_time_ms wrap around
00379     bool timeout = timePassed_ms > cmdTimeout_ms;
00380     if (timeout)
00381     {
00382         // Cancel any ongoing transmission or scheduled event and reset reply cb
00383         dn_ipmt_cancelTx();
00384         dn_fsm_vars.replyCb = NULL;
00385         dn_fsm_cancelEvent();
00386 
00387         // Default timeout state is different while connecting vs sending
00388         switch (dn_fsm_vars.state)
00389         {
00390         case DN_FSM_STATE_PRE_JOIN:
00391         case DN_FSM_STATE_JOINING:
00392         case DN_FSM_STATE_REQ_SERVICE:
00393         case DN_FSM_STATE_RESETTING:
00394             //debug("Connect timeout");
00395             dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00396             break;
00397         case DN_FSM_STATE_SENDING:
00398             //debug("Send timeout");
00399             dn_fsm_enterState(DN_FSM_STATE_SEND_FAILED, 0);
00400             break;
00401         default:
00402             //log_err("Command timeout in unexpected state: %#x", dn_fsm_vars.state);
00403             break;
00404         }
00405     }
00406     return timeout;
00407 }
00408 
00409 //========== C Library API
00410 
00411 //===== notif_cb
00412 
00413 /**
00414  This function is called whenever a notification is received through the
00415  SmartMesh C Library. The notification variables are than available through
00416  the notification buffer that can be cast to the correct type based on the
00417  given command ID (notification type).
00418  */
00419 static void dn_ipmt_notif_cb(uint8_t cmdId, uint8_t subCmdId)
00420 {
00421     //dn_ipmt_timeIndication_nt* notif_timeIndication;
00422     dn_ipmt_events_nt* notif_events;
00423     dn_ipmt_receive_nt* notif_receive;
00424     //dn_ipmt_macRx_nt* notif_macRx;
00425     //dn_ipmt_txDone_nt* notif_txDone;
00426     dn_ipmt_advReceived_nt* notif_advReceived;
00427 
00428     //debug("Got notification: cmdId; %#.2x (%u), subCmdId; %#.2x (%u)",
00429             //cmdId, cmdId, subCmdId, subCmdId);
00430 
00431     switch (cmdId)
00432     {
00433     case CMDID_TIMEINDICATION:
00434         // Not implemented
00435         break;
00436     case CMDID_EVENTS:
00437         notif_events = (dn_ipmt_events_nt*)dn_fsm_vars.notifBuf;
00438         //debug("State: %#.2x | Events: %#.4x", notif_events->state, notif_events->events);
00439 
00440         // Check if in fsm state where we expect a certain mote event
00441         switch (dn_fsm_vars.state)
00442         {
00443         case DN_FSM_STATE_JOINING:
00444             if (notif_events->events & DN_MOTE_EVENT_MASK_OPERATIONAL)
00445             {
00446                 // Join complete
00447                 if (dn_fsm_vars.service_ms > 0)
00448                 {
00449                     dn_fsm_enterState(DN_FSM_STATE_REQ_SERVICE, 0);
00450                 } else
00451                 {
00452                     dn_fsm_enterState(DN_FSM_STATE_CONNECTED, 0);
00453                 }
00454                 return;
00455             }
00456             break;
00457         case DN_FSM_STATE_REQ_SERVICE:
00458             if (notif_events->events & DN_MOTE_EVENT_MASK_SVC_CHANGE)
00459             {
00460                 // Service request complete; check what we were granted
00461                 dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_getServiceInfo);
00462                 return;
00463             }
00464             break;
00465         }
00466 
00467         // Check if reported mote state should trigger fsm state transition
00468         switch (notif_events->state)
00469         {
00470         case DN_MOTE_STATE_IDLE:
00471             switch (dn_fsm_vars.state)
00472             {
00473             case DN_FSM_STATE_PRE_JOIN:
00474             case DN_FSM_STATE_JOINING:
00475             case DN_FSM_STATE_REQ_SERVICE:
00476             case DN_FSM_STATE_RESETTING:
00477             case DN_FSM_STATE_PROMISCUOUS:
00478                 // Restart during connect; retry
00479                 dn_fsm_enterState(DN_FSM_STATE_PRE_JOIN, 0);
00480                 break;
00481             case DN_FSM_STATE_CONNECTED:
00482             case DN_FSM_STATE_SENDING:
00483             case DN_FSM_STATE_SEND_FAILED:
00484                 // Disconnect/reset; set state accordingly
00485                 dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00486                 break;
00487             }
00488             break;
00489         case DN_MOTE_STATE_OPERATIONAL:
00490             switch (dn_fsm_vars.state)
00491             {
00492             case DN_FSM_STATE_PRE_JOIN:
00493             case DN_FSM_STATE_PROMISCUOUS:
00494                 /*
00495                  Early (and unexpected) operational (connected to network)
00496                  during connect; reset and retry
00497                  */
00498                 dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
00499                 break;
00500             }
00501             break;
00502         }
00503         break;
00504     case CMDID_RECEIVE:
00505         notif_receive = (dn_ipmt_receive_nt*)dn_fsm_vars.notifBuf;
00506         //debug("Received downstream data");
00507 
00508         // Push payload at tail of inbox
00509         memcpy
00510                 (
00511                 dn_fsm_vars.inbox.pktBuf[dn_fsm_vars.inbox.tail],
00512                 notif_receive->payload,
00513                 notif_receive->payloadLen
00514                 );
00515         dn_fsm_vars.inbox.pktSize[dn_fsm_vars.inbox.tail] = notif_receive->payloadLen;
00516         dn_fsm_vars.inbox.tail = (dn_fsm_vars.inbox.tail + 1) % DN_INBOX_SIZE;
00517         if(dn_fsm_vars.inbox.unreadPackets == DN_INBOX_SIZE)
00518         {
00519             //log_warn("Inbox overflow; oldest packet dropped");
00520         } else
00521         {
00522             dn_fsm_vars.inbox.unreadPackets++;
00523         }
00524         //debug("Inbox capacity at %u / %u", dn_fsm_vars.inbox.unreadPackets, DN_INBOX_SIZE);
00525 
00526         break;
00527     case CMDID_MACRX:
00528         // Not implemented
00529         break;
00530     case CMDID_TXDONE:
00531         // Not implemented
00532         break;
00533     case CMDID_ADVRECEIVED:
00534         notif_advReceived = (dn_ipmt_advReceived_nt*)dn_fsm_vars.notifBuf;
00535         //debug("Received network advertisement");
00536 
00537         if (dn_fsm_vars.state == DN_FSM_STATE_PROMISCUOUS
00538                 && dn_fsm_vars.networkId == DN_PROMISCUOUS_NET_ID)
00539         {
00540             //debug("Saving network ID: %#.4x (%u)",
00541                     //notif_advReceived->netId, notif_advReceived->netId);
00542             dn_fsm_vars.networkId = notif_advReceived->netId;
00543             dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_setNetworkId);
00544         }
00545 
00546         break;
00547     default:
00548         //log_warn("Unknown notification ID");
00549         break;
00550     }
00551 }
00552 
00553 //===== reply_cb
00554 
00555 /**
00556  This function is called whenever a reply is received through the SmartMesh.
00557  C Library. It calls the reply function that was armed at the start of the
00558  current event.
00559  */
00560 static void dn_ipmt_reply_cb(uint8_t cmdId)
00561 {
00562     //debug("Got reply: cmdId; %#.2x (%u)", cmdId, cmdId);
00563     if (dn_fsm_vars.replyCb == NULL)
00564     {
00565         //debug("Reply callback empty");
00566         return;
00567     }
00568     dn_fsm_vars.replyCb();
00569 }
00570 
00571 //===== response_timeout
00572 
00573 /**
00574  This event is scheduled after each mote API command is sent, effectively
00575  placing a timeout for the mote to reply.
00576  */
00577 static void dn_event_responseTimeout(void)
00578 {
00579     //debug("Response timeout");
00580 
00581     // Cancel any ongoing transmission and reset reply cb
00582     dn_ipmt_cancelTx();
00583     dn_fsm_vars.replyCb = NULL;
00584 
00585     switch (dn_fsm_vars.state)
00586     {
00587     case DN_FSM_STATE_PRE_JOIN:
00588     case DN_FSM_STATE_JOINING:
00589     case DN_FSM_STATE_REQ_SERVICE:
00590     case DN_FSM_STATE_RESETTING:
00591     case DN_FSM_STATE_PROMISCUOUS:
00592         // Response timeout during connect; retry
00593         dn_fsm_enterState(DN_FSM_STATE_PRE_JOIN, 0);
00594         break;
00595     case DN_FSM_STATE_SENDING:
00596         // Response timeout during send; fail
00597         dn_fsm_enterState(DN_FSM_STATE_SEND_FAILED, 0);
00598         break;
00599     default:
00600         //log_err("Response timeout in unexpected state: %#x", dn_fsm_vars.state);
00601         break;
00602     }
00603 }
00604 
00605 //===== reset
00606 
00607 /**
00608  Initiates a soft-reset of the mote. Its reply simply checks that
00609  the command was accepted, as the FSM will wait for the ensuing boot event.
00610  */
00611 static void dn_event_reset(void)
00612 {
00613     //debug("Reset");
00614     // Arm reply callback
00615     dn_fsm_setReplyCallback(dn_reply_reset);
00616 
00617     // Issue mote API command
00618     dn_ipmt_reset
00619             (
00620             (dn_ipmt_reset_rpt*)dn_fsm_vars.replyBuf
00621             );
00622 
00623     // Schedule timeout for reply
00624     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00625 }
00626 
00627 static void dn_reply_reset(void)
00628 {
00629     dn_ipmt_reset_rpt* reply;
00630     //debug("Reset reply");
00631 
00632     // Cancel reply timeout
00633     dn_fsm_cancelEvent();
00634 
00635     // Parse reply
00636     reply = (dn_ipmt_reset_rpt*)dn_fsm_vars.replyBuf;
00637 
00638     // Choose next event or state transition
00639     switch (reply->RC)
00640     {
00641     case DN_RC_OK:
00642         //debug("Mote soft-reset initiated");
00643         // Will wait for notification of reboot
00644         break;
00645     default:
00646         //log_warn("Unexpected response code: %#x", reply->RC);
00647         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00648         break;
00649     }
00650 }
00651 
00652 //===== disconnect
00653 
00654 /**
00655  This event does much the same as reset, however it uses the disconnect command
00656  instead, where the mote first spends a couple of seconds notifying its
00657  neighbors of its imminent soft-reset. If the reply is anything but success,
00658  it will schedule a simple reset event instead.
00659  */
00660 static void dn_event_disconnect(void)
00661 {
00662     //debug("Disconnect");
00663 
00664     // Arm reply callback
00665     dn_fsm_setReplyCallback(dn_reply_disconnect);
00666 
00667     // Issue mote API command
00668     dn_ipmt_disconnect
00669             (
00670             (dn_ipmt_disconnect_rpt*)dn_fsm_vars.replyBuf
00671             );
00672 
00673     // Schedule timeout for reply
00674     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00675 }
00676 
00677 static void dn_reply_disconnect(void)
00678 {
00679     dn_ipmt_disconnect_rpt* reply;
00680     //debug("Disconnect reply");
00681 
00682     // Cancel reply timeout
00683     dn_fsm_cancelEvent();
00684 
00685     // Parse reply
00686     reply = (dn_ipmt_disconnect_rpt*)dn_fsm_vars.replyBuf;
00687 
00688     // Choose next event or state transition
00689     switch (reply->RC)
00690     {
00691     case DN_RC_OK:
00692         //debug("Mote disconnect initiated");
00693         // Will wait for notification of reboot
00694         break;
00695     case DN_RC_INVALID_STATE:
00696         //debug("The mote is in an invalid state to disconnect; resetting");
00697         dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_reset);
00698         break;
00699     default:
00700         //log_warn("Unexpected response code: %#x", reply->RC);
00701         dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_reset);
00702         break;
00703     }
00704 }
00705 
00706 //===== getMoteStatus
00707 
00708 /**
00709  Asks the mote for its status, and the reply will use the reported
00710  mote state to decide whether or not it is ready to proceed with pre-join
00711  configurations or if a reset is needed first.
00712  */
00713 static void dn_event_getMoteStatus(void)
00714 {
00715     //debug("Mote status");
00716 
00717     // Arm reply callback
00718     dn_fsm_setReplyCallback(dn_reply_getMoteStatus);
00719 
00720     // Issue mote API command
00721     dn_ipmt_getParameter_moteStatus
00722             (
00723             (dn_ipmt_getParameter_moteStatus_rpt*)dn_fsm_vars.replyBuf
00724             );
00725 
00726     // Schedule timeout for reply
00727     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00728 }
00729 
00730 static void dn_reply_getMoteStatus(void)
00731 {
00732     dn_ipmt_getParameter_moteStatus_rpt* reply;
00733     //debug("Mote status reply");
00734 
00735     // Cancel reply timeout
00736     dn_fsm_cancelEvent();
00737 
00738     // Parse reply
00739     reply = (dn_ipmt_getParameter_moteStatus_rpt*)dn_fsm_vars.replyBuf;
00740     //debug("Mote state: %#.2x", reply->state);
00741 
00742     // Choose next event or state transition
00743     switch (reply->state)
00744     {
00745     case DN_MOTE_STATE_IDLE:
00746         dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_openSocket);
00747         break;
00748     case DN_MOTE_STATE_OPERATIONAL:
00749         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
00750         break;
00751     default:
00752         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
00753         break;
00754     }
00755 }
00756 
00757 //===== openSocket
00758 
00759 /**
00760  Tells the mote to open a socket, and the reply saves the reported
00761  socket ID before scheduling its binding. If no sockets are available, a mote
00762  reset is scheduled and the connect process starts over.
00763  */
00764 static void dn_event_openSocket(void)
00765 {
00766     //debug("Open socket");
00767 
00768     // Arm reply callback
00769     dn_fsm_setReplyCallback(dn_reply_openSocket);
00770 
00771     // Issue mote API command
00772     dn_ipmt_openSocket
00773             (
00774             DN_PROTOCOL_TYPE_UDP,
00775             (dn_ipmt_openSocket_rpt*)dn_fsm_vars.replyBuf
00776             );
00777 
00778     // Schedule timeout for reply
00779     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00780 }
00781 
00782 static void dn_reply_openSocket(void)
00783 {
00784     dn_ipmt_openSocket_rpt* reply;
00785     //debug("Open socket reply");
00786 
00787     // Cancel reply timeout
00788     dn_fsm_cancelEvent();
00789 
00790     // Parse reply
00791     reply = (dn_ipmt_openSocket_rpt*)dn_fsm_vars.replyBuf;
00792 
00793     // Choose next event or state transition
00794     switch (reply->RC)
00795     {
00796     case DN_RC_OK:
00797         //debug("Socket %d opened successfully", reply->socketId);
00798         dn_fsm_vars.socketId = reply->socketId;
00799         dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_bindSocket);
00800         break;
00801     case DN_RC_NO_RESOURCES:
00802         //debug("Couldn't create socket due to resource availability");
00803         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
00804         break;
00805     default:
00806         //log_warn("Unexpected response code: %#x", reply->RC);
00807         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00808         break;
00809     }
00810 }
00811 
00812 //===== bindSocket
00813 
00814 /**
00815  Binds the previously opened socket to a port. If said port is already bound,
00816  a mote reset is scheduled and the connect process starts over.
00817  */
00818 static void dn_event_bindSocket(void)
00819 {
00820     //debug("Bind socket");
00821 
00822     // Arm reply callback
00823     dn_fsm_setReplyCallback(dn_reply_bindSocket);
00824 
00825     // Issue mote API command
00826     dn_ipmt_bindSocket
00827             (
00828             dn_fsm_vars.socketId,
00829             dn_fsm_vars.srcPort,
00830             (dn_ipmt_bindSocket_rpt*)dn_fsm_vars.replyBuf
00831             );
00832 
00833     // Schedule timeout for reply
00834     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00835 }
00836 
00837 static void dn_reply_bindSocket(void)
00838 {
00839     dn_ipmt_bindSocket_rpt* reply;
00840     //debug("Bind socket reply");
00841 
00842     // Cancel reply timeout
00843     dn_fsm_cancelEvent();
00844 
00845     // Parse reply
00846     reply = (dn_ipmt_bindSocket_rpt*)dn_fsm_vars.replyBuf;
00847 
00848     // Choose next event or state transition
00849     switch (reply->RC)
00850     {
00851     case DN_RC_OK:
00852         //debug("Socket bound successfully");
00853         dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_setJoinKey);
00854         break;
00855     case DN_RC_BUSY:
00856         //debug("Port already bound");
00857         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
00858         break;
00859     case DN_RC_NOT_FOUND:
00860         //debug("Invalid socket ID");
00861         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00862         break;
00863     default:
00864         //log_warn("Unexpected response code: %#x", reply->RC);
00865         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00866         break;
00867     }
00868 }
00869 
00870 //===== setJoinKey
00871 
00872 /**
00873  Configures the join key that the mote should use when attempting to join a
00874  network.
00875  */
00876 static void dn_event_setJoinKey(void)
00877 {
00878     //debug("Set join key");
00879 
00880     // Arm reply callback
00881     dn_fsm_setReplyCallback(dn_reply_setJoinKey);
00882 
00883     // Issue mote API command
00884     dn_ipmt_setParameter_joinKey
00885             (
00886             dn_fsm_vars.joinKey,
00887             (dn_ipmt_setParameter_joinKey_rpt*)dn_fsm_vars.replyBuf
00888             );
00889 
00890     // Schedule timeout for reply
00891     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00892 }
00893 
00894 static void dn_reply_setJoinKey(void)
00895 {
00896     dn_ipmt_setParameter_joinKey_rpt* reply;
00897     //debug("Set join key reply");
00898 
00899     // Cancel reply timeout
00900     dn_fsm_cancelEvent();
00901 
00902     // Parse reply
00903     reply = (dn_ipmt_setParameter_joinKey_rpt*)dn_fsm_vars.replyBuf;
00904 
00905     // Choose next event or state transition
00906     switch (reply->RC)
00907     {
00908     case DN_RC_OK:
00909         //debug("Join key set");
00910         if (dn_fsm_vars.networkId == DN_PROMISCUOUS_NET_ID)
00911         {
00912             // Promiscuous netID set; search for new first
00913             dn_fsm_enterState(DN_FSM_STATE_PROMISCUOUS, 0);
00914             /*
00915              As of version 1.4.x, a network ID of 0xFFFF can be used to indicate
00916              that the mote should join the first network heard. Thus, searching
00917              before joining will not be necessary.
00918             */
00919         } else
00920         {
00921             dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_setNetworkId);
00922         }
00923         break;
00924     case DN_RC_WRITE_FAIL:
00925         //debug("Could not write the key to storage");
00926         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00927         break;
00928     default:
00929         //log_warn("Unexpected response code: %#x", reply->RC);
00930         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00931         break;
00932     }
00933 }
00934 
00935 //===== setNetworkId
00936 
00937 /**
00938  Configures the ID of the network that the mote should should try to join.
00939  */
00940 static void dn_event_setNetworkId(void)
00941 {
00942     //debug("Set network ID");
00943 
00944     // Arm reply callback
00945     dn_fsm_setReplyCallback(dn_reply_setNetworkId);
00946 
00947     // Issue mote API command
00948     dn_ipmt_setParameter_networkId
00949             (
00950             dn_fsm_vars.networkId,
00951             (dn_ipmt_setParameter_networkId_rpt*)dn_fsm_vars.replyBuf
00952             );
00953 
00954     // Schedule timeout for reply
00955     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
00956 }
00957 
00958 static void dn_reply_setNetworkId(void)
00959 {
00960     dn_ipmt_setParameter_networkId_rpt* reply;
00961     //debug("Set network ID reply");
00962 
00963     // Cancel reply timeout
00964     dn_fsm_cancelEvent();
00965 
00966     // Parse reply
00967     reply = (dn_ipmt_setParameter_networkId_rpt*)dn_fsm_vars.replyBuf;
00968 
00969     // Choose next event or state transition
00970     switch (reply->RC)
00971     {
00972     case DN_RC_OK:
00973         //debug("Network ID set");
00974         dn_fsm_enterState(DN_FSM_STATE_JOINING, 0);
00975         break;
00976     case DN_RC_WRITE_FAIL:
00977         //debug("Could not write the network ID to storage");
00978         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00979         break;
00980     default:
00981         //log_warn("Unexpected response code: %#x", reply->RC);
00982         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
00983         break;
00984     }
00985 }
00986 
00987 //===== search
00988 
00989 /**
00990  Tells the mote to start listening for network advertisements. The mote will
00991  then report the network ID (among other things) of any advertisements heard.
00992  Upon a successful reply, the FSM will wait for an advReceived notification,
00993  before attempting to join the reported network.
00994  */
00995 static void dn_event_search(void)
00996 {
00997     //debug("Search");
00998 
00999     // Arm reply callback
01000     dn_fsm_setReplyCallback(dn_reply_search);
01001 
01002     // Issue mote API command
01003     dn_ipmt_search
01004             (
01005             (dn_ipmt_search_rpt*)dn_fsm_vars.replyBuf
01006             );
01007 
01008     // Schedule timeout for reply
01009     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
01010 }
01011 
01012 static void dn_reply_search(void)
01013 {
01014     dn_ipmt_search_rpt* reply;
01015     //debug("Search reply");
01016 
01017     // Cancel reply timeout
01018     dn_fsm_cancelEvent();
01019 
01020     // Parse reply
01021     reply = (dn_ipmt_search_rpt*)dn_fsm_vars.replyBuf;
01022 
01023     // Choose next event or state transition
01024     switch (reply->RC)
01025     {
01026     case DN_RC_OK:
01027         //debug("Searching for network advertisements");
01028         // Will wait for notification of advertisement received
01029         break;
01030     case DN_RC_INVALID_STATE:
01031         //debug("The mote is in an invalid state to start searching");
01032         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
01033         break;
01034     default:
01035         //log_warn("Unexpected response code: %#x", reply->RC);
01036         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
01037         break;
01038     }
01039 }
01040 
01041 //===== join
01042 
01043 /**
01044  Requests that the mote start searching for the previously configured network
01045  and attempt to join with the configured join key. If the mote is in an invalid
01046  state to join or lacks configuration to start joining, a reset is scheduled and
01047  the connect procedure starts over. Otherwise the FSM will wait for the ensuing
01048  operational event when the mote has finished joining.
01049  */
01050 static void dn_event_join(void)
01051 {
01052     //debug("Join");
01053 
01054     // Arm reply callback
01055     dn_fsm_setReplyCallback(dn_reply_join);
01056 
01057     // Issue mote API command
01058     dn_ipmt_join
01059             (
01060             (dn_ipmt_join_rpt*)dn_fsm_vars.replyBuf
01061             );
01062 
01063     // Schedule timeout for reply
01064     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
01065 }
01066 
01067 static void dn_reply_join(void)
01068 {
01069     dn_ipmt_join_rpt* reply;
01070     //debug("Join reply");
01071 
01072     // Cancel reply timeout
01073     dn_fsm_cancelEvent();
01074 
01075     // Parse reply
01076     reply = (dn_ipmt_join_rpt*)dn_fsm_vars.replyBuf;
01077 
01078     // Choose next event or state transition
01079     switch (reply->RC)
01080     {
01081     case DN_RC_OK:
01082         //debug("Join operation started");
01083         // Will wait for join complete notification (operational event)
01084         break;
01085     case DN_RC_INVALID_STATE:
01086         //debug("The mote is in an invalid state to start join operation");
01087         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
01088         break;
01089     case DN_RC_INCOMPLETE_JOIN_INFO:
01090         //debug("Incomplete configuration to start joining");
01091         dn_fsm_enterState(DN_FSM_STATE_RESETTING, 0);
01092         break;
01093     default:
01094         //log_warn("Unexpected response code: %#x", reply->RC);
01095         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
01096         break;
01097     }
01098 }
01099 
01100 //===== requestService
01101 
01102 /**
01103  The mote is told to request a new service level from the manager. Its reply
01104  simply checks that the command was accepted, as the FSM will wait for the
01105  ensuing svcChange event when the service allocation has changed.
01106  */
01107 static void dn_event_requestService(void)
01108 {
01109     //debug("Request service");
01110 
01111     // Arm reply callback
01112     dn_fsm_setReplyCallback(dn_reply_requestService);
01113 
01114     // Issue mote API command
01115     dn_ipmt_requestService
01116             (
01117             DN_SERVICE_ADDRESS,
01118             DN_SERVICE_TYPE_BW,
01119             dn_fsm_vars.service_ms,
01120             (dn_ipmt_requestService_rpt*)dn_fsm_vars.replyBuf
01121             );
01122 
01123     // Schedule timeout for reply
01124     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
01125 }
01126 
01127 static void dn_reply_requestService(void)
01128 {
01129     dn_ipmt_requestService_rpt* reply;
01130     //debug("Request service reply");
01131 
01132     // Cancel reply timeout
01133     dn_fsm_cancelEvent();
01134 
01135     // Parse reply
01136     reply = (dn_ipmt_requestService_rpt*)dn_fsm_vars.replyBuf;
01137 
01138     // Choose next event or state transition
01139     switch (reply->RC)
01140     {
01141     case DN_RC_OK:
01142         //debug("Service request accepted");
01143         // Will wait for svcChanged notification
01144         break;
01145     default:
01146         //log_warn("Unexpected response code: %#x", reply->RC);
01147         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
01148         break;
01149     }
01150 }
01151 
01152 //===== getServiceInfo
01153 
01154 /**
01155  Requests details about the service currently allocated to the mote. Its reply
01156  checks that we have been granted a service equal to or better than what was
01157  requested (smaller value equals better).
01158  */
01159 static void dn_event_getServiceInfo(void)
01160 {
01161     //debug("Get service info");
01162 
01163     // Arm reply callback
01164     dn_fsm_setReplyCallback(dn_reply_getServiceInfo);
01165 
01166     // Issue mote API command
01167     dn_ipmt_getServiceInfo
01168             (
01169             DN_SERVICE_ADDRESS,
01170             DN_SERVICE_TYPE_BW,
01171             (dn_ipmt_getServiceInfo_rpt*)dn_fsm_vars.replyBuf
01172             );
01173 
01174     // Schedule timeout for reply
01175     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
01176 }
01177 
01178 static void dn_reply_getServiceInfo(void)
01179 {
01180     dn_ipmt_getServiceInfo_rpt* reply;
01181     //debug("Get service info reply");
01182 
01183     // Cancel reply timeout
01184     dn_fsm_cancelEvent();
01185 
01186     // Parse reply
01187     reply = (dn_ipmt_getServiceInfo_rpt*)dn_fsm_vars.replyBuf;
01188 
01189     // Choose next event or state transition
01190     switch (reply->RC)
01191     {
01192     case DN_RC_OK:
01193         if (reply->state == DN_SERVICE_STATE_COMPLETED)
01194         {
01195             if (reply->value <= dn_fsm_vars.service_ms)
01196             {
01197                 //debug("Granted service of %u ms (requested %u ms)", reply->value, dn_fsm_vars.service_ms);
01198                 dn_fsm_enterState(DN_FSM_STATE_CONNECTED, 0);
01199             } else
01200             {
01201                 //log_warn("Only granted service of %u ms (requested %u ms)", reply->value, dn_fsm_vars.service_ms);
01202                 dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
01203             }
01204 
01205         } else
01206         {
01207             //debug("Service request still pending");
01208             dn_fsm_scheduleEvent(DN_CMD_PERIOD_MS, dn_event_getServiceInfo);
01209         }
01210         break;
01211     default:
01212         //log_warn("Unexpected response code: %#x", reply->RC);
01213         dn_fsm_enterState(DN_FSM_STATE_DISCONNECTED, 0);
01214         break;
01215     }
01216 }
01217 
01218 //===== sendTo
01219 
01220 /**
01221  This event sends a packet into the network, and its reply checks that it was
01222  accepted and queued up for transmission.
01223  */
01224 static void dn_event_sendTo(void)
01225 {
01226     dn_err_t err;
01227     //debug("Send");
01228 
01229     // Arm reply callback
01230     dn_fsm_setReplyCallback(dn_reply_sendTo);
01231 
01232     // Issue mote API command
01233     err = dn_ipmt_sendTo
01234             (
01235             dn_fsm_vars.socketId,
01236             dn_fsm_vars.destIPv6,
01237             dn_fsm_vars.destPort,
01238             DN_SERVICE_TYPE_BW,
01239             DN_PACKET_PRIORITY_MEDIUM,
01240             DN_PACKET_ID_NO_NOTIF,
01241             dn_fsm_vars.payloadBuf,
01242             dn_fsm_vars.payloadSize,
01243             (dn_ipmt_sendTo_rpt*)dn_fsm_vars.replyBuf
01244             );
01245     if (err != DN_ERR_NONE)
01246     {
01247         //debug("Send error: %u", err);
01248         dn_fsm_enterState(DN_FSM_STATE_SEND_FAILED, 0);
01249     }
01250 
01251     // Schedule timeout for reply
01252     dn_fsm_scheduleEvent(DN_SERIAL_RESPONSE_TIMEOUT_MS, dn_event_responseTimeout);
01253 }
01254 
01255 static void dn_reply_sendTo(void)
01256 {
01257     dn_ipmt_sendTo_rpt* reply;
01258     //debug("Send reply");
01259 
01260     // Cancel reply timeout
01261     dn_fsm_cancelEvent();
01262 
01263     // Parse reply
01264     reply = (dn_ipmt_sendTo_rpt*)dn_fsm_vars.replyBuf;
01265 
01266     // Choose next event or state transition
01267     switch (reply->RC)
01268     {
01269     case DN_RC_OK:
01270         //debug("Packet was queued up for transmission");
01271         dn_fsm_enterState(DN_FSM_STATE_CONNECTED, 0);
01272         break;
01273     case DN_RC_NO_RESOURCES:
01274         //debug("No queue space to accept the packet");
01275         dn_fsm_enterState(DN_FSM_STATE_SEND_FAILED, 0);
01276         break;
01277     default:
01278         //log_warn("Unexpected response code: %#x", reply->RC);
01279         dn_fsm_enterState(DN_FSM_STATE_SEND_FAILED, 0);
01280         break;
01281     }
01282 }
01283 
01284 //=========================== helpers =========================================
01285 
01286 static dn_err_t checkAndSaveNetConfig(uint16_t netID, const uint8_t* joinKey, uint16_t srcPort, uint32_t req_service_ms)
01287 {
01288     if (netID == 0)
01289     {
01290         //debug("No network ID given; using default");
01291         dn_fsm_vars.networkId = DN_DEFAULT_NET_ID;
01292     } else if (netID == DN_PROMISCUOUS_NET_ID)
01293     {
01294         //debug("Promiscuous network ID given; will search for and join first network advertised");
01295         dn_fsm_vars.networkId = netID;
01296     } else
01297     {
01298         dn_fsm_vars.networkId = netID;
01299     }
01300 
01301     if (joinKey == NULL)
01302     {
01303         //debug("No join key given; using default");
01304         memcpy(dn_fsm_vars.joinKey, DN_DEFAULT_JOIN_KEY, DN_JOIN_KEY_LEN);
01305     } else
01306     {
01307         memcpy(dn_fsm_vars.joinKey, joinKey, DN_JOIN_KEY_LEN);
01308     }
01309 
01310     if (srcPort == 0)
01311     {
01312         //debug("No source port given; using default");
01313         dn_fsm_vars.srcPort = DN_DEFAULT_SRC_PORT;
01314     } else
01315     {
01316         dn_fsm_vars.srcPort = srcPort;
01317     }
01318 
01319     if (req_service_ms == 0)
01320     {
01321         //debug("No service requested; will only be granted base bandwidth");
01322     }
01323     dn_fsm_vars.service_ms = req_service_ms;
01324 
01325     return DN_ERR_NONE;
01326 }
01327 
01328 static uint8_t getPayloadLimit(uint16_t destPort)
01329 {
01330     bool destIsF0Bx = (destPort >= DN_WELL_KNOWN_PORT_1 && destPort <= DN_WELL_KNOWN_PORT_8);
01331     bool srcIsF0Bx = (dn_fsm_vars.srcPort >= DN_WELL_KNOWN_PORT_1 && dn_fsm_vars.srcPort <= DN_WELL_KNOWN_PORT_8);
01332     int8_t destIsMng = memcmp(DN_DEST_IP, DN_DEFAULT_DEST_IP, DN_IPv6ADDR_LEN);
01333 
01334     if (destIsMng == 0)
01335     {
01336         if (destIsF0Bx && srcIsF0Bx)
01337             return DN_PAYLOAD_SIZE_LIMIT_MNG_HIGH;
01338         else if (destIsF0Bx || srcIsF0Bx)
01339             return DN_PAYLOAD_SIZE_LIMIT_MNG_MED;
01340         else
01341             return DN_PAYLOAD_SIZE_LIMIT_MNG_LOW;
01342     } else
01343     {
01344         if (destIsF0Bx && srcIsF0Bx)
01345             return DN_PAYLOAD_SIZE_LIMIT_IP_HIGH;
01346         else if (destIsF0Bx || srcIsF0Bx)
01347             return DN_PAYLOAD_SIZE_LIMIT_IP_MED;
01348         else
01349             return DN_PAYLOAD_SIZE_LIMIT_IP_LOW;
01350     }
01351 }
01352