[Tinyos-2-commits] CVS: tinyos-2.x/apps/tosthreads/tinyld/SerialLoader Blink.tos, NONE, 1.1 Makefile, NONE, 1.1 README, NONE, 1.1 SerialLoader.h, NONE, 1.1 SerialLoaderAppC.nc, NONE, 1.1 SerialLoaderP.nc, NONE, 1.1 serialloader.py, NONE, 1.1 tinyos.py, NONE, 1.1

Chieh-Jan Mike Liang liang_mike at users.sourceforge.net
Tue Feb 3 23:41:37 PST 2009


Update of /cvsroot/tinyos/tinyos-2.x/apps/tosthreads/tinyld/SerialLoader
In directory ddv4jf1.ch3.sourceforge.com:/tmp/cvs-serv8269/apps/tosthreads/tinyld/SerialLoader

Added Files:
	Blink.tos Makefile README SerialLoader.h SerialLoaderAppC.nc 
	SerialLoaderP.nc serialloader.py tinyos.py 
Log Message:
Initial commit of TinyLD (TOSThreads' dynamic loader)


--- NEW FILE: Blink.tos ---


--- NEW FILE: Makefile ---
COMPONENT=SerialLoaderAppC

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

ifdef TENET
    CFLAGS += -DTOSTHREAD_TENET=1
endif
CFLAGS += -DDISABLE_LOADER_FLASH=1
CFLAGS += -DDISABLE_LOADER_USERBUTTON=1

CLEAN_EXTRA += *.pyc

include $(MAKERULES)

--- NEW FILE: README ---
README for SerialLoader
Author/Contact: Chieh-Jan Mike Liang <cliang4 at cs.jhu.edu>

Description:

SerialLoader receives loadable programs from the serial port and stores
it in a byte array. 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:
    tosthread-gen-dynamic-app ../../capps/Blink/Blink.c

3.) Clear the byte array in the mote RAM buffer:
    ./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

--- NEW FILE: SerialLoader.h ---
/*
 * 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 at cs.jhu.edu>
 */

#ifndef SERIALLOADER_H
#define SERIALLOADER_H

#define MAX_BIN_SIZE 2000

#define SERIALMSG_ERASE 0
#define SERIALMSG_WRITE 1
#define SERIALMSG_READ  2
#define SERIALMSG_CRC   3
#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

--- NEW FILE: SerialLoaderAppC.nc ---
/*
 * 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 at cs.jhu.edu>
 * @author Jeongyeup Paek <jpaek at enl.usc.edu>
 */

#include "AM.h"
#include "SerialLoader.h"

configuration SerialLoaderAppC {}
implementation
{
  components MainC,
             SerialActiveMessageC,
             new SerialAMSenderC(0xAB),
             new SerialAMReceiverC(0xAB),
             SerialLoaderP,
             BigCrcC,
             LedsC;
  
  SerialLoaderP.Boot -> MainC;
  SerialLoaderP.SerialSplitControl -> SerialActiveMessageC;
  SerialLoaderP.SerialAMSender -> SerialAMSenderC;
  SerialLoaderP.SerialAMReceiver -> SerialAMReceiverC;
  SerialLoaderP.Leds -> LedsC;
  SerialLoaderP.BigCrc -> BigCrcC;

  components DynamicLoaderC;
  SerialLoaderP.DynamicLoader -> DynamicLoaderC;
}


--- NEW FILE: SerialLoaderP.nc ---
/*
 * 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 at cs.jhu.edu>
 * @author Jeongyeup Paek <jpaek at enl.usc.edu>
 **/

#include "SerialLoader.h"

module SerialLoaderP
{
  uses {
    interface Boot;
    interface SplitControl as SerialSplitControl;
    interface AMSend as SerialAMSender;
    interface Receive as SerialAMReceiver;
    interface Leds;
    interface DynamicLoader;
    interface BigCrc;
  }
}
implementation
{
  message_t serialMsg;
  uint32_t dumpAddr = 0;
  
  uint8_t image[MAX_BIN_SIZE];

  event void Boot.booted()
  {
    call SerialSplitControl.start();
  }
  
  event void SerialSplitControl.startDone(error_t error)
  {
    if (error != SUCCESS) {
      call SerialSplitControl.start();
    }
  }
  
  event void SerialSplitControl.stopDone(error_t error) {}
  
  void sendReply(error_t error, uint8_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 SerialAMSender.sendDone(message_t* msg, error_t error) {}
  
  error_t write_image(uint16_t offset, void *data, uint16_t len) {
    if ((offset + len > MAX_BIN_SIZE) || (data == NULL))
      return FAIL;
    memcpy(&image[offset], data, len);
    return SUCCESS;
  }

  error_t read_image(uint16_t offset, void *readbuf, uint16_t len) {
    if ((offset + len > MAX_BIN_SIZE) || (readbuf == NULL))
      return FAIL;
    memcpy(readbuf, &image[offset], len);
    return SUCCESS;
  }

  event void DynamicLoader.loadFromFlashDone(uint8_t volumeId, tosthread_t id, error_t error) {}
  event void DynamicLoader.loadFromMemoryDone(void *addr, tosthread_t id, error_t error) {
    sendReply(error, sizeof(SerialReplyPacket));
  }

  event void BigCrc.computeCrcDone(void* buf, uint16_t len, uint16_t crc, error_t error)
  {
    SerialReplyPacket *srpkt = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg, sizeof(SerialReplyPacket));
        
    srpkt->data[1] = crc & 0xFF;
    srpkt->data[0] = (crc >> 8) & 0xFF;
    sendReply(SUCCESS, 2 + sizeof(SerialReplyPacket));
  }

  void sendCrcReply(uint16_t offset, uint16_t len)
  {
    call BigCrc.computeCrc(&(image[offset]), len);
  }


  event message_t* SerialAMReceiver.receive(message_t* msg, void* payload, uint8_t len)
  {
    uint16_t i;
    error_t error = FAIL;
    SerialReqPacket *srpkt = (SerialReqPacket *)payload;
    SerialReplyPacket *serialMsg_payload = (SerialReplyPacket *)call SerialAMSender.getPayload(&serialMsg, sizeof(SerialReplyPacket));
    
    switch (srpkt->msg_type) {
      case SERIALMSG_ERASE :
        for (i = 0; i < MAX_BIN_SIZE; i++) { image[i] = 0; }
        call Leds.set(7);
        for (i = 0; i < 2000; i++) {}
        call Leds.set(0);
        sendReply(SUCCESS, sizeof(SerialReplyPacket));
        break;
      case SERIALMSG_RUN :
        error = call DynamicLoader.loadFromMemory(image);
        if (error != SUCCESS)
          sendReply(error, sizeof(SerialReplyPacket));
        break;
      case SERIALMSG_WRITE :
        error = write_image(srpkt->offset, srpkt->data, srpkt->len);
        if (error != SUCCESS)
          call Leds.led0On();
        sendReply(error, sizeof(SerialReplyPacket));
        break;
      case SERIALMSG_READ :
        error = read_image(srpkt->offset, serialMsg_payload->data, srpkt->len);
        if (error != SUCCESS)
          sendReply(error, sizeof(SerialReplyPacket));
        else
          sendReply(error, len + sizeof(SerialReplyPacket));
        break;
      case SERIALMSG_LEDS:
        call Leds.set(7);
        for (i = 0; i < 2000; i++) {}
        call Leds.set(0);
        break;
      case SERIALMSG_CRC :
        sendCrcReply(srpkt->offset, srpkt->len);
        break;
    }
    
    return msg;
  }
}


--- NEW FILE: serialloader.py ---
#!/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 at cs.jhu.edu>

import sys, os, stat, struct
import tinyos

SERIAL_BAUDRATE = 57600
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
MAX_BIN_SIZE = 2000

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:
        print "ERROR: !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], SERIAL_BAUDRATE)
  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] <= MAX_BIN_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 max buffer size (" + str(MAX_BIN_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"

--- NEW FILE: tinyos.py ---
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



More information about the Tinyos-2-commits mailing list