]> git.llucax.com Git - z.facultad/66.09/etherled.git/blob - cliente/etherled/protocol.py
Agrega implementación del protocolo y un server (emulador del dispositivo) de prueba.
[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 class SendError(socket.error):
36     pass
37
38 class RecvError(socket.error):
39     pass
40
41 class Client(object):
42
43     def __init__(self, host='localhost', port=38437, timeout=3.0):
44         self._host = host
45         self._port = port
46         self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
47         self._sock.connect(self.addr)
48         self._sock.settimeout(timeout)
49         self._ids = {}
50         self._drop = 0
51
52     def send(self, type, var, data=None):
53         pkt = packet.ClientPacket(type, var, self._getId(type, var), data)
54         try:
55             sent = self._sock.send(str(pkt))
56         except socket.timeout:
57             raise SendError, "Tiempo de espera agotado"
58         if sent != len(pkt):
59             raise SendError, "Sólo se enviaron %d bytes de %d" \
60                 % (sent, len(pkt))
61         while True:
62             try:
63                 msg = self._sock.recv(_BUFSIZ)
64             except socket.timeout:
65                 raise RecvError, "Tiempo de espera agotado"
66             pkt_r = packet.ClientPacket(msg)
67             if pkt == pkt_r:
68                 break # paquete ok
69             self._drop += 1
70         return pkt_r.data
71
72     def get(self, var):
73         return self.send(packet.TYPE_GET, var)
74
75     def set(self, var, data):
76         self.send(packet.TYPE_SET, var, data)
77
78     def _getId(self, type, var):
79         id = self._ids.get((type, var), 0)
80         self._ids[type, var] = (id + 1) % packet.MAX_ID
81         return id
82
83     def _getHost(self):
84         return self._host
85
86     def _getPort(self):
87         return self._port
88
89     def _getAddr(self):
90         return (self._host, self._port)
91
92     def _getDrop(self):
93         return self._drop
94
95     host = property(_getHost, doc='Host al cual enviar datos')
96     port = property(_getPort, doc='Puerto al cual enviar datos')
97     addr = property(_getAddr, doc='Tupla (host, port)')
98     drop = property(_getDrop, doc='Cantidad de paquetes descartados')
99
100 class NetworkedDevice(Client):
101
102     LED_BYTES = 2
103
104     def _getMatrix(self):
105         stream = self.get(packet.VAR_MATRIX)
106         return self._stream2Matrix(stream)
107
108     def _setMatrix(self, matrix):
109         stream = self._matrix2Stream(matrix)
110         self.set(packet.VAR_MATRIX, stream)
111
112     def _stream2Matrix(self, stream):
113         cols = ord(stream[0]) # Obtiene tamaño
114         stream = stream[1:1+cols*self.LED_BYTES] # me quedo con el resto
115         matrix = {}
116         for col in xrange(cols-1, -1, -1):
117             for row_byte in xrange(self.LED_BYTES):
118                 byte = ord(stream[(cols-col-1)*self.LED_BYTES+row_byte])
119                 for i in xrange(8):
120                     shift = 8 - i - 1
121                     matrix[col, row_byte*8+i] = (byte >> shift) & 1
122         return matrix
123
124     def _matrix2Stream(self, matrix):
125         cols = len(matrix) / (self.LED_BYTES*8)
126         stream = chr(cols) # primero va el tamaño
127         for col in xrange(cols-1, -1, -1):
128             for i in xrange(self.LED_BYTES):
129                 byte = 0
130                 for row in xrange(8):
131                     shift = 8 - row - 1
132                     byte += matrix[col,row] << shift
133                 stream += chr(byte)
134         return stream
135
136     matrix = property(_getMatrix, _setMatrix, doc='Matriz de leds')
137
138 class DummyServer:
139
140     def __init__(self, host='localhost', port=38437, timeout=3.0):
141         self._host = host
142         self._port = port
143         self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
144         self._sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
145         self._sock.bind(self.addr)
146         self._vars = [None for i in xrange(8)]
147
148     def run(self):
149         while True:
150             (msg, addr) = self._sock.recvfrom(_BUFSIZ)
151             pkt = packet.ServerPacket(msg)
152             if pkt.type == packet.TYPE_GET:
153                 pkt.data = self._vars[pkt.var]
154             elif pkt.type == packet.TYPE_SET:
155                 self._vars[pkt.var] = pkt.data
156                 pkt = packet.ServerPacket(pkt.type, pkt.var, pkt.id)
157             sent = self._sock.sendto(str(pkt), addr)
158             if sent != len(pkt):
159                 raise SendError, "Sólo se enviaron %d bytes de %d" \
160                     % (sent, len(packet))
161
162     def _getHost(self):
163         return self._host
164
165     def _getPort(self):
166         return self._port
167
168     def _getAddr(self):
169         return (self._host, self._port)
170
171     host = property(_getHost, doc='Host al cual enviar datos')
172     port = property(_getPort, doc='Puerto al cual enviar datos')
173     addr = property(_getAddr, doc='Tupla (host, port)')
174
175 def _print_matrix(matrix):
176     for row in xrange(NetworkedDevice.LED_BYTES*8):
177         for col in xrange(len(matrix)/(NetworkedDevice.LED_BYTES*8)):
178             print matrix[row,col],
179         print
180     print
181
182 def _print_stream(stream):
183     for c in stream:
184         print '0x%02X' % ord(c),
185     print
186     print
187
188 # Prueba
189 if __name__ == '__main__':
190     import os, sys, time
191     pid = os.fork()
192     if pid:
193         time.sleep(0.1)
194         # Creo dispositivo por red
195         dev = NetworkedDevice()
196         # Creo matriz
197         matrix = {}
198         for col in xrange(16):
199             for row in xrange(16):
200                 matrix[row,col] = row % 2
201         # Mando matriz
202         print 'Matriz enviada:'
203         _print_matrix(matrix)
204         dev.matrix = matrix
205         print 'Matriz recibida:'
206         _print_matrix(dev.matrix)
207         # Verifico resultado
208         assert matrix == dev.matrix
209         ###########################
210         # Creo matriz
211         matrix = {}
212         for col in xrange(16):
213             for row in xrange(16):
214                 matrix[row,col] = col % 2
215         # Mando matriz
216         print 'Matriz enviada:'
217         _print_matrix(matrix)
218         dev.matrix = matrix
219         print 'Matriz recibida:'
220         _print_matrix(dev.matrix)
221         # Verifico resultado
222         assert matrix == dev.matrix
223         ###########################
224         # Creo matriz
225         matrix = {}
226         for col in xrange(16):
227             for row in xrange(16):
228                 matrix[row,col] = (col+row) % 2
229         # Mando matriz
230         print 'Matriz enviada:'
231         _print_matrix(matrix)
232         dev.matrix = matrix
233         print 'Matriz recibida:'
234         _print_matrix(dev.matrix)
235         # Verifico resultado
236         assert matrix == dev.matrix
237         # Matamos al servidor
238         os.kill(pid, 15)
239     else:
240         server = DummyServer()
241         server.run()
242         sys.exit(0)
243     print "OK!"
244