void applet_send_beacon(m2session* session) { { //open request for broadcast otapi_open_request(ADDR_broadcast, NULL); } { //use a command template for collection of single file from single file search ot_u8 status; command_tmpl command; command.opcode = (ot_u8)CMD_announce_file; command.type = (ot_u8)CMDTYPE_na2p_request; command.extension = (ot_u8)CMDEXT_no_response; otapi_put_command_tmpl(&status, &command); } { //write the dialog information (timeout, channels to use) ot_u8 status; dialog_tmpl dialog; dialog.channels = 0; //use same channel as request for response dialog.timeout = 0; //0 tick response timeout (1 tick = 0,977 ms) otapi_put_dialog_tmpl(&status, &dialog); } { //write the ISF return data (note: use isfcall template) ot_u8 status; isfcall_tmpl isfcall; isfcall.is_series = False; isfcall.isf_id = ISF_ID(network_settings); isfcall.max_return = ISF_LEN(network_settings); isfcall.offset = 0; otapi_put_isf_return(&status, &isfcall); } //Done building command, close the request and send the dialog otapi_close_request(); }
OT_WEAK void rm2_init(void) { vlFILE* fp; /// Set universal Radio module initialization defaults radio.state = RADIO_Idle; radio.evtdone = &otutils_sig2_null; /// These Radio Link features are available on the SPIRIT1 ///@todo see if this and the "Set startup channel" part of the init can /// get bundled into a common initialization function in radio_task.c # if (OT_FEATURE(RF_LINKINFO)) # if (M2_FEATURE(RSCODE)) # define _CORRECTIONS RADIO_LINK_CORRECTIONS # else # define _CORRECTIONS 0 # endif radio.link.flags = _CORRECTIONS | RADIO_LINK_PQI | RADIO_LINK_SQI \ | RADIO_LINK_LQI | RADIO_LINK_AGC; # endif radio.link.offset_thr = 0; radio.link.raw_thr = 0; /// Set startup channel to an always invalid channel ID (0xF0), and run /// lookup on the default channel (0x18) to kick things off. Since the /// startup channel will always be different than a real channel, the /// necessary settings and calibration will always occur. phymac[0].channel = 0xF0; phymac[0].tx_eirp = 0x7F; fp = ISF_open_su( ISF_ID(channel_configuration) ); rm2_channel_lookup(0x18, fp); vl_close(fp); }
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(); }
void applet_send_query(m2session* session) { /// The C-API for building commands can be bypassed in favor of directly /// putting data to the queue. That way is more efficient, but it also requires /// you to know more about DASH7 than just what order the templates should be. /// /// The query that we build will collect sensor configuration data back from /// all devices that support the sensor protocol. Much more interesting queries /// are possible. ot_u8 status; { //open request for single hop anycast query routing_tmpl routing; routing.hop_code = 0; otapi_open_request(ADDR_anycast, &routing); } { //use a command template for collection of single file from single file search command_tmpl command; command.opcode = (ot_u8)CMD_udp_on_file; command.type = (ot_u8)CMDTYPE_na2p_request; command.extension = (ot_u8)CMDEXT_none; otapi_put_command_tmpl(&status, &command); } { //write the dialog information (timeout, channels to use) dialog_tmpl dialog; dialog.channels = 0; //use same channel as request for response dialog.timeout = 0x41; //same as otutils_encode_timeout(512) -- 512 tick response slot otapi_put_dialog_tmpl(&status, &dialog); } { //write the query to search for the sensor protocol id static const ot_u8 query_str[10] = "APP=PongLT"; query_tmpl query; query.code = M2QC_COR_SEARCH + 10; // do a 100% length=10 correlation search query.mask = NULL; // don't do any masking (no partial matching) query.length = 10; // query_str is 10 bytes query.value = (ot_u8*)query_str; otapi_put_query_tmpl(&status, &query); } { //put in the information of the file to search (the user id) isfcomp_tmpl isfcomp; isfcomp.is_series = False; isfcomp.isf_id = ISF_ID(user_id); isfcomp.offset = 0; otapi_put_isf_comp(&status, &isfcomp); } { //put in UDP ports (from 254 to 255) and Ping ID q_writebyte(&txq, 254); q_writebyte(&txq, 255); q_writeshort(&txq, app.pingval); } //Done building command, close the request and send the dialog otapi_close_request(); }
/** ALP Processor Callback for Starting a Ping <BR> * ========================================================================<BR> * "ALP" is the NDEF-based set of low-level API protocols that OpenTag uses. * ALP messages can come-in over any communication method: wire, wireless, * telepathy... anything that can transfer a packet payload. * * Some ALPs are standardized. Those get handled by OTlib automatically. ALPs * that are not recognized are sent to this function to be handled. In this * demo, we are using a very simple ALP, shown below: * * ALP Payload Length: 0 * ALP Protocol ID: 255 (FF) * ALP Protocol Commands: 0-127 (00-7F) corresponding to channel to sniff * * The "user_id" parameter corresponds to the Device ID that sent this ALP. * * A quickstart guide to the ALP API is available on the Indigresso Wiki. * http://www.indigresso.com/wiki/doku.php?id=opentag:api:quickstart */ void otapi_alpext_proc(alp_tmpl* alp, id_tmpl* user_id) { /// The function app_invoke() will cause the kernel to call ext_systask() as /// soon as resources are available. vlFILE* fp; ot_uni16 scratch; ot_u8 channel; ot_u8 retval; // Start the task only if: Caller is ROOT, ALP Call is Protocol-255, Task is idle if ( auth_isroot(user_id) \ && (alp->inrec.id == 0xFF) \ && (APP_TASK.event == 0) ) { /// Make sure channel is spec-legal. If so, set the channel of the /// first (and only) in the channel list to the specified one, and also /// set the channel of the hold scan accordingly. By default, the scan /// is updated every second. The next scan will have these settings. retval = 0; channel = alp->inrec.cmd & 0x7F; if (((channel & 0xF0) <= 0x20) && ((channel & 0x0F) <= 0x0E)) { fp = ISF_open_su(ISF_ID(channel_configuration)); scratch.ushort = vl_read(fp, 0); scratch.ubyte[0] = channel; vl_write(fp, 0, scratch.ushort); vl_close(fp); fp = ISF_open_su(ISF_ID(hold_scan_sequence)); scratch.ushort = vl_read(fp, 0); scratch.ubyte[0] = channel; vl_write(fp, 0, scratch.ushort); vl_close(fp); retval = 1; //success } alp_load_retval(alp, retval); } }
ot_bool applet_beacon_discovery() { { //create a new session (it will get copied to session stack) session_tmpl session; session.channel = 0x00; session.flagmask = 0; session.flags = 0; session.subnet = 0; session.subnetmask = 0; session.timeout = 16; otapi_new_session(&session, NULL); } { //open request for broadcast otapi_open_request(ADDR_broadcast, NULL); } { //use a command template for collection of single file from single file search ot_u8 status; command_tmpl command; command.opcode = (ot_u8)CMD_announce_file; command.type = (ot_u8)CMDTYPE_na2p_request; command.extension = (ot_u8)CMDEXT_no_response; otapi_put_command_tmpl(&status, &command); } { //write the dialog information (timeout, channels to use) ot_u8 status; dialog_tmpl dialog; dialog.channels = 0; //use same channel as request for response dialog.timeout = 0; //0 tick response timeout (1 tick = 0,977 ms) otapi_put_dialog_tmpl(&status, &dialog); } { //write the ISF return data (note: use isfcall template) ot_u8 status; isfcall_tmpl isfcall; isfcall.is_series = False; isfcall.isf_id = ISF_ID(network_settings); isfcall.max_return = ISF_LEN(network_settings); isfcall.offset = 0; otapi_put_isf_return(&status, &isfcall); } //Done building command, close the request and send the dialog otapi_close_request(); //otapi_start_dialog(); return True; }
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, /* Mode 2 ISFs, written as little endian */ ISF_LEN(network_settings), 0x00, /* Length, little endian */ SPLIT_SHORT_LE(ISF_ALLOC(network_settings)), /* Alloc, little endian */ ISF_ID(network_settings), /* ID */ ISF_MOD(network_settings), /* Perms */ SPLIT_SHORT_LE(ISF_BASE(network_settings)), SPLIT_SHORT_LE(ISF_MIRROR(network_settings)), ISF_LEN(device_features), 0x00, SPLIT_SHORT_LE(ISF_ALLOC(device_features)), ISF_ID(device_features), ISF_MOD(device_features), SPLIT_SHORT_LE(ISF_BASE(device_features)), SPLIT_SHORT_LE(ISF_MIRROR(device_features)), ISF_LEN(channel_configuration), 0x00, SPLIT_SHORT_LE(ISF_ALLOC(channel_configuration)), ISF_ID(channel_configuration), ISF_MOD(channel_configuration),
void applet_send_query(m2session* session) { /// The C-API for building commands can be bypassed in favor of directly /// putting data to the queue. That way is more efficient, but it also requires /// you to know more about DASH7 than just what order the templates should be. /// /// The query that we build will collect sensor configuration data back from /// all devices that support the sensor protocol. Much more interesting queries /// are possible. { //open request for single hop anycast query routing_tmpl routing; routing.hop_code = 0; otapi_open_request(ADDR_anycast, &routing); } { //use a command template for collection of single file from single file search ot_u8 status; command_tmpl command; command.opcode = (ot_u8)CMD_collect_file_on_file; command.type = (ot_u8)CMDTYPE_na2p_request; command.extension = (ot_u8)CMDEXT_none; otapi_put_command_tmpl(&status, &command); } { //write the dialog information (timeout, channels to use) ot_u8 status; dialog_tmpl dialog; dialog.channels = 0; //use same channel as request for response dialog.timeout = 512; //512 tick response timeout (1 tick = 0,977 ms) otapi_put_dialog_tmpl(&status, &dialog); } { //write the query to search for the sensor protocol id query_tmpl query; ot_u8 status; ot_u8 protocol_id; protocol_id = 0x02; // sensor protocol id = 0x02 query.code = M2QC_COR_SEARCH | 1; // do a 100% length=1 correlation search query.mask = NULL; // don't do any masking (no partial matching) query.length = 1; // look for one byte (0x02) query.value = &protocol_id; // (query.value is a string) otapi_put_query_tmpl(&status, &query); } { //put in the information of the file to search (the protocol list) ot_u8 status; isfcomp_tmpl isfcomp; isfcomp.is_series = False; isfcomp.isf_id = ISF_ID(protocol_list); isfcomp.offset = 0; otapi_put_isf_comp(&status, &isfcomp); } { //put in the information of the file to return (the sensor list) ot_u8 status; isfcall_tmpl isfcall; isfcall.is_series = False; isfcall.isf_id = ISF_ID(sensor_list); isfcall.max_return = 32; isfcall.offset = 0; otapi_put_isf_call(&status, &isfcall); } //Done building command, close the request and send the dialog otapi_close_request(); }
ot_int network_route_ff(m2session* session) { ot_int route_val; /// Strip CRC (-2 bytes) rxq.front[0] -= 2; /// Acquire Flags and Protocol from the Frame Info Field rxq.getcursor = &rxq.front[3]; session->protocol = (*rxq.getcursor & M2FI_FRTYPEMASK); session->flags = *rxq.getcursor & 0xC0; m2np.header.fr_info = *rxq.getcursor++; /// Treat Non-Mode-2 Protocols /// @note Non-Mode-2 protocols not supported at this time if (m2np.header.fr_info & M2FI_NM2) { return -1; } /// Data Link Layer Security if (m2np.header.fr_info & M2FI_DLLS) { # if (OT_FEATURE(DLL_SECURITY)) ///@todo experimental AES_load_static_key(ISF_ID(user_authentication_key), (ot_u32*)txq.front); AES_keyschedule_dec((ot_u32*)txq.front, (ot_u32*)(txq.front+16)); AES_decrypt(rxq.getcursor, rxq.getcursor, (ot_u32*)(txq.front+16)); # else return -1; # endif } /// Address Control Header (Present in M2NP) /// Session Connection and Dialog Filtering: /// - if unassociated, connect now /// - if already connected, make sure the dialog IDs are equal if (m2np.header.fr_info & M2FI_ENADDR) { if (session->netstate & M2_NETSTATE_CONNECTED) { if (session->dialog_id != q_readbyte(&rxq)) { return -1; } } else { session->netstate |= M2_NETSTATE_CONNECTED; session->subnet = rxq.front[2]; session->dialog_id = q_readbyte(&rxq); } /// Grab global flags from Address Control m2np.header.addr_ctl = q_readbyte(&rxq); session->flags |= m2np.header.addr_ctl & 0x3F; /// Grab Source Address from this packet (dialog address), which is /// converted to the target address in the response. m2np.rt.dlog.length = (m2np.header.addr_ctl & M2_FLAG_VID) ? 2 : 8; m2np.rt.dlog.value = q_markbyte(&rxq, m2np.rt.dlog.length); /// Network Layer Security /// @note Network Layer Security not supported at this time if (m2np.header.addr_ctl & M2_FLAG_NLS) { # if (OT_FEATURE(NL_SECURITY)) # else return -1; # endif } /// If unicasting, the next data is the target address, which will have /// the same length as the source address, and it needs to match this /// device's device ID (VID or UID) if ((m2np.header.addr_ctl & 0xC0) == 0) { session->netstate |= M2_NETFLAG_FIRSTRX; if ( !m2np_idcmp(m2np.rt.dlog.length, q_markbyte(&rxq, m2np.rt.dlog.length)) ) { return -1; } } } /// Vector to the appropriate Network Layer Protocol Parser /// Most network protocols don't do anything except broadcast. M2NP is the /// exception, and it manages various types of routing at the network layer. route_val = -1; switch (session->protocol & M2FI_FRTYPEMASK) { case M2FI_FRDIALOG: case M2FI_FRNACK: { // Reset routing template m2np.rt.hop_code = 0; m2np.rt.hop_ext = 0; m2np.rt.orig.value = NULL; m2np.rt.dest.value = NULL; /// Unicast and Anycast Requests have a routing template /// (Not currently supported, so just move the cursor ahead) if ((m2np.header.addr_ctl & 0x40) == 0) { m2np.rt.hop_code = q_readbyte(&rxq); m2np.rt.orig.length = ((m2np.rt.hop_code & M2HC_VID) != 0) ? 2 : 8; m2np.rt.dest.length = m2np.rt.orig.length; if ((m2np.rt.hop_code & M2HC_EXT) != 0) { m2np.rt.hop_ext = q_readbyte(&rxq); } if ((m2np.rt.hop_code & M2HC_ORIG) != 0) { m2np.rt.orig.value = q_markbyte(&rxq, m2np.rt.orig.length); } if ((m2np.rt.hop_code & M2HC_DEST) != 0) { m2np.rt.dest.value = q_markbyte(&rxq, m2np.rt.dest.length); } } } // Note case fall-through case M2FI_STREAM: { /// M2DP gets parsed just like M2NP, but it uses the Network data /// stored from the last M2NP frame route_val = m2qp_parse_frame(session); break; } case M2FI_RFU: break; } /// Attach footer to response, if necessary if (route_val >= 0) { m2np_footer(session); } # if (OT_FEATURE(M2NP_CALLBACKS) == ENABLED) && \ !defined(EXTF_network_sig_route) m2np.signal.route(route_val, session->protocol); # elif defined(EXTF_network_sig_route) network_sig_route(route_val, session->protocol); # endif return route_val; }