]> defiant.homedns.org Git - pyshared.git/blob - protocol.py
Bootloader: Allow to set i2c addr
[pyshared.git] / protocol.py
1 #!/usr/bin/env python
2 # -*- coding: iso-8859-15 -*-
3
4 import struct
5 import threading
6 import math
7 from pycrc.crc_algorithms import Crc
8
9 class ByteError(Exception):
10         def __init__(self, value):
11                 Exception.__init__(self)
12                 self.value = value
13         def __str__(self):
14                 return "Byte Error, got 0x%x" % self.value
15
16 class CRCError(Exception):
17         def __str__(self):
18                 return "CRC Error"
19
20 class TimeoutException(Exception):
21         def __str__(self):
22                 return "Timeout"
23
24 class NAKReceived(Exception):
25         def __str__(self):
26                 return "NAK received"
27
28 class PackageTooBigException(Exception):
29         def __str__(self):
30                 return "Package too long"
31
32
33 class Protocol:
34         ENQ = 0x5
35         ACK = 0x6
36         DC1 = 0x11
37         NAK = 0x21
38         MAX_LEN = 128
39         STATE_DEFAULT = 0
40         STATE_LEN = 1
41         STATE_READ = 2
42         
43         def __init__(self, conn):
44                 self.conn = conn
45                 self.lock = threading.Lock()
46                 self.crc = Crc(width = 8, poly = 0x07, reflect_in = False, xor_in = 0x0, reflect_out = False, xor_out = 0x00)
47
48         def __get_ack(self):
49                 c = ""
50                 for i in range(60):
51                         try:
52                                 c = self.conn.read(1)
53                         except:
54                                 continue
55                         if c:
56                                 break
57                 if not c:
58                         self.conn.close()
59                         raise TimeoutException()
60                 c = ord(c)
61                 if c not in (self.ACK, self.NAK):
62                         raise ByteError(c)
63                 return c == self.ACK
64
65         def send(self, addr, msg, bSlitMsg=False):
66                 msg_len = 3 + len(msg) + 1
67                 if bSlitMsg and msg_len > self.MAX_LEN:
68                         num_per_packet = self.MAX_LEN - 3 - 1
69                         num_packets = math.ceil(len(msg)/float(num_per_packet))
70                         self.send(addr, "%cSplit %d" % (self.DC1, num_packets))
71                         for i in range(0, len(msg), num_per_packet):
72                                 msg_part = msg[i:i+num_per_packet]
73                                 self.send(addr, msg_part)
74                         return
75                 self.lock.acquire()
76                 try:
77                         if msg_len > self.MAX_LEN:
78                                 raise PackageTooBigException()
79                         packet = struct.pack("<BBB%ds" % len(msg), self.ENQ, msg_len, addr, msg)
80                         packet+=chr(self.crc.bit_by_bit_fast(packet))
81                         self.conn.write(packet)
82                         if not self.__get_ack():
83                                 raise NAKReceived()
84                 except:
85                         raise
86                 finally:
87                         self.lock.release()
88
89         def write(self, addr, msg):
90                 return self.send(addr, msg)
91
92         def __reply_ack(self):
93                 self.conn.write(chr(self.ACK))
94         
95         def __reply_nak(self):
96                 self.conn.write(chr(self.NAK))
97
98         def receive(self):
99                 packet = ""
100                 num = 0
101                 state = self.STATE_DEFAULT
102                 self.lock.acquire()
103                 try:
104                         while(True):
105                                 c = self.conn.read(1)
106                                 if not c:
107                                         raise
108                                 if state == self.STATE_DEFAULT:
109                                         if ord(c) != self.ENQ:
110                                                 self.__reply_nak()
111                                                 raise ByteError(ord(c))
112                                         state = self.STATE_LEN
113                                         packet = c
114                                 elif state == self.STATE_LEN:
115                                         if ord(c) > self.MAX_LEN:
116                                                 self.__reply_nak()
117                                                 raise PackageTooBigException()
118                                         state = self.STATE_READ
119                                         packet += c
120                                         num = ord(c)-2
121                                 elif state == self.STATE_READ:
122                                         packet += c
123                                         num-=1
124                                         if num == 0:
125                                                 if self.crc.bit_by_bit_fast(packet) == 0:
126                                                         self.__reply_ack()
127                                                         msgtype, msglen, addr, msg, crc = struct.unpack("<BBB%dsB" % (len(packet)-3-1), packet)
128                                                         return addr, msg
129                                                 else:
130                                                         self.__reply_nak()
131                                                         raise CRCError()
132                 except:
133                         raise
134                 finally:
135                         self.lock.release()
136         
137         def read(self):
138                 addr, msg = self.receive()
139                 if msg[0] == chr(self.DC1) and len(msg) > 1:
140                         lCmd = msg[1:].split()
141                         if len(lCmd) == 2 and lCmd[0] == "Split":
142                                 num = int(lCmd[1])
143                                 msg = ""
144                                 for i in range(num):
145                                         addr_part, msg_part = self.receive()
146                                         if addr_part == addr:
147                                                 msg+=msg_part
148                 return addr, msg
149
150 if __name__ == "__main__":
151         import sys
152         if (len(sys.argv) > 2):
153                 # sender
154                 with open(sys.argv[1], "a+") as f:
155                         p = Protocol(f)
156                         p.write(int(sys.argv[2]), sys.argv[3])
157         else:
158                 # receiver
159                 with open(sys.argv[1], "a+") as f:
160                         p = Protocol(f)
161                         print p.read()