línea de comandos que permite obtener y setear todos los valores básicos (delay,
pause, off y obtener la matriz). Además tiene una interfaz gráfica para dibujar
la matriz y enviarla (o recibirla).
<property name="homogeneous">False</property>
<property name="spacing">10</property>
- <child>
- <widget class="GtkHBox" id="hbox3">
- <property name="visible">True</property>
- <property name="homogeneous">False</property>
- <property name="spacing">5</property>
-
- <child>
- <widget class="GtkLabel" id="label3">
- <property name="visible">True</property>
- <property name="label" translatable="yes">IP:</property>
- <property name="use_underline">False</property>
- <property name="use_markup">False</property>
- <property name="justify">GTK_JUSTIFY_LEFT</property>
- <property name="wrap">False</property>
- <property name="selectable">False</property>
- <property name="xalign">0.5</property>
- <property name="yalign">0.5</property>
- <property name="xpad">0</property>
- <property name="ypad">0</property>
- <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
- <property name="width_chars">-1</property>
- <property name="single_line_mode">False</property>
- <property name="angle">0</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">False</property>
- <property name="fill">False</property>
- </packing>
- </child>
-
- <child>
- <widget class="GtkEntry" id="entry_ip">
- <property name="visible">True</property>
- <property name="can_focus">True</property>
- <property name="editable">True</property>
- <property name="visibility">True</property>
- <property name="max_length">0</property>
- <property name="text" translatable="yes"></property>
- <property name="has_frame">True</property>
- <property name="invisible_char">*</property>
- <property name="activates_default">False</property>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
- </widget>
- <packing>
- <property name="padding">0</property>
- <property name="expand">True</property>
- <property name="fill">True</property>
- </packing>
- </child>
-
<child>
<widget class="GtkTable" id="table_leds">
<property name="visible">True</property>
import gtk
from simplegladeapp import SimpleGladeApp
from simplegladeapp import bindtextdomain
+from optparse import OptionParser
#from dispatcher import Dispatcher
from led import Led
import etherled
bindtextdomain(app_name, locale_dir)
+ROWS = 16
+
class MainWindow(SimpleGladeApp):
def __init__(self, path="cetherled.glade", root="main_window",
domain=app_name, **kwargs):
+ self.columns = kwargs.get('columns', 16)
+ self.host = kwargs.get('host', 'localhost')
+ self.port = kwargs.get('port', 9876)
#notificar = Dispatcher(self.actualizar)
- self.device = etherled.NetworkedDevice()
+ self.device = etherled.NetworkedDevice(self.host, self.port)
path = os.path.join(glade_dir, path)
SimpleGladeApp.__init__(self, path, root, domain, **kwargs)
def new(self):
self.tabla = {}
- for i in xrange(16):
- for j in xrange(16):
+ for i in xrange(ROWS):
+ for j in xrange(self.columns):
led = Led()
self.table_leds.attach(led, j, j+1, i, i+1)
led.show()
def on_btn_recibir_clicked(self, widget, *args):
matrix = self.device.matrix
- for row in xrange(16):
- for col in xrange(16):
+ for row in xrange(ROWS):
+ for col in xrange(self.columns):
self.tabla[row,col].prendido = matrix[row,col]
+ self.tabla[row,col].queue_draw()
etherled.protocol._print_matrix(matrix)
def on_main_window_delete_event(self, widget, event, *args):
def leds2matrix(self):
matrix = {}
- for row in xrange(16):
- for col in xrange(16):
+ for row in xrange(ROWS):
+ for col in xrange(self.columns):
matrix[row,col] = int(self.tabla[row,col].prendido)
etherled.protocol._print_matrix(matrix)
return matrix
+
+def parse_options():
+ parser = OptionParser(description="Cliente de etherled",
+ version="%prog " + app_version, prog='cetherled')
+ parser.add_option("-s", "--server", default='localhost', dest="host",
+ metavar="HOSTNAME", help="Nombre/IP del host del dispositivo "
+ "[default: localhost]")
+ parser.add_option("-p", "--port", default=9876, metavar="PORT",
+ type="int", help="Puerto UDP del dispositivo [default: 9876].")
+ parser.add_option("-c", "--columns", default=16, metavar="COLS",
+ type="int", help="Cantidad de columnas de la matriz [default: 16].")
+ parser.add_option("-g", "--gui", default=False, action="store_true",
+ help="Levanta la interfaz gráfica para dibujar la matriz")
+ (opts, args) = parser.parse_args()
+ return (parser, opts, args)
+
+
def main():
- gtk.threads_init()
- main_window = MainWindow()
- gtk.threads_enter()
- main_window.run()
- gtk.threads_leave()
+ (parser, opts, args) = parse_options()
+ if (opts.columns < 8) or (opts.columns > 32):
+ parser.error("El número de columnas debe estar entre 8 y 32.")
+ if opts.gui:
+ gtk.threads_init()
+ main_window = MainWindow(columns=opts.columns, host=opts.host,
+ port=opts.port)
+ gtk.threads_enter()
+ main_window.run()
+ gtk.threads_leave()
+ else:
+ if len(args) < 2:
+ parser.error("Debe especificarse un comando si no se usa la GUI.")
+ type = args[0]
+ var = args[1]
+ dev = etherled.NetworkedDevice(opts.host, opts.port)
+ if type == 'get':
+ if len(args) > 2:
+ parser.error("El comando get no puede llevar argumentos.")
+ if var == 'matrix':
+ etherled.protocol._print_matrix(dev.matrix)
+ elif var == 'pause':
+ print dev.paused
+ elif var == 'delay':
+ print dev.delay
+ else:
+ parser.error("Variable desconocida, debe ser una de: "
+ "matrix, pause, delay.")
+ elif type == 'set':
+ if var == 'off':
+ dev.turn_off()
+ elif var == 'matrix':
+ parser.error("Use la GUI para enviar la matriz.")
+ elif var == 'pause':
+ dev.paused = True
+ elif var == 'continue':
+ dev.paused = False
+ elif var == 'delay':
+ if len(args) != 3:
+ parser.error("Delay lleva 1 argumento.")
+ dev.delay = int(args[2])
+ else:
+ parser.error("Variable desconocida, debe ser una de: "
+ "off, pause, continue, delay.")
+
if __name__ == '__main__':
main()
# Autores: Leandro Lucarella <llucare@fi.uba.ar>
#----------------------------------------------------------------------------
+from sets import ImmutableSet as frozenset
+
# Tipos de operación
TYPE_GET = 0
TYPE_SET = 1
# Variables
-VAR_MATRIX = 0
+VAR_OFF = 0
+VAR_MATRIX = 1
+VAR_PAUSE = 2
+VAR_DELAY = 3
-# Limites
-MAX_ID = 8
-MAX_VAR = 8
+# Variables soportadas
+supported_vars = frozenset([VAR_OFF, VAR_MATRIX, VAR_PAUSE, VAR_DELAY])
-class ParityError(ValueError):
- pass
+# Limites
+MAX_ID = 7
class Packet(object):
def fromStr(self, string):
header = ord(string[0])
- self.type = header >> 7
- self.var = (header & 0x70) >> 4
- self.id = (header & 0x0E) >> 1
- par = header & 0x01
- if self.par != par:
- raise ParityError
+ self.type = header >> 7 # bit 7
+ self.var = (header & 0x78) >> 3 # bits 6 5 4 3
+ self.id = (header & 0x07) # bits 2 1 0
self.data = string[1:] or None
def __str__(self):
return self.type == p.type and self.var == p.var and self.id == p.id
def _header_to_int(self):
- res = (self.type << 7) + (self.var << 4) + (self.id << 1)
- return res + self.par
-
- def _getPar(self):
- par = self.type
- for i in xrange(3):
- par += int((self.var & (1 << i)) != 0)
- for i in xrange(3):
- par += int((self.id & (1 << i)) != 0)
- return par % 2
+ return (self.type << 7) + (self.var << 3) + self.id
def _getType(self):
return self._type
return self._var
def _setVar(self, var):
- if var < 0 and var >= self.MAX_VAR:
- raise ValueError, "var debe estar entre 0 y %d" % self.MAX_VAR-1
+ if var not in supported_vars:
+ raise ValueError, "var puede ser uno de %s" % tuple(supported_vars)
self._var = var
def _getId(self):
return self._id
def _setId(self, id):
- if id < 0 and id >= self.MAX_ID:
- raise ValueError, "id debe estar entre 0 y %d" % self.MAX_ID-1
+ if id < 0 or id > MAX_ID:
+ raise ValueError, "id debe estar entre 0 y %d" % MAX_ID
self._id = id
type = property(_getType, _setType, doc="Tipo de operación")
var = property(_getVar, _setVar, doc="Variable con la cual operar")
id = property(_getId, _setId, doc="Identificador del paquete")
- par = property(_getPar, doc="Paridad de la cabecera del paquete")
class ClientPacket(Packet):
# Prueba
if __name__ == '__main__':
- assert str(Packet(1, 7, 7)) == '\xFF'
- assert str(Packet(0, 0, 0)) == '\x00'
- assert str(Packet(1, 1, 1)) == '\x93'
- assert str(Packet(TYPE_SET, VAR_MATRIX, 2)) == '\x84'
- assert str(Packet(TYPE_GET, 4, 0)) == 'A'
- assert str(Packet(TYPE_GET, 4, 0, 'hola')) == 'Ahola'
- p = Packet(TYPE_GET, 4, 0, 'hola')
+ # GET
+ assert str(Packet(TYPE_GET, VAR_OFF, 0)) == chr(0x00)
+ assert str(Packet(TYPE_GET, VAR_OFF, 7)) == chr(0x07)
+ assert str(Packet(TYPE_GET, VAR_MATRIX, 1)) == chr(0x09)
+ assert str(Packet(TYPE_GET, VAR_MATRIX, 6)) == chr(0x0E)
+ assert str(Packet(TYPE_GET, VAR_PAUSE, 2)) == chr(0x12)
+ assert str(Packet(TYPE_GET, VAR_PAUSE, 5)) == chr(0x15)
+ assert str(Packet(TYPE_GET, VAR_DELAY, 3)) == chr(0x1B)
+ assert str(Packet(TYPE_GET, VAR_DELAY, 4)) == chr(0x1C)
+ assert str(Packet(TYPE_GET, VAR_DELAY, 7, 'hola')) == chr(0x1F) + 'hola'
+ p = Packet(TYPE_GET, VAR_MATRIX, 0, 'hola')
+ assert Packet(str(p)) == p
+ # SET
+ assert str(Packet(TYPE_SET, VAR_OFF, 0)) == chr(0x80)
+ assert str(Packet(TYPE_SET, VAR_OFF, 7)) == chr(0x87)
+ assert str(Packet(TYPE_SET, VAR_MATRIX, 1)) == chr(0x89)
+ assert str(Packet(TYPE_SET, VAR_MATRIX, 6)) == chr(0x8E)
+ assert str(Packet(TYPE_SET, VAR_PAUSE, 2)) == chr(0x92)
+ assert str(Packet(TYPE_SET, VAR_PAUSE, 5)) == chr(0x95)
+ assert str(Packet(TYPE_SET, VAR_DELAY, 3)) == chr(0x9B)
+ assert str(Packet(TYPE_SET, VAR_DELAY, 4)) == chr(0x9C)
+ assert str(Packet(TYPE_SET, VAR_DELAY, 7, 'hola')) == chr(0x9F) + 'hola'
+ p = Packet(TYPE_SET, VAR_MATRIX, 0, 'hola')
assert Packet(str(p)) == p
print "OK!"
class Client(object):
- def __init__(self, host='localhost', port=38437, timeout=3.0):
+ def __init__(self, host='localhost', port=9876, timeout=3.0):
self._host = host
self._port = port
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
except socket.timeout:
raise RecvError, "Tiempo de espera agotado"
pkt_r = packet.ClientPacket(msg)
+ # Verifica ACK
if pkt == pkt_r:
break # paquete ok
self._drop += 1
def _getId(self, type, var):
id = self._ids.get((type, var), 0)
- self._ids[type, var] = (id + 1) % packet.MAX_ID
+ self._ids[type, var] = (id + 1) % (packet.MAX_ID + 1)
return id
def _getHost(self):
class NetworkedDevice(Client):
+ def turn_off(self):
+ self.set(packet.VAR_OFF)
+
def _getMatrix(self):
stream = self.get(packet.VAR_MATRIX)
return _stream2Matrix(stream)
stream = _matrix2Stream(matrix)
self.set(packet.VAR_MATRIX, stream)
+ def _getPaused(self):
+ return bool(ord(self.get(packet.VAR_PAUSE)))
+
+ def _setPaused(self, paused):
+ self.set(packet.VAR_PAUSE, chr(paused))
+
+ def _getDelay(self):
+ return ord(self.get(packet.VAR_DELAY))
+
+ def _setDelay(self, delay):
+ self.set(packet.VAR_DELAY, chr(delay & 0xFF))
+
matrix = property(_getMatrix, _setMatrix, doc='Matriz de leds')
+ paused = property(_getPaused, _setPaused,
+ doc='Indica si el dispositivo está en pausa')
+ delay = property(_getDelay, _setDelay,
+ doc='Timpo de retardo del dibujado')
class DummyServer:
- def __init__(self, host='localhost', port=38437, timeout=3.0):
+ def __init__(self, host='localhost', port=9876, timeout=3.0):
self._host = host
self._port = port
self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
cols = ord(stream[0]) # Obtiene tamaño
stream = stream[1:1+cols*_LED_BYTES] # me quedo con el resto
matrix = {}
- for col in xrange(cols-1, -1, -1):
+ for col in xrange(cols):
for row_byte in xrange(_LED_BYTES):
- byte = ord(stream[(cols-col-1)*_LED_BYTES+row_byte])
+ byte = ord(stream[col*_LED_BYTES+_LED_BYTES-row_byte-1])
for i in xrange(8):
- shift = 8 - i - 1
- matrix[row_byte*8+i,col] = (byte >> shift) & 1
+ matrix[row_byte*8+i,col] = (byte >> i) & 1
return matrix
def _matrix2Stream(matrix):
cols = len(matrix) / (_LED_BYTES*8)
stream = chr(cols) # primero va el tamaño
- for col in xrange(cols-1, -1, -1):
- for i in xrange(_LED_BYTES):
+ for col in xrange(cols):
+ for i in xrange(_LED_BYTES-1, -1, -1):
byte = 0
- for row in xrange(8):
- shift = 8 - row - 1
- byte += matrix[row+i*8,col] << shift
+ for row in xrange(7, -1, -1):
+ byte += matrix[row+i*8,col] << row
stream += chr(byte)
return stream
_print_matrix(dev.matrix)
# Verifico resultado
assert matrix == dev.matrix
+ # Probamos con otras cositas
+ dev.paused = True
+ assert dev.paused == True
+ dev.paused = False
+ assert dev.paused == False
+ dev.delay = 0x40
+ assert dev.delay == 0x40
+ dev.delay = 0xff
+ assert dev.delay == 0xff
# Matamos al servidor
os.kill(pid, 15)
else: