void mpipedrv_tx(ot_bool blocking, mpipe_priority data_priority) {
/// @note Using blocking: OpenTag currently does not implement blocking TX,
///       because it can interfere with time-critical radio processes.  You can
///       achieve a similar affect by calling "mpipedrv_wait()" after a logging
///       function call, if you need blocking on certain transmissions.

    if (mpipe.state == MPIPE_Idle) {
        ot_u8* data;
    	ot_u16 scratch;
        mpipe.state = MPIPE_Tx_Done;
    
        q_writeshort(mpipe.alp.outq, tty.seq.ushort);                // Sequence Number

        ///@todo remove CRC part, not necessary for USB.  
        /// Requires coordination with OTcom, though: need to add a checkbox
        scratch = mpipe.alp.outq->putcursor - mpipe.alp.outq->getcursor;    //data length
        scratch = crc16drv_block(mpipe.alp.outq->getcursor, scratch);   //CRC value
        q_writeshort(mpipe.alp.outq, scratch);                              //Put CRC
        
        scratch                     = mpipe.alp.outq->putcursor \
                                    - mpipe.alp.outq->getcursor;            //data length w/ CRC
        data                        = mpipe.alp.outq->getcursor;            //data start
        mpipe.alp.outq->getcursor   = mpipe.alp.outq->putcursor;            //move queue past packet
        
        usbcdc_txdata(data, scratch, CDC0_INTFNUM);

        // Wait for the USB transmission to complete (optional).
        if (blocking) {
        	mpipedrv_wait();
        }
    }
}
Example #2
0
OT_WEAK void alp_stream_dialog_tmpl(ot_queue* out_q, void* data_type) { 
    if _PTR_TEST(data_type) {
        q_writeshort(out_q, ((dialog_tmpl*)data_type)->timeout);
        q_writeshort(out_q, ((dialog_tmpl*)data_type)->channels);
        q_writestring(out_q, ((dialog_tmpl*)data_type)->chanlist, ((dialog_tmpl*)data_type)->channels); 
    }
}
Example #3
0
ot_int sub_fileheaders( 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);

    /// Only run if respond bit is set!
    if (respond) {
        while ((data_in > 0) && sub_qnotfull(respond, 6, alp->outq)) {
            vaddr   header;
            ot_bool allow_output = True;
            
            data_in--;  // one for the file id
            
            allow_output = (ot_bool)(vl_getheader_vaddr(&header, file_block, \
                                    q_readbyte(alp->inq), VL_ACCESS_R, NULL) == 0);
            if (allow_output) {
                q_writeshort_be(alp->outq, vworm_read(header + 4)); // id & mod
                q_writeshort(alp->outq, vworm_read(header + 0)); // length
                q_writeshort(alp->outq, vworm_read(header + 2)); // alloc
                data_out += 6;
            }
        }
        
        //alp->BOOKMARK_IN = (void*)sub_testchunk(data_in);
    }
    
    return data_out; 
}
Example #4
0
OT_WEAK void alp_stream_queue(ot_queue* out_q, void* data_type) { 
    if _PTR_TEST(data_type) {
    	ot_int length;
    	length = q_length((ot_queue*)data_type);
        q_writeshort(out_q, ((ot_queue*)data_type)->alloc);
        q_writeshort(out_q, ((ot_queue*)data_type)->options.ushort);
        q_writeshort(out_q, length);
        q_writestring(out_q, ((ot_queue*)data_type)->front, length);     
    }
}
Example #5
0
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();
}
void mpipe_txndef(ot_u8* data, ot_bool blocking, mpipe_priority data_priority) {
/// Data TX will only occur if this function is called when the MPipe state is
/// idle.  The exception is when the function is called with ACK priority, in
/// which case the state doesn't need to be Idle.  Lastly, if you specify the 
/// blocking parameter, the function will not return until the packet is 
/// completely transmitted.
    ot_int      data_length;

#if (MPIPE_USE_ACKS)
    if (data_priority == MPIPE_Ack)) {
        mpipe.priority  = data_priority;
        goto mpipe_txndef_SETUP;
    }
#endif
    if (mpipe.state == MPIPE_Idle) {
        mpipe.state     = MPIPE_Tx_Wait;
        mpipe_txndef_SETUP:
        MPIPE_DMAEN(OFF);

#       if (MPIPE_DMANUM == 0)
        DMA->CTL0  |= MPIPE_UART_TXTRIG;
#       elif (MPIPE_DMANUM == 1)
        DMA->CTL0  |= (MPIPE_UART_TXTRIG << 8);
#       elif (MPIPE_DMANUM == 2)
        DMA->CTL1   = MPIPE_UART_TXTRIG;
#       endif

        DMA->CTL4 = (   DMA_Options_RMWDisable | \
                        DMA_Options_RoundRobinDisable | \
                        DMA_Options_ENMIEnable  );

        // Sequence Number
        q_writeshort(mpipe_alp.outq, mpipe.sequence.ushort);

        // Data alignment
        data                        = mpipe_alp.outq->getcursor;
        data_length                 = mpipe_alp.outq->putcursor \
        		                    - mpipe_alp.outq->getcursor;
        // CRC
        q_writeshort(mpipe_alp.outq, platform_crc_block(data, data_length));
        data_length                += 2;
        mpipe_alp.outq->getcursor   = mpipe_alp.outq->putcursor;

        MPIPE_DMA_TXCONFIG(data, data_length, ON);
        UART_OPEN();
        MPIPE_DMA_TXTRIGGER();

        if (blocking) {
           mpipe_wait();
        }
    }
}
Example #7
0
void mpipe_txndef(ot_u8* data, ot_bool blocking, mpipe_priority data_priority) {
/// Data TX will only occur if this function is called when the MPipe state is
/// idle.  The exception is when the function is called with ACK priority, in
/// which case the state doesn't need to be Idle.  Lastly, if you specify the 
/// blocking parameter, the function will not return until the packet is 
/// completely transmitted.
    ot_u16 scratch;

#if (MPIPE_USE_ACKS)
    if (data_priority == MPIPE_Ack)) {
        mpipe.priority  = data_priority;
        goto mpipe_txndef_SETUP;
    }
#endif
    if (mpipe.state == MPIPE_Idle) {
        mpipe.state     = MPIPE_Tx_Done; //MPIPE_Tx_Wait;
        mpipe_txndef_SETUP:
        MPIPE_DMAEN(OFF);

#       if (MPIPE_DMANUM == 0)
        DMA->CTL0  |= MPIPE_UART_TXTRIG;
#       elif (MPIPE_DMANUM == 1)
        DMA->CTL0  |= (MPIPE_UART_TXTRIG << 8);
#       elif (MPIPE_DMANUM == 2)
        DMA->CTL1   = MPIPE_UART_TXTRIG;
#       endif

        q_writeshort(mpipe_alp.outq, mpipe.sequence.ushort);                // Sequence Number

        scratch = mpipe_alp.outq->putcursor - mpipe_alp.outq->getcursor;    //data length
        scratch = platform_crc_block(mpipe_alp.outq->getcursor, scratch);   //CRC value
        q_writeshort(mpipe_alp.outq, scratch);                              //Put CRC
        
        scratch                     = mpipe_alp.outq->putcursor \
                                    - mpipe_alp.outq->getcursor;            //data length w/ CRC
        data                        = mpipe_alp.outq->getcursor;            //data start
        mpipe_alp.outq->getcursor   = mpipe_alp.outq->putcursor;            //move queue past packet

        // DMA setup
        MPIPE_DMA_TXCONFIG(data, scratch, ON);
        UART_OPEN();
        MPIPE_DMA_TXTRIGGER();

        if (blocking) {
           mpipe_wait();
        }
    }
}
Example #8
0
OT_WEAK void alp_stream_isfcomp_tmpl(ot_queue* out_q, void* data_type) { 
    if _PTR_TEST(data_type) {
        q_writebyte(out_q, ((isfcomp_tmpl*)data_type)->is_series);
        q_writebyte(out_q, ((isfcomp_tmpl*)data_type)->isf_id);
        q_writeshort(out_q, ((isfcomp_tmpl*)data_type)->offset);
    }
}
Example #9
0
OT_WEAK void alp_stream_udp_tmpl(ot_queue* out_q, void* data_type) { 
    if _PTR_TEST(data_type) {
        q_writeshort(out_q, ((udp_tmpl*)data_type)->data_length);
        q_writebyte(out_q, ((udp_tmpl*)data_type)->dst_port);
        q_writebyte(out_q, ((udp_tmpl*)data_type)->src_port);
        q_writestring(out_q, ((udp_tmpl*)data_type)->data, ((udp_tmpl*)data_type)->data_length);
    }
}
Example #10
0
void m2advp_open(m2session* session) {
    q_start(&txq, 1, 0);
    txq.front[0] = 7;
    q_writebyte(&txq, session->subnet);
    q_writebyte(&txq, 0xF0);
    q_writebyte(&txq, session->channel);
    q_writeshort(&txq, session->counter);
}
Example #11
0
OT_WEAK void sub_put_isf_offset(ot_u8 is_series, ot_u16 offset) {
    if (is_series) {
        q_writeshort(&txq, offset);
    }
    else {
        q_writebyte(&txq, (ot_u8)offset);
    }
}
Example #12
0
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;
}
Example #13
0
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();
}
Example #14
0
void q_writeshort_be(ot_queue* q, uint16_t short_in) {
#   ifdef __BIG_ENDIAN__
    q_writeshort(q, short_in);

#   else
    uint8_t* data;
    data            = (uint8_t*)&short_in;
    *q->putcursor++ = data[0];
    *q->putcursor++ = data[1];

    //#q->length     += 2;
#   endif
}
Example #15
0
OT_WEAK ot_bool alp_load_retval(alp_tmpl* alp, ot_u16 retval) {
/// This function is for writing a two-byte integer to the return record.  It
/// is useful for some types of API return sequences
    ot_bool respond = (ot_bool)(alp->OUTREC(CMD) & 0x80);

    if (respond)  {
      //alp->OUTREC(FLAGS)          &= ~ALP_FLAG_CF;
        alp->OUTREC(PLEN) = 2;
        alp->OUTREC(CMD)    |= 0x40;
        q_writeshort(alp->outq, retval);
    }
    
    return respond;
}
Example #16
0
void q_writeshort_be(ot_queue* q, ot_uint short_in) {
#   ifdef __BIG_ENDIAN__
        q_writeshort(q, short_in);

#   else
        ot_u8* data;
        data = (ot_u8*)&short_in;

        q->putcursor[0] = data[0];
        q->putcursor[1] = data[1];

        q->putcursor  += 2;
        q->length     += 2;
#   endif
}
Example #17
0
OT_WEAK ot_bool alp_proc_api_query(alp_tmpl* alp, id_tmpl* user_id ) {
/// The M2QP API calls follow the rules that future extensions to the API shall
/// abide, apart from special cases which *must* be cleared by the developer
/// community prior to becoming official.
/// The form is: ot_u16 otapi_function(ot_u8*, void*)
    static const ot_u8 argmap[OTAPI_M2QP_FUNCTIONS] = \
        { 6, 9, 10, 11, 12, 13, 14, 14, 15, 0, 0 };

    //sub_bdtmpl  get_tmpl;
    ot_u8   dt_buf[24];   // 24 bytes is a safe amount, although less might suffice
    ot_u16  txq_len;
    ot_u8   status          = alp->inq->getcursor[3];    // record cmd
    ot_u8   lookup_cmd      = (status & ~0x80) - 1;
    ot_bool respond         = (ot_bool)(status & 0x80);
    
    alp->inq->getcursor    += 4;
    
    if ((lookup_cmd < OTAPI_M2QP_FUNCTIONS) && auth_isroot(user_id)) {
        /// Load template from ALP dir cmd into C datatype
        bdtmpl_cmd[argmap[lookup_cmd]](alp->inq, (void*)dt_buf);
        
        /// Run ALP command, using input template
        txq_len = m2qp_cmd[lookup_cmd](&status, (void*)dt_buf);
        
        /// Response to ALP query command includes three bytes:
        /// byte 1 - status (0 is error)
        /// bytes 2 & 3 - 16 bit integer, length of TXQ
        if (respond) {
            //alp->outrec.flags   &= ~ALP_FLAG_CF;
            //alp->outrec.cmd     |= 0x40;
            //alp->outrec.plength  = 3;
            alp->OUTREC(FLAGS)   &= ~ALP_FLAG_CF;
            alp->OUTREC(PLEN)     = 3;
            alp->OUTREC(CMD)     |= 0x40;
            q_writebyte(alp->outq, status);
            q_writeshort(alp->outq, txq_len);
        }
    }
    
    return True;
}
Example #18
0
int sub_getdecnum(int* status, FILE* stream, ot_queue* msg) {
    int     digits;
    char    next;
    char    buf[16];
    int     sign    = 1;
    int     force_u = 0;
    int     number  = 0;
    int     i       = 0;
    int     size    = 0;
    
    // Buffer until whitespace or ')' delimiter 
    digits = sub_buffernum(status, stream, buf, 15);
    
    // Deal with leading minus sign
    if (buf[i] == '-') {
        sign = -1;
        i++;
    }
    
    // Go through the digits & footer
    // - load in numerical value, one digit at a time
    // - also look for the type footer: ul, us, uc, u, l, s, c, or none
    while (i < digits) {
        if ((buf[i] >= '0') && (buf[i] <= '9')) {
            number *= 10;
            number += (buf[i++] - '0');
        }
        else {
            force_u = (buf[i] == 'u');
            i      += force_u;

            if (buf[i] == 'c')      size = 1;   // c: char (1 byte)
            else if (buf[i] == 's') size = 2;   // s: short (2 bytes)
            else if (buf[i] == 'l') size = 3;   // l: long (4 bytes)
            break;
        }
    }
    
    // Determine size in case where footer is not explicitly provided
    if (size == 0) {
        int j;
        int bound[] = {128, 256, 32768, 65536, 0, 0};
        int max     = number - (sign < 0);
        
        for (j=force_u, size=1;  ; j+=2, size++) {
            if ((bound[j]==0) || (bound[j]>=max)) break;
        }
    }

    number *= sign;

    switch (size & 3) {
        case 0:
        case 1: q_writebyte(msg, (ot_u8)number);
                break;
        
        case 2: q_writeshort(msg, (ot_u16)number);
                break;
        
        case 3: size = 4;
                q_writelong(msg, (ot_u32)number);
                break;
    }
    
    return size;
}
Example #19
0
OT_WEAK void alp_stream_advert_tmpl(ot_queue* out_q, void* data_type) { 
    if _PTR_TEST(data_type) {
        q_writestring(out_q, (ot_u8*)data_type, 4);
        q_writeshort(out_q, ((advert_tmpl*)data_type)->duration);
    }
}
Example #20
0
OT_WEAK void alp_stream_isfcall_tmpl(ot_queue* out_q, void* data_type) { 
    if _PTR_TEST(data_type) {
        alp_breakdown_isfcomp_tmpl(out_q, data_type);
        q_writeshort(out_q, ((isfcall_tmpl*)data_type)->max_return);
    }
}
Example #21
0
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;
}
Example #22
0
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();
}