X-Git-Url: https://oss.titaniummirror.com/gitweb/?p=tinyos-2.x.git;a=blobdiff_plain;f=support%2Fsdk%2Fpython%2Ftos.py;h=dee4de43af77364e5d3abbcfeb4d61ce6222d280;hp=7aaf760c99629cb3b44fc6b76e15a02541587c93;hb=e9bfab607e051bae6afb47b44892ce37541d1b44;hpb=adf1de6c009d13b7b52e68535c63b28f59c97400 diff --git a/support/sdk/python/tos.py b/support/sdk/python/tos.py index 7aaf760c..dee4de43 100644 --- a/support/sdk/python/tos.py +++ b/support/sdk/python/tos.py @@ -21,17 +21,22 @@ # @author Razvan Musaloiu-E. # @author David Purdy -"""A library that implements the T2 serial communication. +""" +A library that implements the T2 serial communication. This library has two parts: one that deals with sending and receiving packets using the serial format from T2 (TEP113) and a second one that tries to simplifies the work with arbitrary packets. - """ -import sys, struct, time, serial, socket, operator, thread -from Queue import Queue -from threading import Lock, Condition +import sys, struct, time, socket, operator, os +import traceback + +try: + import serial +except ImportError, e: + print "Please install PySerial first." + sys.exit(1) __version__ = "$Id$" @@ -40,124 +45,135 @@ __all__ = ['Serial', 'AM', 'AckFrame', 'DataFrame', 'NoAckDataFrame', 'ActiveMessage'] -ACK_WAIT = 0.2 # Maximum amount of time to wait for an ack -ACK_WARN = 0.2 # Warn if acks take longer than this to arrive - -def list2hex(v): - return " ".join(["%02x" % p for p in v]) - - -class Error(Exception): - """Base error class for this module""" - pass - - -class TimeoutError(Error): - """Thrown when a serial operation times out""" - pass - +HDLC_FLAG_BYTE = 0x7e +HDLC_CTLESC_BYTE = 0x7d -class ReadError(Error): - """Base class for read error exceptions""" - pass - - -class WriteError(Error): - """Base class for write error exceptions""" - pass - - -class ReadTimeoutError(TimeoutError, ReadError): - """Thrown when a serial read operation times out""" - pass +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 -class ReadCRCError(ReadError): - """Thrown when a read packet fails a CRC check""" - pass - - -class BadAckSeqnoError(ReadError): - """Thrown if an ack packet has an unexpected sequenc number""" - pass - +def list2hex(v): + return " ".join(["%02x" % p for p in v]) -class WriteTimeoutError(TimeoutError, WriteError): - """Thrown when a serial write operation times out""" +class Timeout(Exception): pass +def getSource(comm): + source = comm.split('@') + params = source[1].split(':') + debug = '--debug' in sys.argv + if source[0] == 'serial': + try: + return Serial(params[0], int(params[1]), flush=True, debug=debug) + except: + print "ERROR: Unable to initialize a serial connection to", comm + raise Exception + elif source[0] == 'network': + try: + return SerialMIB600(params[0], int(params[1]), debug=debug) + except: + print "ERROR: Unable to initialize a network connection to", comm + print "ERROR:", traceback.format_exc() + raise Exception + raise Exception -class SimpleSerial: - """ - A SimpleSerial object offers a way to send and data using a HDLC-like - formating. - - Use SimpleSerial objects for basic low-level serial communications. Use - Serial objects for higher level logic (retry sends, log printfs, etc). - """ - - 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 - - def __init__(self, port, baudrate, flush=False, debug=False, qsize=10, - timeout=None): - self._debug = debug - self._in_queue = [] - self._qsize = qsize - self._ack = None - self._write_counter = 0 - self._write_counter_failures = 0 - self._read_counter = 0 +class Serial: + def __init__(self, port, baudrate, flush=False, debug=False, readTimeout=None, ackTimeout=0.02): + self.debug = debug + self.readTimeout = readTimeout + self.ackTimeout = ackTimeout self._ts = None - self.timeout = timeout # Public attribute - self._received_packet_filters = [] # filter functions for received packets - # Remember sent (and unacknowledged) seqno numbers for 15 seconds: - self._unacked_seqnos = SeqTracker(15.0) + if port.startswith('COM') or port.startswith('com'): + port = int(port[3:]) - 1 + elif port.isdigit(): + port = int(port) - 1 - self._s = serial.Serial(port, baudrate, rtscts=0, timeout=0.5) + self._s = serial.Serial(port, int(baudrate), rtscts=0, timeout=0.5) self._s.flushInput() if flush: print >>sys.stdout, "Flushing the serial port", endtime = time.time() + 1 while time.time() < endtime: - try: - self._read() - except ReadError: - pass + self._s.read() sys.stdout.write(".") - if not self._debug: + if not self.debug: sys.stdout.write("\n") self._s.close() - self._s = serial.Serial(port, baudrate, rtscts=0, timeout=timeout) + self._s = serial.Serial(port, baudrate, rtscts=0, timeout=readTimeout) - # Add a filter for received 'write ack' packets - self.add_received_packet_filter(self._write_ack_filter) + def getByte(self): + c = self._s.read() + if c == '': + raise Timeout + #print 'Serial:getByte: 0x%02x' % ord(c) + return ord(c) - # Returns the next incoming serial packet - def _read(self, timeout=None): - """Wait for a packet and return it as a RawPacket. + def putBytes(self, data): + #print "DEBUG: putBytes:", data + for b in data: + self._s.write(struct.pack('B', b)) + time.sleep(0.000001) - Throws: - - ReadCRCError if a CRC check fails - - ReadTimeoutError if the timeout expires. + def getTimeout(self): + return self._s.timeout - """ + def setTimeout(self, timeout): + self._s.timeout = timeout + +class SerialMIB600: + def __init__(self, host, port=10002, debug=False, readTimeout=None, ackTimeout=0.5): + self.debug = debug + self.readTimeout = readTimeout + self.ackTimeout = ackTimeout + self._ts = None + self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self._s.connect((host, port)) + print "Connected" + + def getByte(self): + try: + c = self._s.recv(1) + except socket.timeout: + c = '' + if c == '': + raise Timeout + #print 'Serial:getByte: 0x%02x' % ord(c) + return ord(c) + + def putBytes(self, data): + #print "DEBUG: putBytes:", data + for b in data: + self._s.send(struct.pack('B', b)) + + def getTimeout(self): + return self._s.gettimeout() + + def setTimeout(self, timeout): + self._s.settimeout(timeout) + +class HDLC: + """ + An HDLC object offers a way to send and receive data on a byte + source using a HDLC-like formating. + """ + def __init__(self, source): + self._s = source + + # Returns the next incoming serial packet + def read(self, timeout=None): + """Wait for a packet and return it as a RawPacket.""" # Developer notes: # - # Packet data read from Serial is in this format: - # [HDLC_FLAG_BYTE][Escaped data][HDLC_FLAG_BYTE] + # Packet data read is in this format: + # [HDLC_FLAG_BYTE][Escaped data][HDLC_FLAG_BYTE] # # [Escaped data] is encoded so that [HDLC_FLAG_BYTE] byte # values cannot occur within it. When [Escaped data] has been @@ -167,57 +183,72 @@ class SimpleSerial: # # It's also possible that the serial device was half-way # through transmitting a packet when this function was called - # (app was just started). So we also neeed to handle this case: + # (app was just started). So we also neeed to handle this + # case: # - # [Incomplete escaped data][HDLC_FLAG_BYTE][HDLC_FLAG_BYTE][Escaped data][HDLC_FLAG_BYTE] + # [Incomplete escaped data][HDLC_FLAG_BYTE][HDLC_FLAG_BYTE][Escaped data][HDLC_FLAG_BYTE] # # In this case we skip over the first (incomplete) packet. # - if self._s.timeout != timeout and timeout != None: - if self._debug: - print "Set the timeout to %s, previous one was %s" % (timeout, self._s.timeout) - self._s.timeout = timeout + if self._s.getTimeout() != timeout and timeout != None: + self.log("Set the timeout to %s, previous one was %s" % (timeout, self._s.getTimeout())) + self._s.setTimeout(timeout) + + # +--- FLAG -----+ + # | | ___________ + # v | / | + # >(1)-- !FLAG -->(2)<-- !FLAG --+ + # | + # FLAG + # | ___________ + # v / | + # (3)<-- FLAG ---+ + # | + # !FLAG + # | ___________ + # v / | + # (4)<-- !FLAG --+ + # | + # FLAG + # | + # v + # (5) try: # Read bytes until we get to a HDLC_FLAG_BYTE value # (either the end of a packet, or the start of a new one) - d = self._get_byte(timeout) + d = self._s.getByte() ts = time.time() - if self._debug and d != self.HDLC_FLAG_BYTE: - print "Skipping incomplete packet" - while d != self.HDLC_FLAG_BYTE: - d = self._get_byte(timeout) - ts = time.time() + if d != HDLC_FLAG_BYTE: + self.log("Skipping byte %d" % d) + while d != HDLC_FLAG_BYTE: + d = self._s.getByte() + self.log("Skipping byte %d" % d) + ts = time.time() # Store HDLC_FLAG_BYTE at the start of the retrieved packet # data: packet = [d] # Is the next byte also HDLC_FLAG_BYTE? - d = self._get_byte(timeout) - if d == self.HDLC_FLAG_BYTE: - # Yes. This means that the previous byte was for - # the end of the previous packet, and this byte is for - # the start of the next packet. - - # Get the 2nd byte of the new packet: - d = self._get_byte(timeout) + d = self._s.getByte() + while d == HDLC_FLAG_BYTE: + d = self._s.getByte() ts = time.time() # We are now on the 2nd byte of the packet. Add it to # our retrieved packet data: packet.append(d) - # Read bytes from serial until we read another - # HDLC_FLAG_BYTE value (end of the current packet): - while d != self.HDLC_FLAG_BYTE: - d = self._get_byte(timeout) + # Read bytes from serial until we read another HDLC_FLAG_BYTE + # value (end of the current packet): + while d != HDLC_FLAG_BYTE: + d = self._s.getByte() packet.append(d) # Done reading a whole packet from serial - if self._debug: - print "SimpleSerial:_read: unescaped", packet + self.log("SimpleSerial:_read: unescaped %s" % packet) # Decode the packet, and check CRC: packet = self._unescape(packet) @@ -227,137 +258,32 @@ class SimpleSerial: if crc != packet_crc: print "Warning: wrong CRC! %x != %x %s" % (crc, packet_crc, ["%2x" % i for i in packet]) - raise ReadCRCError - if self._debug: - if self._ts == None: - self._ts = ts - else: - print "Serial:_read: %.4f (%.4f) Recv:" % (ts, ts - self._ts), self._format_packet(packet[1:-3]) - self._ts = ts + if not self._s._ts: + self._s._ts = ts + self.log("Serial:_read: %.4f (%.4f) Recv: %s" % (ts, ts - self._s._ts, self._format(packet[1:-3]))) + self._ts = ts # Packet was successfully retrieved, so return it in a - # RawPacket wrapper object (but leave out the - # HDLC_FLAG_BYTE and CRC bytes) + # RawPacket wrapper object (but leave out the HDLC_FLAG_BYTE + # and CRC bytes) return RawPacket(ts, packet[1:-3]) - except socket.timeout: - raise ReadTimeoutError - - def _write_ack_filter(self, packet): - """Filter for recieved write acknowledgement packets""" - ack = AckFrame(packet.data) - if ack.protocol == self.SERIAL_PROTO_ACK: - if self._debug: - print "_filter_read: got an ack:", ack - self._ack = ack - packet = None # No further processing of received ack packet - return packet - - def _filter_read(self, timeout=None): - """Read a packet from the serial device, perform filtering, and return - the packet if it hasn't been processed yet. - - """ - p = self._read(timeout) - self._read_counter += 1 - if self._debug: - print "_filter_read: got a packet(%d): %s" % (self._read_counter, p) - - # Pass the received packet through the filter functions: - if p is not None: - for filter_func in self._received_packet_filters: - p = filter_func(p) - # Stop now if the packet doesn't need further processing: - if p is None: - break - - # Return the packet (if there was no timeout and it wasn't filtered) - return p - - def _get_ack(self, timeout, expected_seqno): - """Get the next ack packet - - Read packets from the serial device until we get the next ack (which - then gets stored in self._ack), or the timeout expires. non-ack packets - are buffered. - - Throws: - - ReadTimeoutError if the timeout expires. - - BadAckSeqnoError if an ack with a bad sequence number is received - - """ - endtime = time.time() + timeout - while time.time() < endtime: - # Read the a packet over serial - self._ack = None - remaining = endtime - time.time() - p = self._filter_read(timeout) - - # Was the packet filtered? - if p: - # Got an unfiltered packet - if len(self._in_queue) >= self._qsize: - print "Warning: Buffer overflow" - self._in_queue.pop(0) - self._in_queue.append(p) - else: - # Packet was filtered. Was it an ack? - if self._ack is not None: - # The packet was an ack, so remove it from our - # 'unacknowledged seqnos' list (or raise a BadAckSeqnoError - # error if it isn't in the list) - self._unacked_seqnos.seqno_acked(self._ack.seqno) - - # Stop reading packets if it's the ack we are waiting for: - if self._ack.seqno == expected_seqno: - return - - # Timed out - raise ReadTimeoutError - - def close(self): - """Close the serial device""" - self._s.close() - - def read(self, timeout=None): - """Read a packet, either from the input buffer or from the serial - device. - - Returns a RawPacket object, otherwise None if the packet was filtered - (by eg: Serial's printf-filtering function) - - Does not retry reads if the first one fails. Use Serial.read() for - that. - - """ - if self._in_queue: - return self._in_queue.pop(0) - else: - return self._filter_read(timeout) + except Timeout: + return None - def write(self, payload, seqno, timeout=0.2): + def write(self, payload, seqno): """ Write a packet. If the payload argument is a list, it is assumed to be exactly the payload. Otherwise the payload is assume to be a Packet and the real payload is obtain by calling the .payload(). - - Only attempts to write once, and times out if an ack packet is not - received within [timeout] seconds. Use Serial.write() if you want - automatic write retries. - - seqno should be an integer between 0 and 99 which changes each time you - send a new packet. The value should remain the same when you are - retrying a packet write that just failed. - - Raises WriteTimeoutError if the write times out (ack packet doesn't - arrive within [timeout] seconds). - """ - if type(payload) != type([]): - # Assume this will be derived from Packet + + if isinstance(payload, Packet): payload = payload.payload() + packet = DataFrame(); - packet.protocol = self.SERIAL_PROTO_PACKET_ACK + # We need to always request for acks + packet.protocol = SERIAL_PROTO_PACKET_ACK packet.seqno = seqno packet.dispatch = 0 packet.data = payload @@ -365,59 +291,14 @@ class SimpleSerial: 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] - - # Write the packet: - self._unacked_seqnos.seqno_sent(seqno) # Keep track of sent seqno's - self._put_bytes(packet) - self._write_counter += 1 - - # Wait for an ack packet: - if self._debug: - print "Send(%d/%d): %s" % (self._write_counter, self._write_counter_failures, packet) - print "Wait for ack %d ..." % (seqno) - - try: - self._get_ack(timeout, seqno) - except ReadTimeoutError: - # Re-raise read timeouts (of ack packets) as write timeouts (of - # the write operation) - self._write_counter_failures += 1 - raise WriteTimeoutError - - # Received an ack packet, with the expected sequence number - if self._debug: - print "Wait for ack %d done. Latest ack:" % (seqno), self._ack - print "The packet was acked." - print "Returning from SimpleSerial.write..." - - def add_received_packet_filter(self, filter_func): - """Register a received packet-filtering callback function + packet = [HDLC_FLAG_BYTE] + self._escape(packet) + [HDLC_FLAG_BYTE] - _filter_read() calls all of the registered filter functions for each - packet received over serial. Registered filter functions are called in - the order they were registered. + self.log("Serial: write %s" % packet) + self._s.putBytes(packet) - Filter functions are called like this: filter_func(packet) - - When a filter function recognises and handles a received packet it - should return a None value to indicate that no further processing - is required for the packet. - - When a filter function skips a packet (or for some reason you want - further processing to happen on a packet you've just processed), the - function should return the packet that was passed to it as an argument. - - """ - self._received_packet_filters.append(filter_func) - - def remove_received_packet_filter(self, filter_func): - """Remove a filter function added with add_received_packet_filter()""" - self._received_packet_filters.remove(filter_func) - - def _format_packet(self, payload): + def _format(self, payload): f = NoAckDataFrame(payload) - if f.protocol == self.SERIAL_PROTO_ACK: + if f.protocol == SERIAL_PROTO_ACK: rpacket = AckFrame(payload) return "Ack seqno: %d" % (rpacket.seqno) else: @@ -452,24 +333,6 @@ class SimpleSerial: r = (r << 8) + i return r - def _get_byte(self, timeout=None): -# old_timeout = self._s.timeout -# if timeout is not None: -# self._s.timeout = timeout - try: - r = struct.unpack("B", self._s.read())[0] - return r - except struct.error: - # Serial port read timeout - raise socket.timeout -# finally: -# self._s.timeout = old_timeout - - def _put_bytes(self, data): - #print "DEBUG: _put_bytes:", data - for b in data: - self._s.write(struct.pack('B', b)) - def _unescape(self, packet): r = [] esc = False @@ -477,7 +340,7 @@ class SimpleSerial: if esc: r.append(b ^ 0x20) esc = False - elif b == self.HDLC_CTLESC_BYTE: + elif b == HDLC_CTLESC_BYTE: esc = True else: r.append(b) @@ -486,285 +349,150 @@ class SimpleSerial: 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) + if b == HDLC_FLAG_BYTE or b == HDLC_CTLESC_BYTE: + r.append(HDLC_CTLESC_BYTE) r.append(b ^ 0x20) else: r.append(b) return r - def debug(self, debug): - self._debug = debug - - -class SeqTracker: - """Class for keeping track of unacknowledged packet sequence numbers. + def log(self, s): + if self._s.debug: + print s - SeqTracker is used by SimpleSerial to keep track of sequence numbers which - have been sent with write packets, but not yet acknowledged by received - write ack packets. +class SimpleAM(object): + def __init__(self, source, oobHook=None): + self._source = source + self._hdlc = HDLC(source) + self.seqno = 0 + self.oobHook = oobHook - """ - def __init__(self, keep_for): - """Initialise a SeqTracker object. - - args: - - - keep_for is the length of time for which unacknowledged sequence - numbers should be remembered. After this period has elapsed, the - sequence numbers should be forgotten. If the sequence number is - acknowledged later, it will be treated as unkown - - """ - self._keep_for = keep_for - self._queue = [] - - def seqno_sent(self, seqno): - """Register that a packet with the specified sequence number was just - sent.""" - self._gc() - self._queue.append((seqno, time.time())) - - def seqno_acked(self, seqno): - """Register that a sequence number was just acknowledged. - - Find the oldest-known occurance of seqno in the queue and remove it. If - not found then raise a BadAckSeqnoError to inform applications that - the sequence number is not known. - - """ - self._gc() - for item in self._queue: - if item[0] == seqno: - # Found seqno - self._queue.remove(item) - return - # seqno not found! - raise BadAckSeqnoError - - def get_seqno_sent_times(self, seqno): - """Return the times when packets with the given sequence number were - sent.""" - self._gc() - return [item[1] for item in self._queue if item[0] == seqno] - - def __contains__(self, seqno): - """Return True if the seqno was sent recently (and not acknowledged - yet)""" - self._gc() - for item in self._queue: - if item[0] == seqno: + def read(self, timeout=None): + f = self._hdlc.read(timeout) + if f: + return ActiveMessage(NoAckDataFrame(f)) + return None + + def write(self, packet, amId, timeout=5, blocking=True, inc=1): + self.seqno = (self.seqno + inc) % 256 + prevTimeout = self._source.getTimeout() + ack = None + end = None + if timeout: end = time.time() + timeout + while not end or time.time() < end: + self._hdlc.write(ActiveMessage(packet, amId=amId), seqno=self.seqno) + if not blocking: return True - return False - - def _gc(self): - """Remove old items from the queue""" - remove_before = time.time() - self._keep_for - for item in self._queue: - # Time for the sequence to be removed? - if item[1] < remove_before: - # Sequence data is old, so remove it - self._queue.remove(item) - else: - # Sequence number was added recently, so don't remove it. Also - # stop processing the queue because all later items will be - # newer + start = time.time() + f = self._hdlc.read(self._source.ackTimeout) + if f == None: + #print "Ack Timeout!" + continue + ack = AckFrame(f) + while ack.protocol != SERIAL_PROTO_ACK and (not end or time.time() < end): + if self.oobHook: + self.oobHook(ActiveMessage(NoAckDataFrame(f))) + else: + print 'SimpleAM:write: skip', ack, f + f = self._hdlc.read(self._source.ackTimeout) + if f == None: + #print "Ack Timeout!" + break + ack = AckFrame(f) + if f != None: break - - -class Serial: - """ - Wraps a SimpleSerial object, and provides some higher-level functionality - like retrying writes and logging printf packets. - """ - def __init__(self, port, baudrate, flush=False, debug=False, qsize=10, - timeout=None): - """Initialise a Serial object""" - self._debug = debug - self.timeout = timeout # Public attribute - self._seqno = 0 - self._simple_serial = SimpleSerial(port, baudrate, flush, debug, qsize, - timeout) - - # Setup automatic logging of received printf packets: - self._printf_msg = "" - self._simple_serial.add_received_packet_filter(self._printf_filter) - - def close(self): - """Close the serial device""" - self._simple_serial.close() - - def read(self, timeout=None): - """Read a packet from the serial port. - - Retries packet reads until the timeout expires. - - Throws ReadTimeoutError if a a packet can't be read within the timeout. - - """ - if timeout is None: - timeout = self.timeout - endtime = None - - if timeout is not None: - endtime = time.time() + timeout - - while endtime is None or time.time() < endtime: - remaining = None - if endtime is not None: - remaining = endtime - time.time() + self._source.setTimeout(prevTimeout) + #print 'SimpleAM:write: got an ack:', ack, ack.seqno == self.seqno + return (ack != None and ack.seqno == self.seqno) + + def setOobHook(self, oobHook): + self.oobHook = oobHook + +def printfHook(packet): + if packet == None: + return + if packet.type == 100: + s = "".join([chr(i) for i in packet.data]).strip('\0') + lines = s.split('\n') + for line in lines: + if line: print "PRINTF:", line + packet = None # No further processing for the printf packet + return packet + +class AM(SimpleAM): + def __init__(self, s=None, oobHook=None): + if s == None: try: - p = self._simple_serial.read(remaining) - except ReadError: - if self._debug: - print "Packet read failed. Try again." - else: - # Was the packet filtered? - if p is not None: - # Not filtered, so return it. - # In the current TinyOS the packets from the mote are - # always NoAckDataFrame - return NoAckDataFrame(p.data) - - # Read timeout expired - raise ReadTimeoutError - - def write(self, payload, timeout=None): - """Write a packet to the serial port - - Keeps retrying endlessly, unless a timeout is set. If the timeout - expires then WriteTimeoutError is thrown. - - """ - if timeout is None: - timeout = self.timeout - - endtime = None - if timeout is not None: - endtime = time.time() + timeout - - # Generate the next sequence number: - self._seqno = (self._seqno + 1) % 100 - - while endtime is None or time.time() < endtime: - try: - ackwait = ACK_WAIT - if endtime is not None: - remaining = endtime - time.time() - ackwait = min(ACK_WAIT, remaining) - - before = time.time() - self._simple_serial.write(payload, self._seqno, ackwait) - length = time.time() - before - - if length >= ACK_WARN: - print "Warning: Packet write took %.3fs!" % (length) - return True - except Error: - if self._debug: - print "The packet was not acked. Try again." - - # Write operation timed out - raise WriteTimeoutError - - def _printf_filter(self, packet): - """Filter for recieved printf packets""" - ampkt = ActiveMessage(NoAckDataFrame(packet.data).data) - if ampkt.type == 100: - self._printf_msg += "".join([chr(i) for i in ampkt.data]).strip('\0') - # Split printf data on newline character: - # (last string in the split list doesn't have a newline after - # it, so we keep it until next time) - lines = self._printf_msg.split('\n') - for line in lines[:-1]: - print "PRINTF:", line - self._printf_msg = lines[-1] - packet = None # No further processing for the printf packet - return packet - -class SFClient: - def __init__(self, host, port, qsize=10): - self._in_queue = Queue(qsize) - self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - self._s.connect((host, port)) - data = self._s.recv(2) - if data != 'U ': - print "Wrong handshake" - self._s.send("U ") - print "Connected" - thread.start_new_thread(self.run, ()) - - def run(self): - while True: - length = ord(self._s.recv(1)) - data = self._s.recv(length) - data = [ord(c) for c in data][1:] - #print "Recv %d bytes" % (length), ActiveMessage(data) - if self._in_queue.full(): - print "Warning: Buffer overflow" - self._in_queue.get() - p = RawPacket() - p.data = data - self._in_queue.put(p, block=False) - - def read(self, timeout=0): - return self._in_queue.get() - - def write(self, payload): - print "SFClient: write:", payload - if type(payload) != type([]): - # Assume this will be derived from Packet - payload = payload.payload() - payload = [0] + payload - self._s.send(chr(len(payload))) - self._s.send(''.join([chr(c) for c in payload])) - return True - -class AM: - def __init__(self, s): - self._s = s + s = getSource(sys.argv[1]) + except: + try: + for (i, j) in zip(sys.argv[1::2], sys.argv[2::2]): + if i == '-comm': + s = getSource(j) + if s == None: + raise Exception + except: + try: + s = getSource(os.environ['MOTECOM']) + except: + print "ERROR: Please indicate a way to connect to the mote" + sys.exit(-1) + if oobHook == None: + oobHook = printfHook + super(AM, self).__init__(s, oobHook) def read(self, timeout=None): - return ActiveMessage(self._s.read(timeout).data) - - def write(self, packet, amid, timeout=None): - return self._s.write(ActiveMessage(packet, amid=amid), timeout=timeout) - - -class SimpleSerialAM(SimpleSerial): - """A derived class of SimpleSerial so that apps can read and write using - higher-level packet structures. - - Serves a simalar purpose to the AM class, but for SimpleSerial objects - instead instead of Serial. - - """ - - def read_am(self, timeout=None): - """Read a RawPacket object (or None), convert it to ActiveMessage - (or None), and return to the caller""" - - # Get a tos.Rawpacket (or None, if filtered) object - p = self.read(timeout) - if p is not None: - assert isinstance(p, RawPacket) - # Convert tos.RawPacket object into an ActiveMessage: - p = NoAckDataFrame(p.data) - p = ActiveMessage(p.data) - - # Return the ActiveMessage (or None) packet: - return p - - def write_am(self, packet, amid, seqno, timeout=2.0): - """Convert app packet format to ActiveMessage, and write the - ActiveMessage packet to serial""" - - # Convert from app-specific packet to ActiveMessage: - p = ActiveMessage(packet, amid=amid) + return self.oobHook(super(AM, self).read(timeout)) + + def write(self, packet, amId, timeout=None, blocking=True): + r = super(AM, self).write(packet, amId, timeout, blocking) + while not r: + r = super(AM, self).write(packet, amId, timeout, blocking, inc=0) + if timeout and not r: + raise Timeout + return True - # Write to the serial device - self.write(p, seqno, timeout) +# class SFClient: +# def __init__(self, host, port, qsize=10): +# self._in_queue = Queue(qsize) +# self._s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +# self._s.connect((host, port)) +# data = self._s.recv(2) +# if data != 'U ': +# print "Wrong handshake" +# self._s.send("U ") +# print "Connected" +# thread.start_new_thread(self.run, ()) + +# def run(self): +# while True: +# length = ord(self._s.recv(1)) +# data = self._s.recv(length) +# data = [ord(c) for c in data][1:] +# #print "Recv %d bytes" % (length), ActiveMessage(data) +# if self._in_queue.full(): +# print "Warning: Buffer overflow" +# self._in_queue.get() +# p = RawPacket() +# p.data = data +# self._in_queue.put(p, block=False) + +# def read(self, timeout=0): +# return self._in_queue.get() + +# def write(self, payload): +# print "SFClient: write:", payload +# if type(payload) != type([]): +# # Assume this will be derived from Packet +# payload = payload.payload() +# payload = [0] + payload +# self._s.send(chr(len(payload))) +# self._s.send(''.join([chr(c) for c in payload])) +# return True + + +################################################################################ class Packet: """ @@ -786,6 +514,11 @@ class Packet: output.reverse() return output + def _sign(self, val, dim): + if val > (1 << (dim * 8 - 1)): + return val - (1 << (dim * 8)) + return val + def __init__(self, desc, packet = None): offset = 0 boffset = 0 @@ -805,6 +538,9 @@ class Packet: if t == 'int': self._values.append(self._decode(packet[offset:offset + s])) offset += s + elif t == 'sint': + self._values.append(self._sign(self._decode(packet[offset:offset + s]), s)) + offset += s elif t == 'bint': doffset = 8 - (boffset + s) self._values.append((packet[offset] >> doffset) & ((1<