]> oss.titaniummirror.com Git - tinyos-2.x.git/commitdiff
Add the external flash version of SerialLoader to demonstrate TinyLD
authorliang_mike <liang_mike>
Thu, 5 Feb 2009 04:12:55 +0000 (04:12 +0000)
committerliang_mike <liang_mike>
Thu, 5 Feb 2009 04:12:55 +0000 (04:12 +0000)
apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManager.h [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManagerC.nc [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManagerP.nc [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/Makefile [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/README [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/SerialLoaderFlashAppC.nc [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/serialloader.py [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/tinyos.py [new file with mode: 0755]
apps/tosthreads/tinyld/SerialLoaderFlash/volumes-stm25p.xml [new file with mode: 0755]

diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManager.h b/apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManager.h
new file mode 100755 (executable)
index 0000000..8b2b5e3
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008 Johns Hopkins University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written
+ * agreement is hereby granted, provided that the above copyright
+ * notice, the (updated) modification history and the author appear in
+ * all copies of this source code.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+ * OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#ifndef FLASHVOLUMEMANAGER_H
+#define FLASHVOLUMEMANAGER_H
+
+#define SERIALMSG_ERASE 0
+#define SERIALMSG_WRITE 1
+#define SERIALMSG_READ  2
+#define SERIALMSG_CRC   3
+//#define SERIALMSG_ADDR  4
+#define SERIALMSG_LEDS 5
+#define SERIALMSG_RUN  7
+
+typedef nx_struct SerialReqPacket {
+  nx_uint8_t msg_type;
+  nx_uint8_t pad;
+  nx_uint16_t offset;
+  nx_uint16_t len;
+  nx_uint8_t data[0];
+} SerialReqPacket;
+
+#define SERIALMSG_SUCCESS 0
+#define SERIALMSG_FAIL    1
+
+typedef nx_struct SerialReplyPacket {
+  nx_uint8_t error;
+  nx_uint8_t pad;
+  nx_uint8_t data[0];
+} SerialReplyPacket;
+
+#endif
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManagerC.nc b/apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManagerC.nc
new file mode 100755 (executable)
index 0000000..88b8f00
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2008 Johns Hopkins University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written
+ * agreement is hereby granted, provided that the above copyright
+ * notice, the (updated) modification history and the author appear in
+ * all copies of this source code.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+ * OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#include "AM.h"
+
+generic configuration FlashVolumeManagerC(am_id_t AMId)
+{
+  uses {
+    interface BlockRead;
+    interface BlockWrite;
+    interface DynamicLoader;
+  }
+}
+
+implementation
+{
+  components MainC,
+             SerialActiveMessageC,
+             new SerialAMSenderC(AMId),
+             new SerialAMReceiverC(AMId),
+             new FlashVolumeManagerP(),
+             NoLedsC, LedsC;
+  
+  DynamicLoader = FlashVolumeManagerP;
+  BlockRead = FlashVolumeManagerP;
+  BlockWrite = FlashVolumeManagerP;
+  
+  FlashVolumeManagerP.Boot -> MainC;
+  FlashVolumeManagerP.SerialSplitControl -> SerialActiveMessageC;
+
+  FlashVolumeManagerP.SerialAMSender -> SerialAMSenderC;
+  FlashVolumeManagerP.SerialAMReceiver -> SerialAMReceiverC;
+  FlashVolumeManagerP.Leds -> LedsC;
+}
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManagerP.nc b/apps/tosthreads/tinyld/SerialLoaderFlash/FlashVolumeManagerP.nc
new file mode 100755 (executable)
index 0000000..a998420
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2008 Johns Hopkins University.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose, without fee, and without written
+ * agreement is hereby granted, provided that the above copyright
+ * notice, the (updated) modification history and the author appear in
+ * all copies of this source code.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+ * OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+/**
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#include "FlashVolumeManager.h"
+#include "StorageVolumes.h"
+
+generic module FlashVolumeManagerP()
+{
+  uses {
+    interface Boot;
+    interface SplitControl as SerialSplitControl;
+    interface BlockRead;
+    interface BlockWrite;
+    interface AMSend as SerialAMSender;
+    interface Receive as SerialAMReceiver;
+    interface Leds;
+    interface DynamicLoader;
+  }
+}
+
+implementation
+{
+  message_t serialMsg;
+  storage_addr_t dumpAddr = 0;
+  
+  event void Boot.booted() {
+    while (call SerialSplitControl.start() != SUCCESS);
+  }
+  
+  event void SerialSplitControl.startDone(error_t error)
+  {
+    if (error != SUCCESS) {
+      while (call SerialSplitControl.start() != SUCCESS);
+    }
+  }
+    
+  void sendReply(error_t error, storage_len_t len)
+  {
+    SerialReplyPacket *srpkt = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg, sizeof(SerialReplyPacket));
+    if (error == SUCCESS) {
+      srpkt->error = SERIALMSG_SUCCESS;
+    } else {
+      srpkt->error = SERIALMSG_FAIL;
+    }
+    call SerialAMSender.send(AM_BROADCAST_ADDR, &serialMsg, len);
+  }
+  
+  event void BlockRead.readDone(storage_addr_t addr, void* buf, storage_len_t len, error_t error) {
+    sendReply(error, len + sizeof(SerialReplyPacket));
+  }
+  
+  event void BlockRead.computeCrcDone(storage_addr_t addr, storage_len_t len, uint16_t crc, error_t error)
+  {
+    if (error == SUCCESS) {
+      SerialReplyPacket *srpkt = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg, sizeof(SerialReplyPacket));
+      srpkt->data[1] = crc & 0xFF;
+      srpkt->data[0] = (crc >> 8) & 0xFF;
+    }
+    sendReply(error, 2 + sizeof(SerialReplyPacket));
+  }
+  
+  event void BlockWrite.writeDone(storage_addr_t addr, void* buf, storage_len_t len, error_t error)
+  {
+    if (error != SUCCESS) {
+      call Leds.led1On();
+    }
+    sendReply(error, sizeof(SerialReplyPacket));
+  }
+  
+  event void BlockWrite.eraseDone(error_t error) {
+    sendReply(error, sizeof(SerialReplyPacket));
+  }
+    
+  event message_t* SerialAMReceiver.receive(message_t* msg, void* payload, uint8_t len)
+  {
+    uint16_t i;
+    error_t error = SUCCESS;
+    SerialReqPacket *srpkt = (SerialReqPacket *)payload;
+    SerialReplyPacket *serialMsg_payload = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg, sizeof(SerialReplyPacket));
+    
+    switch (srpkt->msg_type) {
+      case SERIALMSG_ERASE :
+        error = call BlockWrite.erase();
+        if (error != SUCCESS) {
+          sendReply(error, sizeof(SerialReplyPacket));
+        }
+        break;
+      case SERIALMSG_WRITE :
+        call Leds.led2On();
+        error = call BlockWrite.write(srpkt->offset, srpkt->data, srpkt->len);
+        if (error != SUCCESS) {
+          sendReply(error, sizeof(SerialReplyPacket));
+          call Leds.led0On();
+        }
+        break;
+      case SERIALMSG_READ :
+        error = call BlockRead.read(srpkt->offset, serialMsg_payload->data, srpkt->len);
+        if (error != SUCCESS) {
+          sendReply(error, sizeof(SerialReplyPacket));
+        }
+        break;
+      case SERIALMSG_CRC :
+        error = call BlockRead.computeCrc(srpkt->offset, srpkt->len, 0);
+        if (error != SUCCESS) {
+          sendReply(error, sizeof(SerialReplyPacket));
+        }
+        break;
+      case SERIALMSG_LEDS:
+        call Leds.set(7);
+        for (i = 0; i < 2000; i++) {}
+        call Leds.set(0);
+        break;
+      case SERIALMSG_RUN :
+        error = call DynamicLoader.loadFromFlash(VOLUME_MICROEXEIMAGE);
+        if (error != SUCCESS)
+          sendReply(error, sizeof(SerialReplyPacket));
+        break;
+    }
+    
+    return msg;
+  }
+  
+  event void DynamicLoader.loadFromFlashDone(uint8_t volumeId, tosthread_t id, error_t error) {
+    sendReply(error, sizeof(SerialReplyPacket));
+  }
+  
+  event void DynamicLoader.loadFromMemoryDone(void *addr, tosthread_t id, error_t error) {}
+  event void BlockWrite.syncDone(error_t error) {}
+  event void SerialAMSender.sendDone(message_t* msg, error_t error) {}
+  event void SerialSplitControl.stopDone(error_t error) {} 
+}
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/Makefile b/apps/tosthreads/tinyld/SerialLoaderFlash/Makefile
new file mode 100755 (executable)
index 0000000..83d3dbe
--- /dev/null
@@ -0,0 +1,22 @@
+COMPONENT=SerialLoaderFlashAppC
+
+GOALS += threads
+
+THREADS_DIR ?= $(TOSDIR)/lib/tosthreads
+CFLAGS += -I$(THREADS_DIR)/lib/tinyld
+CFLAGS += -I$(THREADS_DIR)/csystem
+CFLAGS += -I$(THREADS_DIR)/sensorboards/tmote_onboard
+CFLAGS += -I$(THREADS_DIR)/sensorboards/universal
+CFLAGS += -I$(THREADS_DIR)/lib/net/ctp
+CFLAGS += -I$(THREADS_DIR)/lib/net
+CFLAGS += -I$(TOSDIR)/lib/net
+CFLAGS += -I$(TOSDIR)/lib/net/ctp
+CFLAGS += -I$(TOSDIR)/lib/net/4bitle
+CFLAGS += -I$(THREADS_DIR)/lib/printf
+
+# Creates VolumeMapC.nc
+VOLUME_ALLOCATOR_FLAGS += -t
+
+CLEAN_EXTRA += *.pyc
+
+include $(MAKERULES)
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/README b/apps/tosthreads/tinyld/SerialLoaderFlash/README
new file mode 100755 (executable)
index 0000000..3a891a0
--- /dev/null
@@ -0,0 +1,25 @@
+README for SerialLoaderFlash
+Author/Contact: Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+
+Description:
+
+SerialLoaderFlash is similar to SerialLoader in that it receives
+loadable programs from the serial port. However, SerialLoaderFlash
+stores them on the external flash. Then, when it receives the command to
+load the code, it makes the call to the dynamic loader.
+
+Here are the steps:
+1.) Load SerialLoader:
+    make telosb install bsl,<device_port>
+    
+2.) Create the loadable code, Blink.tos:
+    tosthreads-gen-dynamic-app ../../capps/Blink/Blink.c
+
+3.) Erase the external flash:
+    ./serialloader.py <device_port> 0
+
+4.) Upload the binary:
+    ./serialloader.py <device_port> 1 Blink.tos
+    
+5.) Run the binary:
+    ./serialloader.py <device_port> 7
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/SerialLoaderFlashAppC.nc b/apps/tosthreads/tinyld/SerialLoaderFlash/SerialLoaderFlashAppC.nc
new file mode 100755 (executable)
index 0000000..eef04af
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2008 Stanford University.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the
+ *   distribution.
+ * - Neither the name of the Stanford University nor the names of
+ *   its contributors may be used to endorse or promote products derived
+ *   from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL STANFORD
+ * UNIVERSITY OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/**
+ * @author Kevin Klues (klueska@cs.stanford.edu)
+ * @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+ */
+
+#include "StorageVolumes.h"
+
+configuration SerialLoaderFlashAppC {}
+
+implementation {  
+  components DynamicLoaderC,
+             new FlashVolumeManagerC(0xAB),
+             new BlockStorageC(VOLUME_MICROEXEIMAGE) as ImageVolume;
+  
+  FlashVolumeManagerC.BlockRead -> ImageVolume;
+  FlashVolumeManagerC.BlockWrite -> ImageVolume;
+  FlashVolumeManagerC.DynamicLoader -> DynamicLoaderC;
+}
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/serialloader.py b/apps/tosthreads/tinyld/SerialLoaderFlash/serialloader.py
new file mode 100755 (executable)
index 0000000..686bf95
--- /dev/null
@@ -0,0 +1,229 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2008 Johns Hopkins University.
+# All rights reserved.
+#
+# Permission to use, copy, modify, and distribute this software and its
+# documentation for any purpose, without fee, and without written
+# agreement is hereby granted, provided that the above copyright
+# notice, the (updated) modification history and the author appear in
+# all copies of this source code.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS `AS IS'
+# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, LOSS OF USE, DATA,
+# OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+# THE POSSIBILITY OF SUCH DAMAGE.
+
+# @author Chieh-Jan Mike Liang <cliang4@cs.jhu.edu>
+
+import sys, os, stat, struct
+import tinyos
+
+SERIALMSG_AMGROUP = 0
+SERIALMSG_AMID    = 0xAB
+
+SERIALMSG_ERASE = 0
+SERIALMSG_WRITE = 1
+SERIALMSG_READ  = 2
+SERIALMSG_CRC   = 3
+SERIALMSG_LEDS   = 5
+SERIALMSG_RUN   = 7
+
+SERIALMSG_SUCCESS = 0
+SERIALMSG_FAIL    = 1
+
+SERIALMSG_DATA_PAYLOAD_SIZE = 20
+DELUGE_VOLUME_SIZE = 262144
+
+HEX_OUTPUT_LINE_SIZE = 16
+
+class SerialReqPacket(tinyos.GenericPacket):
+  def __init__(self, packet = None):
+      tinyos.GenericPacket.__init__(self,
+                             [('msg_type', 'int', 1),
+                              ('pad', 'int', 1),
+                              ('offset', 'int', 2),
+                              ('len', 'int', 2),
+                              ('data', 'blob', None)],
+                             packet)
+
+class SerialReplyPacket(tinyos.GenericPacket):
+  def __init__(self, packet = None):
+      tinyos.GenericPacket.__init__(self,
+                             [('error', 'int', 1),
+                              ('pad', 'int', 1),
+                             ('data', 'blob', None)],
+                             packet)
+
+# Display an integer representation of byte stream to hex representation
+def print_hex(start_addr, byte_stream):
+  byte_stream = ["%02x" % one_byte for one_byte in byte_stream]   # Converts to each byte to hex
+  
+  num_iterations = int( (len(byte_stream) - 1) / HEX_OUTPUT_LINE_SIZE )
+  num_iterations += 1
+  
+  for i in range(num_iterations):
+    line = "%07x" % start_addr + " "   # Prints memory address
+    for j in range(HEX_OUTPUT_LINE_SIZE):
+      if (i * HEX_OUTPUT_LINE_SIZE + j) < len(byte_stream):
+        line += byte_stream[i * HEX_OUTPUT_LINE_SIZE + j] + " "
+    print line
+    
+    start_addr += HEX_OUTPUT_LINE_SIZE
+
+def op_run(s, sreqpkt):
+  success = s.write_packet(SERIALMSG_AMGROUP, SERIALMSG_AMID, sreqpkt.payload())
+  if success == True:
+    packet = s.read_packet()
+    sreplypkt = SerialReplyPacket(packet[1])
+    return (sreplypkt.error == SERIALMSG_SUCCESS)
+
+def op_erase(s, sreqpkt):
+  success = s.write_packet(SERIALMSG_AMGROUP, SERIALMSG_AMID, sreqpkt.payload())
+  if success == True:
+    packet = s.read_packet()
+    sreplypkt = SerialReplyPacket(packet[1])
+    return (sreplypkt.error == SERIALMSG_SUCCESS)
+
+def op_print(s, sreqpkt, offset, length):
+  if (offset + length) <= DELUGE_VOLUME_SIZE:
+    while length > 0:
+      sreqpkt.offset = offset
+      # Calculates the payload size for the reply packet
+      if length >= HEX_OUTPUT_LINE_SIZE:
+        sreqpkt.len = HEX_OUTPUT_LINE_SIZE
+      else:
+        sreqpkt.len = length
+      
+      success = s.write_packet(SERIALMSG_AMGROUP, SERIALMSG_AMID, sreqpkt.payload())
+      if success == True:
+        packet = s.read_packet()
+        sreplypkt = SerialReplyPacket(packet[1])
+        if sreplypkt.error != SERIALMSG_SUCCESS:
+          return False
+  
+      print_hex(offset, sreplypkt.data)
+      length -= sreqpkt.len
+      offset += sreqpkt.len
+  else:
+    print "ERROR: Specified offset and length are too large for the flash volume"
+    return False
+  
+  return True
+
+def op_write(s, sreqpkt, input_file, length):
+  local_crc = 0
+  input_file_size = length
+  
+  sreqpkt.offset = 0
+  while length > 0:
+    # Calculates the payload size for the current packet
+    if length >= SERIALMSG_DATA_PAYLOAD_SIZE:
+      sreqpkt.len = SERIALMSG_DATA_PAYLOAD_SIZE
+    else:
+      sreqpkt.len = length
+    sreqpkt.data = []
+    
+    # Reads in the file we want to transmit
+    for i in range(sreqpkt.len):
+      sreqpkt.data.append(struct.unpack("B", input_file.read(1))[0])
+    
+    # Sends over serial to the mote
+    if s.write_packet(SERIALMSG_AMGROUP, SERIALMSG_AMID, sreqpkt.payload()) == True:
+      # Waiting for confirmation
+      packet = s.read_packet()
+      sreplypkt = SerialReplyPacket(packet[1])
+      if sreplypkt.error != SERIALMSG_SUCCESS:
+        return False
+      local_crc = s.crc16(local_crc, sreqpkt.data)   # Computes running CRC
+    else:
+      print "ERROR: Unable to write to flash"
+      return False
+    
+    length -= sreqpkt.len
+    sreqpkt.offset += sreqpkt.len
+  
+  # Check local and remote CRC
+  sreqpkt.msg_type = SERIALMSG_CRC
+  remote_crc = op_crc(s, sreqpkt, 0, input_file_size)
+  if remote_crc != None:
+    local_crc = [(local_crc >> 8) & 0xFF, local_crc & 0xFF]
+    print "Local CRC:  " + ("%02x" % local_crc[0]) + " " + ("%02x" % local_crc[1])
+    print "Remote CRC: " + ("%02x" % remote_crc[0]) + " " + ("%02x" % remote_crc[1])
+    if remote_crc != local_crc:
+      print "ERROR: Remote CRC doesn't match local CRC"
+      return False
+  else:
+    print "ERROR: Unable to verify CRC"
+    return False
+    
+  return True
+
+def op_crc(s, sreqpkt, offset, length):
+  sreqpkt.offset = offset
+  sreqpkt.len = length
+  success = s.write_packet(SERIALMSG_AMGROUP, SERIALMSG_AMID, sreqpkt.payload())
+  if success == True:
+    packet = s.read_packet()
+    sreplypkt = SerialReplyPacket(packet[1])
+    if sreplypkt.error == SERIALMSG_SUCCESS:
+      return sreplypkt.data
+    else:
+      return None
+
+def op_leds(s, sreqpkt):
+  success = s.write_packet(SERIALMSG_AMGROUP, SERIALMSG_AMID, sreqpkt.payload())
+
+# ======== MAIN ======== #
+if len(sys.argv) >= 3:
+  sys.argv[2] = int(sys.argv[2])
+  
+  s = tinyos.Serial(sys.argv[1], 57600)
+  s.set_debug(False)   # Disables debug msg
+  sreqpkt = SerialReqPacket((sys.argv[2], 0, 0, 0, []))   # msg_type, pad, offset, length, data
+  
+  if sys.argv[2] == SERIALMSG_RUN:
+    if op_run(s, sreqpkt) == True:
+      print "Loaded image should be running now!"
+    else:
+      print "ERROR: Unable to run loaded image"
+  elif sys.argv[2] == SERIALMSG_ERASE:
+    if op_erase(s, sreqpkt) == True:
+      print "Flash volume has been erased"
+    else:
+      print "ERROR: Unable to erase flash volume"
+    
+  elif sys.argv[2] == SERIALMSG_WRITE:
+    input_file = file(sys.argv[3], 'rb')
+    fileStats = os.stat(sys.argv[3])
+    
+    if fileStats[stat.ST_SIZE] <= DELUGE_VOLUME_SIZE:
+      #sreqpkt = SerialReqPacket((SERIALMSG_LEDS, 0, 0, 0, []))
+      #op_leds(s, sreqpkt)
+      sreqpkt = SerialReqPacket((sys.argv[2], 0, 0, 0, []))
+      if op_write(s, sreqpkt, input_file, fileStats[stat.ST_SIZE]) == True:
+        print "File has been successfully transmitted (" + str(fileStats[stat.ST_SIZE]) + " bytes)"
+      else:
+        print "ERROR: Unable to transmit file"
+      sreqpkt = SerialReqPacket((SERIALMSG_LEDS, 0, 0, 0, []))
+      op_leds(s, sreqpkt)
+    else:
+      print "ERROR: File is larger than flash volume (" + DELUGE_VOLUME_SIZE + ")"
+  
+  elif sys.argv[2] == SERIALMSG_READ:
+    data = op_print(s, sreqpkt, int(sys.argv[3]), int(sys.argv[4]))
+    if data != True:
+      print "ERROR: Unable to read the specified range"
+    
+  elif sys.argv[2] == SERIALMSG_CRC:
+    remote_crc = op_crc(s, sreqpkt, int(sys.argv[3]), int(sys.argv[4]))
+    if remote_crc != None:
+      print_hex(0, remote_crc)
+    else:
+      print "ERROR: Unable to compute remote CRC"
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/tinyos.py b/apps/tosthreads/tinyld/SerialLoaderFlash/tinyos.py
new file mode 100755 (executable)
index 0000000..e922f58
--- /dev/null
@@ -0,0 +1,223 @@
+import struct, time, serial
+
+class Serial:
+  HDLC_FLAG_BYTE = 0x7e
+  HDLC_CTLESC_BYTE = 0x7d
+  
+  TOS_SERIAL_ACTIVE_MESSAGE_ID = 0
+  TOS_SERIAL_CC1000_ID = 1
+  TOS_SERIAL_802_15_4_ID = 2
+  TOS_SERIAL_UNKNOWN_ID = 255
+  
+  SERIAL_PROTO_ACK = 67
+  SERIAL_PROTO_PACKET_ACK = 68
+  SERIAL_PROTO_PACKET_NOACK = 69
+  SERIAL_PROTO_PACKET_UNKNOWN = 255
+  
+  __s = None;       # An instance of serial.Serial object
+  __debug = True   # Debug mode
+  
+  def __init__(self, port, baudrate):
+     self.__s = serial.Serial(port, baudrate, rtscts=0)
+  
+  def __format_packet(self, packet):
+      return " ".join(["%02x" % p for p in packet]) + " | " + \
+             " ".join(["%d" % p for p in packet])
+  
+  def crc16(self, base_crc, frame_data):
+      crc = base_crc
+      for b in frame_data:
+          crc = crc ^ (b << 8)
+          for i in range(0, 8):
+              if crc & 0x8000 == 0x8000:
+                  crc = (crc << 1) ^ 0x1021
+              else:
+                  crc = crc << 1
+              crc = crc & 0xffff
+      return crc
+  
+  def __encode(self, val, dim):
+      output = []
+      for i in range(dim):
+          output.append(val & 0xFF)
+          val = val >> 8
+      return output
+  
+  def __decode(self, v):
+      r = long(0)
+      for i in v[::-1]:
+          r = (r << 8) + i
+      return r
+  
+  def __get_byte(self):
+      r = struct.unpack("B", self.__s.read())[0]
+      return r
+  
+  def __put_bytes(self, data):
+      for b in data:
+          self.__s.write(struct.pack('B', b))
+  
+  def __unescape(self, packet):
+      r = []
+      esc = False
+      for b in packet:
+          if esc:
+              r.append(b ^ 0x20)
+              esc = False
+          elif b == self.HDLC_CTLESC_BYTE:
+              esc = True
+          else:
+              r.append(b)
+      return r
+  
+  def __escape(self, packet):
+      r = []
+      for b in packet:
+          if b == self.HDLC_FLAG_BYTE or b == self.HDLC_CTLESC_BYTE:
+              r.append(self.HDLC_CTLESC_BYTE)
+              r.append(b ^ 0x20)
+          else:
+              r.append(b)
+      return r
+  
+  def read_packet(self):
+      d = self.__get_byte()
+      ts = time.time()
+      while d != self.HDLC_FLAG_BYTE:
+          d = self.__get_byte()
+          ts = time.time()
+      packet = [d]
+      d = self.__get_byte()
+      if d == self.HDLC_FLAG_BYTE:
+          d = self.__get_byte()
+          ts = time.time()
+      else:
+          packet.append(d)
+      while d != self.HDLC_FLAG_BYTE:
+          d = self.__get_byte()
+          packet.append(d)
+      un_packet = self.__unescape(packet)
+      crc = self.crc16(0, un_packet[1:-3])
+      packet_crc = self.__decode(un_packet[-3:-1])
+      if crc != packet_crc:
+          print "Warning: wrong CRC!"
+      if self.__debug == True:
+          print "Recv:", self.__format_packet(un_packet)
+      return (ts, un_packet)
+      
+  def write_packet(self, am_group, am_id, data):
+      # The first byte after SERIAL_PROTO_PACKET_ACK is a sequence
+      # number that will be send back by the mote to ack the receive of
+      # the data.
+      packet = [self.SERIAL_PROTO_PACKET_ACK, 0, self.TOS_SERIAL_ACTIVE_MESSAGE_ID,
+                0xff, 0xff,
+                0, 0,
+                len(data), am_group, am_id] + data;
+      crc = self.crc16(0, packet)
+      packet.append(crc & 0xff)
+      packet.append((crc >> 8) & 0xff)
+      packet = [self.HDLC_FLAG_BYTE] + self.__escape(packet) + [self.HDLC_FLAG_BYTE]
+      if self.__debug == True:
+          print "Send:", self.__format_packet(packet)
+      self.__put_bytes(packet)
+      
+      # Waiting for ACK
+      packet = self.read_packet()
+      if len(packet) > 1 and len(packet[1]) > 1:
+        return ((packet[1])[1] == self.SERIAL_PROTO_ACK)
+      return False
+  
+  def set_debug(self, debug):
+      self.__debug = debug
+
+class GenericPacket:
+    """ GenericPacket """
+
+    def __decode(self, v):
+        r = long(0)
+        for i in v:
+            r = (r << 8) + i
+        return r
+    
+    def __encode(self, val, dim):
+        output = []
+        for i in range(dim):
+            output.append(int(val & 0xFF))
+            val = val >> 8
+        output.reverse()
+        return output
+
+    def __init__(self, desc, packet = None):
+        self.__dict__['_schema'] = [(t, s) for (n, t, s) in desc]
+        self.__dict__['_names'] = [n for (n, t, s) in desc]
+        self.__dict__['_values'] = []
+        offset = 10
+        if type(packet) == type([]):
+            for (t, s) in self._schema:
+                if t == 'int':
+                    self._values.append(self.__decode(packet[offset:offset + s]))
+                    offset += s
+                elif t == 'blob':
+                    if s:
+                        self._values.append(packet[offset:offset + s])
+                        offset += s
+                    else:
+                        self._values.append(packet[offset:-3])
+        elif type(packet) == type(()):
+            for i in packet:
+                self._values.append(i)
+        else:
+            for v in self._schema:
+                self._values.append(None)
+
+    def __repr__(self):
+        return self._values.__repr__()
+
+    def __str__(self):
+        return self._values.__str__()
+
+    # Implement the map behavior
+    def __getitem__(self, key):
+        return self.__getattr__(key)
+
+    def __setitem__(self, key, value):
+        self.__setattr__(key, value)
+
+    def __len__(self):
+        return len(self._values)
+
+    def keys(self):
+        return self._names
+
+    def values(self):
+        return self._names
+
+    # Implement the struct behavior
+    def __getattr__(self, name):
+        if type(name) == type(0):
+            return self._names[name]
+        else:
+            return self._values[self._names.index(name)]
+
+    def __setattr__(self, name, value):
+        if type(name) == type(0):
+            self._values[name] = value
+        else:
+            self._values[self._names.index(name)] = value
+
+    # Custom
+    def names(self):
+        return self._names
+
+    def sizes(self):
+        return self._schema
+
+    def payload(self):
+        r = []
+        for i in range(len(self._schema)):
+            (t, s) = self._schema[i]
+            if t == 'int':
+                r += self.__encode(self._values[i], s)
+            else:
+                r += self._values[i]
+        return r
diff --git a/apps/tosthreads/tinyld/SerialLoaderFlash/volumes-stm25p.xml b/apps/tosthreads/tinyld/SerialLoaderFlash/volumes-stm25p.xml
new file mode 100755 (executable)
index 0000000..801def9
--- /dev/null
@@ -0,0 +1,3 @@
+<volume_table>
+  <volume name="MICROEXEIMAGE" size="262144" type="block"/>
+</volume_table>