]> git.llucax.com Git - z.facultad/66.09/etherled.git/blob - cliente/etherled/protocol.py
Implementado el checksum de UDP, tanto para paquetes recibidos como para
[z.facultad/66.09/etherled.git] / cliente / etherled / protocol.py
1 #!/usr/bin/env python
2 # -*- coding: iso-8859-1 -*-
3 # vim: set expandtab tabstop=4 shiftwidth=4 :
4 #----------------------------------------------------------------------------
5 #                               Etherled
6 #----------------------------------------------------------------------------
7 # This file is part of etherled.
8 #
9 # etherled is free software; you can redistribute it and/or modify it
10 # under the terms of the GNU General Public License as published by the Free
11 # Software Foundation; either version 2 of the License, or (at your option)
12 # any later version.
13 #
14 # etherled is distributed in the hope that it will be useful, but
15 # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
16 # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
17 # more details.
18 #
19 # You should have received a copy of the GNU General Public License along
20 # with etherled; if not, write to the Free Software Foundation, Inc., 59
21 # Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 #----------------------------------------------------------------------------
23 # Creado:  sáb oct 29 00:45:52 ART 2005
24 # Autores: Leandro Lucarella <llucare@fi.uba.ar>
25 #----------------------------------------------------------------------------
26
27 import socket
28 import packet
29
30 __all__ = ('SendError', 'RecvError', 'Client', 'NetworkedDevice', 'DummyServer')
31
32 # Tamaño del buffer
33 _BUFSIZ = 65536
34
35 # Cantidad de bytes de la columna de leds
36 _LED_BYTES = 2
37
38 class SendError(socket.error):
39     pass
40
41 class RecvError(socket.error):
42     pass
43
44 class Client(object):
45
46     def __init__(self, host='localhost', port=38437, timeout=3.0):
47         self._host = host
48         self._port = port
49         self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
50         self._sock.connect(self.addr)
51         self._sock.settimeout(timeout)
52         self._ids = {}
53         self._drop = 0
54
55     def send(self, type, var, data=None):
56         pkt = packet.ClientPacket(type, var, self._getId(type, var), data)
57         try:
58             sent = self._sock.send(str(pkt))
59         except socket.timeout:
60             raise SendError, "Tiempo de espera agotado"
61         if sent != len(pkt):
62             raise SendError, "Sólo se enviaron %d bytes de %d" \
63                 % (sent, len(pkt))
64         while True:
65             try:
66                 msg = self._sock.recv(_BUFSIZ)
67             except socket.timeout:
68                 raise RecvError, "Tiempo de espera agotado"
69             pkt_r = packet.ClientPacket(msg)
70             if pkt == pkt_r:
71                 break # paquete ok
72             self._drop += 1
73         return pkt_r.data
74
75     def get(self, var):
76         return self.send(packet.TYPE_GET, var)
77
78     def set(self, var, data):
79         self.send(packet.TYPE_SET, var, data)
80
81     def _getId(self, type, var):
82         id = self._ids.get((type, var), 0)
83         self._ids[type, var] = (id + 1) % packet.MAX_ID
84         return id
85
86     def _getHost(self):
87         return self._host
88
89     def _getPort(self):
90         return self._port
91
92     def _getAddr(self):
93         return (self._host, self._port)
94
95     def _getDrop(self):
96         return self._drop
97
98     host = property(_getHost, doc='Host al cual enviar datos')
99     port = property(_getPort, doc='Puerto al cual enviar datos')
100     addr = property(_getAddr, doc='Tupla (host, port)')
101     drop = property(_getDrop, doc='Cantidad de paquetes descartados')
102
103 class NetworkedDevice(Client):
104
105     def _getMatrix(self):
106         stream = self.get(packet.VAR_MATRIX)
107         return _stream2Matrix(stream)
108
109     def _setMatrix(self, matrix):
110         stream = _matrix2Stream(matrix)
111         self.set(packet.VAR_MATRIX, stream)
112
113     matrix = property(_getMatrix, _setMatrix, doc='Matriz de leds')
114
115 class DummyServer:
116
117     def __init__(self, host='localhost', port=38437, timeout=3.0):
118         self._host = host
119         self._port = port
120         self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
121         self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
122         self._sock.bind(self.addr)
123         self._vars = [None for i in xrange(8)]
124
125     def run(self):
126         while True:
127             (msg, addr) = self._sock.recvfrom(_BUFSIZ)
128             pkt = packet.ServerPacket(msg)
129             print 'Recibido:', repr(pkt)
130             if pkt.type == packet.TYPE_GET:
131                 pkt.data = self._vars[pkt.var]
132             elif pkt.type == packet.TYPE_SET:
133                 if pkt.var == packet.VAR_MATRIX:
134                     _print_matrix(_stream2Matrix(pkt.data))
135                 self._vars[pkt.var] = pkt.data
136                 pkt = packet.ServerPacket(pkt.type, pkt.var, pkt.id)
137             sent = self._sock.sendto(str(pkt), addr)
138             if sent != len(pkt):
139                 raise SendError, "Sólo se enviaron %d bytes de %d" \
140                     % (sent, len(packet))
141             print 'Enviado:', repr(pkt)
142             if pkt.type == packet.TYPE_GET and pkt.var == packet.VAR_MATRIX:
143                 _print_matrix(_stream2Matrix(pkt.data))
144
145     def _getHost(self):
146         return self._host
147
148     def _getPort(self):
149         return self._port
150
151     def _getAddr(self):
152         return (self._host, self._port)
153
154     host = property(_getHost, doc='Host al cual enviar datos')
155     port = property(_getPort, doc='Puerto al cual enviar datos')
156     addr = property(_getAddr, doc='Tupla (host, port)')
157
158 def _stream2Matrix(stream):
159     cols = ord(stream[0]) # Obtiene tamaño
160     stream = stream[1:1+cols*_LED_BYTES] # me quedo con el resto
161     matrix = {}
162     for col in xrange(cols-1, -1, -1):
163         for row_byte in xrange(_LED_BYTES):
164             byte = ord(stream[(cols-col-1)*_LED_BYTES+row_byte])
165             for i in xrange(8):
166                 shift = 8 - i - 1
167                 matrix[row_byte*8+i,col] = (byte >> shift) & 1
168     return matrix
169
170 def _matrix2Stream(matrix):
171     cols = len(matrix) / (_LED_BYTES*8)
172     stream = chr(cols) # primero va el tamaño
173     for col in xrange(cols-1, -1, -1):
174         for i in xrange(_LED_BYTES):
175             byte = 0
176             for row in xrange(8):
177                 shift = 8 - row - 1
178                 byte += matrix[row+i*8,col] << shift
179             stream += chr(byte)
180     return stream
181
182 def _print_matrix(matrix):
183     for row in xrange(_LED_BYTES*8):
184         for col in xrange(len(matrix)/(_LED_BYTES*8)):
185             print matrix[row,col],
186         print
187     print
188
189 def _print_stream(stream):
190     for c in stream:
191         print '0x%02X' % ord(c),
192     print
193     print
194
195 # Prueba
196 if __name__ == '__main__':
197     import os, sys, time
198     pid = os.fork()
199     if pid:
200         time.sleep(0.1)
201         # Creo dispositivo por red
202         dev = NetworkedDevice()
203         # Creo matriz
204         matrix = {}
205         for col in xrange(16):
206             for row in xrange(16):
207                 matrix[row,col] = row % 2
208         # Mando matriz
209         print 'Matriz enviada:'
210         _print_matrix(matrix)
211         dev.matrix = matrix
212         print 'Matriz recibida:'
213         _print_matrix(dev.matrix)
214         # Verifico resultado
215         assert matrix == dev.matrix
216         ###########################
217         # Creo matriz
218         matrix = {}
219         for col in xrange(16):
220             for row in xrange(16):
221                 matrix[row,col] = col % 2
222         # Mando matriz
223         print 'Matriz enviada:'
224         _print_matrix(matrix)
225         dev.matrix = matrix
226         print 'Matriz recibida:'
227         _print_matrix(dev.matrix)
228         # Verifico resultado
229         assert matrix == dev.matrix
230         ###########################
231         # Creo matriz
232         matrix = {}
233         for col in xrange(16):
234             for row in xrange(16):
235                 matrix[row,col] = (col+row) % 2
236         # Mando matriz
237         print 'Matriz enviada:'
238         _print_matrix(matrix)
239         dev.matrix = matrix
240         print 'Matriz recibida:'
241         _print_matrix(dev.matrix)
242         # Verifico resultado
243         assert matrix == dev.matrix
244         ###########################
245         # Creo matriz
246         matrix = {}
247         for col in xrange(16):
248             for row in xrange(16):
249                 matrix[row,col] = 0
250         matrix[0,0] = 1
251         matrix[0,14] = 1
252         matrix[0,15] = 1
253         matrix[1,15] = 1
254         matrix[13,0] = 1
255         matrix[14,0] = 1
256         matrix[15,0] = 1
257         matrix[15,1] = 1
258         matrix[15,2] = 1
259         matrix[12,15] = 1
260         matrix[13,15] = 1
261         matrix[14,15] = 1
262         matrix[15,15] = 1
263         matrix[15,14] = 1
264         matrix[15,13] = 1
265         matrix[15,12] = 1
266         # Mando matriz
267         print 'Matriz enviada:'
268         _print_matrix(matrix)
269         dev.matrix = matrix
270         print 'Matriz recibida:'
271         _print_matrix(dev.matrix)
272         # Verifico resultado
273         assert matrix == dev.matrix
274         # Matamos al servidor
275         os.kill(pid, 15)
276     else:
277         server = DummyServer()
278         server.run()
279         sys.exit(0)
280     print "OK!"
281