OT_WEAK void dll_systask_beacon(ot_task task) { /// The beacon rountine runs as an idependent systask. m2session* b_session; if ((task->event == 0) || (dll.netconf.b_attempts == 0)) { dll_idle(); return; } /// Load file-based beacon: /// Open BTS ISF Element and read the beacon sequence. Make sure there is /// a beacon file of non-zero length and that beacons are presently enabled. if (dll.netconf.dd_flags == 0) { ot_u16 scratch; vlFILE* fp; fp = ISF_open_su( ISF_ID(beacon_transmit_sequence) ); if (fp == NULL) { return; //goto dll_systask_beacon_STOP; } if (fp->length == 0) { vl_close(fp); return; //goto dll_systask_beacon_STOP; } // a little hack scratch = fp->start; fp->start += task->cursor; /// Beacon List Management: /// <LI> Move cursor onto next beacon period (above, +8)</LI> /// <LI> Loop cursor if it is past the length of the list </LI> /// <LI> In special case where cursor = 254, everything still works! </LI> task->cursor += 8; task->cursor = (task->cursor >= fp->length) ? 0 : task->cursor; // Load next beacon into btemp, then undo the start hack, then close vl_load(fp, 8, dll.netconf.btemp); fp->start = scratch; vl_close(fp); } // First 2 bytes: Chan ID, Cmd Code // - Setup beacon ad-hoc session, on specified channel (ad hoc sessions never return NULL) // - Assure cmd code is always Broadcast & Announcement b_session = session_new( &dll_beacon_applet, 0, dll.netconf.btemp[0], (M2_NETSTATE_INIT | M2_NETSTATE_REQTX | M2_NETFLAG_FIRSTRX) ); b_session->subnet = dll.netconf.b_subnet; b_session->extra = dll.netconf.btemp[1]; b_session->flags = dll.netconf.btemp[1] & 0x78; //b_session->flags |= (b_session->extra & 0x30); // Last 2 bytes: Next Scan ticks sys_task_setnext(task, TI2CLK( PLATFORM_ENDIAN16(*(ot_u16*)&dll.netconf.btemp[6]) )); ///@note this might not be necessary or wise! //return; //dll_systask_beacon_STOP: //dll_idle(); }
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(); }
OT_WEAK void dll_response_applet(m2session* active) { /// If this is a response transmission of a session with "Listen" active, it /// means the contention period (Tc) is followed immediately with a subsequent /// request. We must not overlap that request with the tail-end of our own /// response. Therefore, we subtract from Tc the duration of this response. if (active->flags & M2_FLAG_LISTEN) { ot_u8 substate = active->netstate & M2_NETSTATE_TMASK; if (substate == M2_NETSTATE_RESPTX) { dll.comm.tc -= TI2CLK(rm2_pkt_duration(&txq)); } else if (substate == M2_NETSTATE_REQRX) { sys.task_HSS.cursor = 0; sys.task_HSS.nextevent = dll.comm.rx_timeout; dll.comm.rx_timeout = rm2_default_tgd(active->channel); } } }
OT_WEAK ot_u16 otapi_start_dialog(ot_u16 timeout) { /// Stop any ongoing processes and seed the event for the event manager. The /// radio killer will work in all cases, but it is bad form to kill sessions /// that are moving data. if (timeout != 0) { dll.comm.tc = TI2CLK(timeout); } ///@todo update null radio driver to modern interface # ifndef __KERNEL_NONE__ if (radio.state != RADIO_Idle) { rm2_kill(); } # endif # ifndef __KERNEL_NONE__ sys.task_RFA.event = 0; sys_preempt(&sys.task_RFA, 0); # endif return 1; }