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