OT_WEAK void dll_activate(void) { /// Do session creation /// 1. Block DLL Idle-time tasks: they get reactivated by dll_idle() /// 2. Get top session /// 3. Associated Applet can construct packet, or control parameters /// 4. Session is terminated if "SCRAP" bit is 1 /// 5. Session is processed otherwise m2session* s_active; ot_app s_applet; dll_block_idletasks(); //dll.idle_state = sub_default_idle(); s_active = session_top(); s_applet = (s_active->applet == NULL) ? \ &dll_response_applet : s_active->applet; s_active->applet = NULL; s_applet(s_active); if (s_active->netstate & M2_NETSTATE_SCRAP) { session_pop(); dll_idle(); } else if (s_active->netstate & M2_NETSTATE_RX) { dll_init_rx(s_active); } else { dll_init_tx(s_active->netstate & (M2_NETFLAG_BG | M2_NETFLAG_STREAM)); } }
m2session* otapi_task_advertise(advert_tmpl* adv_tmpl, session_tmpl* s_tmpl, ot_app applet) { /// This is a more complicated process than the others, because it actually /// creates two sessions: one for the flood and one for the request. # define _FLOOD_NETSTATE (M2_NETFLAG_FLOOD | M2_NETSTATE_INIT | M2_NETSTATE_REQTX) ot_u8 scratch; m2session* session; /// 1. Clear any sessions between now and the request, and push the /// request session onto the stack. If the push failed, exit. If the /// advertising is 0, also exit and do this session without flood. session_crop(adv_tmpl->duration); session = sub_newtask(s_tmpl, applet, adv_tmpl->duration); if ((session == NULL) || (adv_tmpl->duration == 0)) return NULL; /// 2. Flood duty cycling is not supported at this time. All floods /// are implemented as 100% duty cycle. /// 3. Push the Advertising session onto the stack, for immediate running. /// <LI> Use the same subnet for the advertising as for the request. </LI> /// <LI> For basic flooding, the applet can be empty </LI> scratch = session->subnet; session = session_new(&otutils_applet_null, 0, _FLOOD_NETSTATE, adv_tmpl->channel); if (session == NULL) { session_pop(); //pop the request session from above return NULL; } session->subnet = scratch; return session; }
OT_WEAK void dll_beacon_applet(m2session* active) { /// Beaconing is a Request-TX operation, and the value for Tc is the amount of /// time to spend in CSMA before quitting the beacon. ot_queue beacon_queue; ot_u8 b_params; ot_u8 cmd_ext; ot_u8 cmd_code; b_params = active->extra; active->extra = 0; /// Start building the beacon packet: /// <LI> Calling m2np_header() will write most of the front of the frame </LI> /// <LI> Add the command byte and optional command-extension byte </LI> m2np_header(active, M2RT_BROADCAST, M2FI_FRDIALOG); cmd_ext = (b_params & 0x06); // Normal extension bits cmd_ext |= (dll.netconf.btemp[2] == 0) << 6; // Announcement No-File bit cmd_code = 0x20 | (b_params & 1) | ((cmd_ext!=0) << 7); q_writebyte(&txq, cmd_code); if (cmd_code) { q_writebyte(&txq, cmd_ext); } /// Setup the comm parameters, if the channel is available: /// <LI> dll.comm values tx_eirp, cs_rssi, and cca_rssi must be set by the /// radio module during the CSMA-CA process -- don't set them here. /// The DASH7 spec requires it to happen in this order. </LI> /// <LI> Set CSMA-CA parameters, which are used by the radio module </LI> /// <LI> Set number of redundant TX's we would like to transmit </LI> /// <LI> Set rx_timeout for Default-Tg or 0, if beacon has no response </LI> dll_set_defaults(active); dll.comm.tc = TI2CLK(M2_PARAM_BEACON_TCA); dll.comm.rx_timeout = (b_params & 0x02) ? \ 0 : rm2_default_tgd(active->channel); dll.comm.csmaca_params |= (b_params & 0x04) | M2_CSMACA_NA2P | M2_CSMACA_MACCA; dll.comm.redundants = dll.netconf.b_attempts; q_writebyte(&txq, (ot_u8)dll.comm.rx_timeout); /// Add the announcement file data if the specified return data != 0 bytes. /// If the beacon data is missing or otherwise not accessible by the GUEST /// user, dump the session (thus killing the beacon) and go back to idle. if (dll.netconf.btemp[2] != 0) { q_init(&beacon_queue, &dll.netconf.btemp[2], 4); if (m2qp_isf_call((b_params & 1), &beacon_queue, AUTH_GUEST) < 0) { session_pop(); dll_idle(); return; } } /// Final step to any packet generation: add footer m2np_footer(); }
void dll_processing(void) { /// This is the task for processing a DASH7 packet which has been received. /// If the packet is a valid request, this task will put the DLL into HOLD. /// If the listen bit is high, additionally, this task will clone the session /// to be re-visited at a later time. m2session* active; ot_int proc_score; sys.task_RFA.event = 0; // Only run processing once active = session_top(); active->counter = 0; proc_score = network_route_ff(active); /// Response is prepared already, so setup holdstate and flow control. /// proc_score is always negative after parsing a response. if (proc_score >= 0) { sub_fceval(proc_score); sys.task_HSS.cursor = 0; dll.counter = dll.netconf.hold_limit; dll.idle_state = M2_DLLIDLE_HOLD; /// If the Listen flag is high, clone the session to a time in the /// future, when it will listen again. /// <LI> dll.comm.tc has just been assigned by the request. It is the /// response contention period (Tc). </LI> /// <LI> This device should listen again after Tc ends, so the session /// is cloned & scheduled for Tc </LI> /// <LI> The current session is popped after response, or on next kernel /// loop (immediately) if no response </LI> if (active->flags & M2_FLAG_LISTEN) { network_cont_session(active->applet, M2_NETSTATE_REQRX, 0); } } /// Bad score, plus session indicates no listening or sending response. /// Scrap the session. else if ((active->netstate & M2_NETSTATE_RESP) == 0) { goto dll_processing_SCRAP; } /// A protocol parser has scrapped the session, or possibly the above /// condition branched here directly. if (active->netstate & M2_NETSTATE_SCRAP) { dll_processing_SCRAP: session_pop(); dll_idle(); } }