void sub_proc_media() { if (*alp->inq->getcursor++ != 'd') { //error must be standard DASH7 } else { dashcom.advert.channel = *alp->inq->getcursor++; dashcom.session.channel = *alp->inq->getcursor++; dashcom.session.subnet = *alp->inq->getcursor++; dashcom.session.subnetmask = *alp->inq->getcursor++; dashcom.advert.duration = q_readshort(alp->inq); dashcom.extra.csma_timeout = q_readshort(alp->inq); dashcom.extra.comm_timeout = q_readshort(alp->inq); } }
ot_int sub_filecreate(alp_tmpl* alp, id_tmpl* user_id, ot_u8 respond, ot_u8 cmd_in, ot_int data_in) { ot_int data_out = 0; vlBLOCK file_block = (vlBLOCK)((cmd_in >> 4) & 0x07); while ((data_in > 0) && sub_qnotfull(respond, 2, alp->outq)) { vlFILE* fp = NULL; ot_u8 id; ot_u8 mod; ot_u16 alloc; ot_u8 err_code; data_in -= 6; id = *alp->inq->getcursor++; mod = *alp->inq->getcursor; alp->inq->getcursor+= 3; // cursor goes past mod+length (length ignored) alloc = q_readshort(alp->inq); err_code = vl_new(&fp, file_block, id, mod, alloc, user_id); if (respond) { q_writebyte(alp->outq, id); q_writebyte(alp->outq, err_code); data_out += 2; } vl_close(fp); } //alp->BOOKMARK_IN = (void*)sub_testchunk(data_in); return data_out; }
void sub_get_file(dc_filetmpl* attachpoint) { /// Only add resource if necessary, and breakdown input template if (*alp->inq->getcursor++ != 'a') { handle = (dc_filetmpl*)sub_add_template(sizeof(dc_filetmple)); handle->next = NULL; handle->last = dashcom.filelist; dashcom.filelist->next = handle; dashcom.filelist = handle; dashcom.filelist->block = *alp->inq->getcursor++; dashcom.filelist->id = *alp->inq->getcursor++; dashcom.filelist->offset = q_readshort(alp->inq); dashcom.filelist->length = q_readshort(alp->inq); } /// Attach the file, either new one or the last one attachpoint = dashcom.filelist; }
OT_WEAK void alp_breakdown_udp_tmpl(ot_queue* in_q, void* data_type) { ot_int udp_data_length; udp_data_length = q_readshort(in_q); ((udp_tmpl*)data_type)->data_length = udp_data_length; ((udp_tmpl*)data_type)->dst_port = q_readbyte(in_q); ((udp_tmpl*)data_type)->src_port = q_readbyte(in_q); ((udp_tmpl*)data_type)->data = q_markbyte(in_q, udp_data_length); }
ot_bool m2qp_sig_udp(ot_u8 srcport, ot_u8 dstport, id_tmpl* user_id) { static const char* label[] = { "PongID: ", ", RSSI: ", ", Link: " }; ot_u16 pongval; ot_u8 i; ot_u8 scratch; //1. Read the PONG VAL pongval = q_readshort(&rxq); // Request: Copy PING VAL to PONG if (dstport == 254) { q_writeshort(&txq, pongval); return True; } # if defined(BOARD_eZ430Chronos) // Chronos doesn't have a normal MPipe, so print-out responses on the LCD # else // Response: Compare PING Val to PONG Val and write output to MPipe if ((dstport == 255) && (app.pingval == pongval)) { // Prepare logging header: UTF8 (text log) is subcode 1, dummy length is 0 otapi_log_header(1, 0); // Print out the three parameters for PongLT, one at a time. // If you are new to OpenTag, this is a common example of a state- // based code structure JP likes to use. i = 0; while (1) { q_writestring(mpipe.alp.outq, (ot_u8*)label[i], 8); switch (i++) { case 0: scratch = otutils_bin2hex( mpipe.alp.outq->putcursor, user_id->value, user_id->length ); break; case 1: scratch = otutils_int2dec(mpipe.alp.outq->putcursor, radio.last_rssi); break; case 2: scratch = otutils_int2dec(mpipe.alp.outq->putcursor, dll.last_nrssi); break; case 3: goto m2qp_sig_udp_PRINTDONE; } mpipe.alp.outq->putcursor += scratch; mpipe.alp.outq->length += scratch; } // Close the log file, send it out, return success m2qp_sig_udp_PRINTDONE: otapi_log_direct(); return True; } # endif return False; }
ot_u16 q_readshort_be(ot_queue* q) { # ifdef __BIG_ENDIAN__ return q_readshort(q); # else ot_uni16 data; data.ubyte[0] = q->getcursor[0]; data.ubyte[1] = q->getcursor[1]; q->getcursor += 2; return data.ushort; # endif }
uint16_t q_readshort_be(ot_queue* q) { # ifdef __BIG_ENDIAN__ return q_readshort(q); # else ot_uni16 data; data.ubyte[0] = *q->getcursor++; data.ubyte[1] = *q->getcursor++; return data.ushort; # endif }
OT_WEAK void alp_breakdown_queue(ot_queue* in_q, void* data_type) { ot_u16 queue_length; ot_u8* queue_front; queue_length = q_readshort(in_q); ((ot_queue*)data_type)->alloc = queue_length; ((ot_queue*)data_type)->options = in_q->options; queue_front = q_markbyte(in_q, queue_length); ((ot_queue*)data_type)->front = queue_front; ((ot_queue*)data_type)->back = queue_front+queue_length; ((ot_queue*)data_type)->getcursor = queue_front; ((ot_queue*)data_type)->putcursor = queue_front; }
ot_int sub_filedata( alp_tmpl* alp, id_tmpl* user_id, ot_u8 respond, ot_u8 cmd_in, ot_int data_in ) { vlFILE* fp; ot_u16 offset; ot_u16 span; ot_int data_out = 0; ot_bool inc_header = (ot_bool)((cmd_in & 0x0F) == 0x0C); vlBLOCK file_block = (vlBLOCK)((cmd_in >> 4) & 0x07); ot_u8 file_mod = ((cmd_in & 0x02) ? VL_ACCESS_W : VL_ACCESS_R); ot_queue* inq = alp->inq; ot_queue* outq = alp->outq; sub_filedata_TOP: while (data_in > 0) { vaddr header; ot_u8 err_code; ot_u8 file_id; ot_u16 limit; //alp->BOOKMARK_IN = inq->getcursor; //alp->BOOKMARK_OUT = NULL; file_id = q_readbyte(inq); offset = q_readshort(inq); span = q_readshort(inq); limit = offset + span; err_code = vl_getheader_vaddr(&header, file_block, file_id, file_mod, user_id); file_mod = ((file_mod & VL_ACCESS_W) != 0); //fp = NULL; // A. File error catcher Stage // (In this case, gotos make it more readable) /// Make sure file header was retrieved properly, or goto error if (err_code != 0) { goto sub_filedata_senderror; } /// Make sure file opens properly, or goto error fp = vl_open_file(header); if (fp == NULL) { err_code = 0xFF; goto sub_filedata_senderror; } /// Make sure offset is within file bounds, or goto error if (offset >= fp->alloc) { err_code = 0x07; goto sub_filedata_senderror; } if (limit > fp->alloc) { limit = fp->alloc; err_code = 0x08; } // B. File Writing or Reading Stage // Write to file // 1. Process error on bad ALP parameters, but still do partial write // 2. offset, span are adjusted to convey leftover data // 3. miscellaneous write error occurs when vl_write fails if (file_mod) { for (; offset<limit; offset+=2, span-=2, data_in-=2) { if (inq->getcursor >= inq->back) { goto sub_filedata_overrun; } err_code |= vl_write(fp, offset, q_readshort_be(inq)); } } // Read from File // 1. No error for bad read parameter, just fix the limit // 2. If inc_header param is set, include the file header in output // 3. Read out file data else { ot_u8 overhead; //limit = (limit > fp->length) ? fp->length : limit; overhead = 6; overhead += (inc_header != 0) << 2; if ((outq->putcursor+overhead) >= outq->back) { goto sub_filedata_overrun; } q_writeshort_be(outq, vworm_read(header + 4)); // id & mod if (inc_header) { q_writeshort(outq, vworm_read(header + 0)); // length q_writeshort(outq, vworm_read(header + 2)); // alloc data_out += 4; } q_writeshort(outq, offset); q_writeshort(outq, span); data_out += 6; for (; offset<limit; offset+=2, span-=2, data_out+=2) { if ((outq->putcursor+2) >= outq->back) { goto sub_filedata_overrun; } q_writeshort_be(outq, vl_read(fp, offset)); } } // C. Error Sending Stage sub_filedata_senderror: if ((respond != 0) && (err_code | file_mod)) { if ((outq->putcursor+2) >= outq->back) { goto sub_filedata_overrun; } q_writebyte(outq, file_id); q_writebyte(outq, err_code); q_markbyte(inq, span); // go past any leftover input data data_out += 2; } data_in -= 5; // 5 bytes input header vl_close(fp); } // Total Completion: // Set bookmark to NULL, because the record was completely processed //alp->BOOKMARK_IN = NULL; return data_out; // Partial or Non Completion: // Reconfigure last ALP operation, because it was not completely processed ///@todo Bookmarking is obsolete, because the way Chunking is done has /// been revised. Chunked records must be contiguous. ALP-Main will not /// call this app, and thus not call this function, until the message-end /// bit is detected, therefore meaning that all data is received and /// contiguous. This overrun block, thus, should only check the flags for /// chunking, bypass them, and loop back to the top of this function. sub_filedata_overrun: vl_close(fp); ///@todo alp_next_chunk(alp); // { // ot_u8* scratch; // inq->getcursor = (ot_u8*)alp->BOOKMARK_IN; // scratch = inq->getcursor + 1; // *scratch++ = ((ot_u8*)&offset)[UPPER]; // *scratch++ = ((ot_u8*)&offset)[LOWER]; // *scratch++ = ((ot_u8*)&span)[UPPER]; // *scratch = ((ot_u8*)&span)[LOWER]; // } return data_out; }
ot_int sub_parse_response(m2session* session) { /// Only Gateways and Subcontrollers do anything with the response. Generally, /// Gateways might have some sort of logging in the callbacks. Response types /// include: (1) Normal responses to NA2P standard dialog, (2) Arbitrated /// responses to A2P multicast dialog, (3) Responses that are part of 2, 3, 4, /// or 5-way datastream session. ot_u8 test; ot_u8 cmd_opcode; /// Make sure response command opcode matches the last request's opcode /// (this ensures that the response is to our request). cmd_opcode = m2qp.cmd.code & 0x0F; test = q_readbyte(&rxq) & 0x0F; if (test == cmd_opcode) { # if ((M2_FEATURE(DATASTREAM) == ENABLED) && (OT_FEATURE(ALP) == ENABLED)) /// Manage Responses to Request and Propose Datastream if ((cmd_opcode - M2OP_DS_REQUEST) <= 1) { ot_u16 ds_total_bytes = q_readshort(&rxq); // might be removed ot_u8 fr_per_pkt = q_readbyte(&rxq); // might be removed ot_u8 num_frames = rxq.getcursor[0]; // might be removed rxq.getcursor += ((cmd_opcode & 1) == 0); m2dp.out_rec.flags = ALP_FLAG_MB; // ds beginning // Run Callback (if enabled). Callback can override processing // (Callback is not compiled when callbacks are disabled) test = (ot_u8)M2QP_CALLBACK(DSPKT); if ( test ) { m2dp_dsproc(); } ///@todo Might put in some type of return scoring, later return (ot_int)test; } # if (OT_FEATURE(M2QP_CALLBACKS) == ENABLED) else if (cmd_opcode == 10) { test = (ot_u8)M2QP_CALLBACK(DSACK); if ( test ) { ///@todo Prepare the next stream packet } return (ot_int)test; } # endif else if (((m2qp.cmd.code & 0x60) == 0x40) && \ ((txq.back - txq.putcursor) > 48) ) # else //((M2_FEATURE(DATASTREAM) == ENABLED) && (OT_FEATURE(ALP) == ENABLED)) if (((m2qp.cmd.code & 0x60) == 0x40) && \ ((txq.back - txq.putcursor) > 48) ) # endif /// If using A2P, put this responder's ID onto the ACK chain <BR> /// - Reserve some room at the back for query data (48 bytes) <BR> /// - Increment "Number of ACKs" on each use (txq.getcursor[0]) <BR> /// - Run the A2P callback (if enabled) { ///@todo check to make sure NumACKs is 0 on 1st run (might be done) ///@todo Might put in some type of return scoring, later txq.getcursor[0]++; q_writestring(&txq, m2np.rt.dlog.value, m2np.rt.dlog.length); test = (ot_u8)M2QP_CALLBACK(A2P); } /// If nothing else, the response is a normal response (NA2P), so run /// the callback as normal else { test = (ot_u8)M2QP_CALLBACK(STANDARD); } /// Make into 0/-1 form for returning return (ot_int)test - 1; } }
OT_WEAK void alp_breakdown_u16(ot_queue* in_q, void* data_type) { *(ot_u16*)data_type = q_readshort(in_q); }
OT_WEAK void alp_breakdown_isfcall_tmpl(ot_queue* in_q, void* data_type) { alp_breakdown_isfcomp_tmpl(in_q, data_type); ((isfcall_tmpl*)data_type)->max_return = q_readshort(in_q); }
OT_WEAK void alp_breakdown_isfcomp_tmpl(ot_queue* in_q, void* data_type) { ((isfcomp_tmpl*)data_type)->is_series = q_readbyte(in_q); ((isfcomp_tmpl*)data_type)->isf_id = q_readbyte(in_q); ((isfcomp_tmpl*)data_type)->offset = q_readshort(in_q); }
OT_WEAK void alp_breakdown_advert_tmpl(ot_queue* in_q, void* data_type) { q_readstring(in_q, (ot_u8*)data_type, 4); ((advert_tmpl*)data_type)->duration = q_readshort(in_q); }