Tuesday, June 3, 2014

Data Upload from Arduino - Arduino Web Logger

The Arduino WebSocket we used limits the size of packet we can send.  We are unable to receive entire 512 bytes Block, even if we divided it into 3, from the WebSocket.

Thus we are going to change the protocol so we are sending each Data item one-by-one.

Get Last Data Block Number

If we send "GET0", we receive N = <Data Block Number>.


<Data Block Number

is unsigned 32 bit integer ranging from "N = 1" to "N = 4294967295"
Of course it doesn't get that big.
In the source code from Data Log Code posting, SD_BASE_BLOCK (1024) is equal to 0.


Get Data Block

If we send "GETn", we receive
  • N = <Data Block Number>
  • T = <time stamp>
  • D = <data>
<time stamp> uses sec part from POSIX time_t.
Because we don't use the millisecond part, we need to *1000.
"T = 4294967295". Of course it will be hard to see this number in your lifetime.

<data> has +dd.ddd format.
  • "D=+12.345"
  • "D=": when there is no data
  • "D=-99.999": termination. Data Block has finished.

Original Protocol

Digital Out

  • Turning On: "DOn=ON"
  • Turning Off: "DOn=OFF"
n is equal to Channel number which is between 0 and 7, and there is no reply.

Digital In

When you send "DI" it replies with "bbbbbbbb".  b is equal to each input channel and it is either '0' or '1'.

Analog In

When you send "AIn" it replies with "+dd.ddd". n is equal to channel number which is between 0 and 7, and "+dd.ddd" ranges from -10.000 to +10.000.

Below I am only excerpting codes related to uploading.  Refer to the link at the bottom for entire code.
// -------------------------------- Data Uploading Function
void upload_lastBlockNo(void);
void upload_DataBlock(uint32_t reqBlock);
byte *setTerminator(byte *pD);

/*
 ----------------------------------------------------------
 D A T A  U P L O A D I N G  Function
 ----------------------------------------------------------
*/

/*
 0         1
 012345678901 last data block number 12 bytes send
 N=4294967295

 0         1
 012345678901 time stamp 12 bytes send
 T=4294967295

 012345678 Data 9 bytes send
 D=+99.999
 D=        empty
 D=-99.999 terminator
*/
void xsfBlockNo(uint32_t block) {
 ltoa(block - SD_BASE_BLOCK, printLn + 2, 10);
 printLn[0] = 'N';
 printLn[1] = '=';
 WSsend(printLn, strlen(printLn));
}

void upload_loastBlockNo(void) {
 xsfBlockNo(currBlock - 1);
}

void upload_DataBlock(uint32_t reqBlock) {
 byte *pS;
 int cnt;
 float data, *pF;

 // Store the currently logging Block into SD.
 // We might lose packets that ADAM-4017 is receiving.
 sdCard.writeBlock(currBlock, sdBuffer);

 printLn[1] = '=';

 if(sdCard.readBlock(reqBlock, sdBuffer)) {
  pS = sdBuffer;

  if(*((uint32_t*)pS) == USED_MARK) {
   pS += 4;

   // block number
   xsfBlockNo(reqBlock);

   // time stamp (milliseconds)
   ltoa(*((uint32_t*)pS), printLn + 2, 10);
   printLn[0] = 'T';
   WSsend(printLn, strlen(printLn));
   pS += 4;

   // data
   printLn[0] = 'D';
   pF = (float*)pS;
   cnt = 120;

   while(cnt--) {
    data = *pF++ / 10.0;

    if(data != -99.999)
     dtostrf(data, 7, 3, printLn + 2);
    else
     printLn[2] = 0x00;

    WSsend(printLn, strlen(printLn));
   }
  }

  printLn[0] = 'D';
  setTerminator((byte*)(printLn + 2));
  WSsend(printLn, strlen(printLn));
 }

 // Reload the block that we have stored.
 sdCard.readBlock(currBlock, sdBuffer);
}

//---------------------------------------------------------
byte *setTerminator(byte *pD) {
 *pD++ = '-';
 *pD++ = '9';
 *pD++ = '9';
 *pD++ = '.';
 *pD++ = '9';
 *pD++ = '9';
 *pD++ = '9';
 *pD++ = 0x00;
 return pD;
}

/*
  ---------------------------------------------------------
  W E B S O C K E T   h a n d l e r
  ---------------------------------------------------------
*/

void onData(WebSocket &socket, char* rxLn, byte rxSz) {
 uint32_t block;

 if((rxLn[0] == 'G') && (rxLn[1] == 'E') && (rxLn[2] == 'T')) {
  *(rxLn + rxSz) = 0x00;
  block = atol(rxLn + 3);
  
  if(block)
   upload_DataBlock(block + SD_BASE_BLOCK);
  else
   upload_lastBlockNo();
 }
}

HTML/JS code for Upload Testing



<!DOCTYPE html>
<html>
<head>
    <title>WebLogger 5.0</title>

    <script type="text/javascript" src="jquery-2.0.3.min.js"></script>
    <script>
        var ws;
        var rcvCnt;

        $(document).ready(function() {
            WebSocketConnect();
        });

        function WebSocketConnect() {
            var ar = new Array();
            var arSz, i;

            try {
                ws = new WebSocket('ws://192.168.219.16:80/');
                ws.onopen = function() {
                    status('Connected...');
                }

                ws.onclose = function() { status('Closed...'); }
                ws.onerror = function(evt) { status('Error ' + evt.data); }
                ws.onmessage = function(evt) {
                    ar = evt.data.split('=');

                    // receive Last Data Block Number  
                    if (ar[0] == 'N') {
                        $("#lastBlockNo").empty();
                        $("#lastBlockNo").append('Last Block Number:' + ar[1]);
                    }

                    // receive Time Stamp
                    if (ar[0] == 'T') {
                        $("#timestamp").empty();
                        $("#timestamp").append('TimeStamp(milliseconds):' + ar[1]);
                    }

                    // receive Data Block
                    if (ar[0] == 'D') {
                        $("#RcvLn").append('<p>' + ar[1] + '<p>');

                        if (ar[1] == '-99.999') {
                            $("#recordCnt").empty();
                            $("#recordCnt").append('Record Count:' + rcvCnt);
                        }

                        rcvCnt++;
                    }
                }
            } catch (exception) { status('Exception' + exception); }
        }

        function upload_lastBlockNo() {
            ws.send("GET0");
        }

        function upload_DataBlock() {
            var recNo = document.getElementById("getRecordNo").value;
            ws.send("GET" + recNo);
            rcvCnt = 0;
            $("#timestamp").empty();
            $("#recordCnt").empty();
            $("#RcvLn").empty();
        }

        function status(str) {
            $("#status").empty();
            $("#status").append(str);
        }

    </script>

</head>
<body>
    <p id="status"></p>
    <button type="button" onclick="upload_lastBlockNo()">Get Last Data Block Number</button>
    
    <br />
    
    <input type="text" id="getRecordNo" value="1">
    <button type="button" onclick="upload_DataBlock()">Get Data Block</button>
    
    <p id="lastBlockNo"></p>
    <p id="timestamp"></p>
    <p id="recordCnt"></p>
    <p id="RcvLn"></p>
</body>
</html>

Full codes can be found in following links