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 AES_load_static_key(ot_u8 key_id, ot_u32* key) { ot_int i; vlFILE* fp; fp = ISF_open_su(key_id); for (i=0; i<16; i+=2) { *(ot_u16*)((ot_u8*)key+i) = vl_read(fp, i); } vl_close(fp); }
OT_WEAK void dll_refresh(void) { ot_uni16 scratch; vlFILE* fp; /// Open Network Features ISF and load the values from that file into the /// cached dll.netconf settings. fp = ISF_open_su(0); vl_load(fp, 10, dll.netconf.vid); dll.netconf.dd_flags = 0; dll.netconf.hold_limit = PLATFORM_ENDIAN16(dll.netconf.hold_limit); vl_close(fp); fp = ISF_open_su(1); vl_load(fp, 8, dll.netconf.uid); vl_close(fp); // Reset the Scheduler (only does anything if scheduler is implemented) dll_refresh_rts(); sub_dll_flush(); }
void sub_build_uhfmsg(ot_int* buffer) { /// This is the routine that builds the DASH7 UDP generic protocol message. /// The protocol has data elements marked by a letter (T, V, R, E, D) that /// signify Temperature, Voltage, RSSI (LF), PaLFi wake Event, and RX Data. /// The elements are fixed/known length. command_tmpl c_tmpl; ot_u8* data_start; ot_u8 status; // Broadcast request (takes no 2nd argument) otapi_open_request(ADDR_broadcast, NULL); // Insert Transport-Layer headers c_tmpl.type = CMDTYPE_na2p_request; c_tmpl.opcode = CMD_udp_on_file; c_tmpl.extension= CMDEXT_no_response; otapi_put_command_tmpl(&status, &c_tmpl); otapi_put_dialog_tmpl(&status, NULL); // NULL = defaults // UDP Header q_writebyte(&txq, 255); // Source Port: 255 (custom application port) q_writebyte(&txq, 255); // Destination Port (same value) data_start = txq.putcursor; // Place temperature data q_writebyte(&txq, 'T'); q_writeshort(&txq, buffer[0]); // Place Voltage data q_writebyte(&txq, 'V'); q_writeshort(&txq, buffer[1]); // Place RSSI data q_writebyte(&txq, 'R'); q_writeshort(&txq, radio.last_rssi); // Store this information into the Port 255 file for continuous, automated // reporting by DASH7/OpenTag until it is updated next time. The length of // this information is always 6 bytes. { vlFILE* fp; fp = ISF_open_su(255); if (fp != NULL) { vl_store(fp, 6, data_start); vl_close(fp); } } // Finish Message 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_WEAK void dll_change_settings(ot_u16 new_mask, ot_u16 new_settings) { vlFILE* fp_active; vlFILE* fp_supported; // Get Active Settings, Get Supported Settings, // Mask-out unsupported settings, apply to new active settings ///@todo assert fp fp_active = ISF_open_su( 0x00 ); fp_supported = ISF_open_su( 0x01 ); new_mask &= vl_read(fp_supported, 8); dll.netconf.active = vl_read(fp_active, 4); new_settings &= new_mask; dll.netconf.active &= ~new_mask; dll.netconf.active |= new_settings; // Write the new settings to the ISF 0 vl_write(fp_active, 4, dll.netconf.active); vl_close(fp_active); vl_close(fp_supported); // Flush the System of all Sessions and Events, and restart it sub_dll_flush(); }
void m2np_put_deviceid(ot_bool use_vid) { vlFILE* fp; //file 0=network_settings, 1=device_features fp = ISF_open_su( (ot_u8)(use_vid == False) ); ///@todo assert fp q_writeshort_be( &txq, vl_read(fp, 0) ); if (use_vid == False) { q_writeshort_be( &txq, vl_read(fp, 2) ); q_writeshort_be( &txq, vl_read(fp, 4) ); q_writeshort_be( &txq, vl_read(fp, 6) ); } vl_close(fp); }
ot_bool m2np_idcmp(ot_int length, void* id) { ot_bool check = True; ot_u8 use_uid = (length == 8); vlFILE* fp; //file 0=network_settings, 1=device_features fp = ISF_open_su( use_uid ); check &= ( ((ot_u16*)id)[0] == vl_read(fp, 0)); if (use_uid) { check &= ( ((ot_u16*)id)[1] == vl_read(fp, 2) ); check &= ( ((ot_u16*)id)[2] == vl_read(fp, 4) ); check &= ( ((ot_u16*)id)[3] == vl_read(fp, 6) ); } vl_close(fp); return check; }
OT_WEAK void dll_systask_sleepscan(ot_task task) { /// The Sleep Scan process runs as an independent task. It is very similar /// to the Hold Scan process, which actually calls this same routine. They /// use independent task markers, however, so they behave differently. ot_u8 s_channel; ot_u8 s_code; ot_uni16 scratch; vlFILE* fp; m2session* s_new; /// event = 0 is the initializer, but there is no state-based operation /// or any heap-stored data for this task, so it does nothing if (task->event == 0) { return; } fp = ISF_open_su( task->event ); ///@note fp doesn't really need to be asserted unless you are mucking /// with things in test builds. /// Pull channel ID and Scan flags scratch.ushort = vl_read(fp, task->cursor); s_channel = scratch.ubyte[0]; s_code = scratch.ubyte[1]; /// Set the next idle event from the two-byte Next Scan field. /// The DASH7 registry is big-endian. scratch.ushort = PLATFORM_ENDIAN16( vl_read(fp, (task->cursor)+=2 ) ); sys_task_setnext(task, scratch.ushort); /// Advance cursor to next datum, go back to 0 if end of sequence /// (still works in special case where cursor = 254) task->cursor += 2; task->cursor = (task->cursor >= fp->length) ? 0 : task->cursor; vl_close(fp); /// Choosing Background-Scan or Foreground-Scan is based on scan-code. /// If b7 is set, do a Background-Scan. At the session level, the "Flood" /// select uses b6, which is why there is a >> 1. s_new = session_new(&dll_scan_applet, 0, s_channel, ((M2_NETSTATE_REQRX | M2_NETSTATE_INIT) | (s_code & 0x80) >> 1) ); s_new->extra = s_code; }
OT_WEAK void dll_refresh_rts(void) { #if (OT_FEATURE(CRON) && M2_FEATURE(RTC_SCHEDULER)) ///@todo need to update this implementation to also delete the old tasks. vlFILE* fp; // Early exit if RTS is not active if (dll.netconf.active_settings & M2_SET_SCHEDMASK) == 0) return; // - open the real-time-schedule ISF // - make sure the file is there // - make sure the file has at least 12 bytes (this is how much DLL uses) fp = ISF_open_su(ISF_ID_real_time_scheduler); if (fp != NULL) { if (fp->length < 12) { static const ot_task task_fn[3] = { &dll_systask_holdscan, &dll_systask_sleepscan, &dll_systask_beacon }; ot_u16 sched_enable = dll.netconf.active_settings & M2_SET_SCHEDMASK; ot_u16 cursor = 0; ot_sigv* fn = task_fn; // Apply Hold, Sleep, and Beacon RTS as specified in enabler bitmask while (sched_enable != 0) { if (sched_enable & M2_SET_HOLDSCHED) { ot_u32 time_evt; ot_u32 time_mask; time_evt = vl_read(fp, cursor); time_mask = 0xFFFF0000 | vl_read(fp, cursor+2); otcron_add(*fn, CRONTIME_absolute, time_evt, time_mask); } fn++; cursor += 4; sched_enable <<= 1; } } vl_close(fp); } #endif }
void sub_build_uhfmsg(ot_int* buffer) { /// This is the routine that builds the DASH7 UDP generic protocol message. /// The protocol has data elements marked by a letter (T, V, R, E, D) that /// signify Temperature, Voltage, RSSI (LF), PaLFi wake Event, and RX Data. /// The elements are fixed/known length. session_tmpl s_tmpl; command_tmpl c_tmpl; ot_u8* data_start; ot_u8 status; // Create a new session: you could change these parameters // Use "CHAN1" for odd events, "CHAN2" for even events s_tmpl.channel = (palfi.wake_event & 1) ? ALERT_CHAN1 : ALERT_CHAN2; s_tmpl.subnetmask = 0; // Use default subnet s_tmpl.flagmask = 0; // Use default app-flags s_tmpl.timeout = 10; // Do CSMA for no more than 10 ticks (~10 ms) otapi_new_session(&s_tmpl); // Broadcast request (takes no 2nd argument) otapi_open_request(ADDR_broadcast, NULL); // Insert Transport-Layer headers c_tmpl.type = CMDTYPE_na2p_request; c_tmpl.opcode = CMD_udp_on_file; c_tmpl.extension= CMDEXT_no_response; otapi_put_command_tmpl(&status, &c_tmpl); otapi_put_dialog_tmpl(&status, NULL); // NULL = defaults // UDP Header q_writebyte(&txq, 255); // Source Port: 255 (custom application port) q_writebyte(&txq, 255); // Destination Port (same value) data_start = txq.putcursor; // Place temperature data q_writebyte(&txq, 'T'); q_writeshort(&txq, buffer[0]); // Place Voltage data q_writebyte(&txq, 'V'); q_writeshort(&txq, buffer[1]); // Place RSSI data q_writebyte(&txq, 'R'); q_writestring(&txq, (ot_u8*)&palfi.rssi1, 3); // Place Action data q_writebyte(&txq, 'E'); q_writebyte(&txq, (ot_int)palfi.wake_event); // Dump some received data if (palfi.wake_event) { q_writebyte(&txq, 'D'); q_writestring(&txq, palfi.rxdata, 8); } // Store this information into the Port 255 file for continuous, automated // reporting by DASH7/OpenTag until it is updated next time. The length of // this information is always 23 bytes. { vlFILE* fp; fp = ISF_open_su(255); if (fp != NULL) { vl_store(fp, 23, data_start); vl_close(fp); } } // Finish Message otapi_close_request(); }