Groovy colours :)
[zanchey/dispense2.git] / virtualvend / vvend.py
1 #!/usr/bin/env python
2
3 import sys
4 import socket
5 import string
6
7 try:
8   import pygtk
9   #tell pyGTK, if possible, that we want GTKv2
10   pygtk.require("2.0")
11 except:
12   #Some distributions come with GTK2, but not pyGTK
13   pass
14
15 try:
16   import gtk
17   import gtk.glade
18 except:
19   print "You need to install pyGTK or GTKv2 ",
20   print "or set your PYTHONPATH correctly."
21   print "try: export PYTHONPATH=",
22   print "/usr/local/lib/python2.2/site-packages/"
23   sys.exit(1)
24
25 import pango
26
27 #now we have both gtk and gtk.glade imported
28 #Also, we know we are running GTK v2
29
30 class appgui:
31   def __init__(self):
32     """
33     In this init we are going to display the main
34     serverinfo window
35     """
36     gladefile="vvend.glade"
37     windowname="vvend"
38     self.wTree=gtk.glade.XML (gladefile,windowname)
39     # we only have two callbacks to register, but
40     # you could register any number, or use a
41     # special class that automatically
42     # registers all callbacks. If you wanted to pass
43     # an argument, you would use a tuple like this:
44     # dic = { "on button1_clicked" : 
45     #         (self.button1_clicked, arg1,arg2) , ...
46     
47     dic = { 
48         "on_button1_clicked" : self.keypad_clicked,
49         "on_button2_clicked" : self.keypad_clicked,
50         "on_button3_clicked" : self.keypad_clicked,
51         "on_button4_clicked" : self.keypad_clicked,
52         "on_button5_clicked" : self.keypad_clicked,
53         "on_button6_clicked" : self.keypad_clicked,
54         "on_button7_clicked" : self.keypad_clicked,
55         "on_button8_clicked" : self.keypad_clicked,
56         "on_button9_clicked" : self.keypad_clicked,
57         "on_button10_clicked" : self.keypad_clicked,
58         "on_button11_clicked" : self.keypad_clicked,
59         "on_button11_clicked" : self.keypad_clicked,
60         "on_door_toggled" : self.door_changed,
61         "on_vvend_destroy_event" : self.quit,
62         "on_vvend_delete_event" : self.quit }
63     self.wTree.signal_autoconnect (dic)
64     display = self.wTree.get_widget("label1")
65     label_font = pango.FontDescription('monospace 28')
66     display.modify_font(label_font)
67
68     label_style = display.get_style().copy()
69     fg_color = display.get_colormap().alloc_color('lightgreen')
70     label_style.fg[gtk.STATE_NORMAL] = fg_color
71     display.set_style(label_style)
72
73     w = self.wTree.get_widget("eventbox1")
74     wstyle = w.get_style().copy()
75     bg_color = w.get_colormap().alloc_color('black')
76     wstyle.bg[gtk.STATE_NORMAL] = bg_color
77     w.set_style(wstyle)
78
79     display.set_text("*5N4CK0RZ*")
80
81     # vending machine password set here
82     self.vendpw = "AAAAAAAAAAAAAAAA"
83
84     self.messageid = None
85
86     #s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
87     #s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1)
88 #
89 #    listenhost=""
90 #    listenport=5150
91 #    s.bind((listenhost, listenport))
92 #    # only one connection
93 #    s.listen(1)
94 #    s.setblocking(1)
95 #    #GDK->gtk.gdk in GTK V 2.0
96 #    id=gtk.input_add(s, gtk.gdk.INPUT_READ, self.handleNewConnection)
97
98     self.server()
99
100
101     return
102
103     def __del__(self):
104         try:
105             self.sock.close()
106             self.sock.shutdown()
107         except:
108             pass
109
110 #####CALLBACKS
111   def keypad_clicked(self,widget):
112     key = widget.get_label()
113     if key == 'RESET':
114         key = '11'
115     else:
116         key = '0'+key
117     self.do_send('2'+key+' keypress\n')
118
119   def door_changed(self, widget):
120     print 'Door changed to', widget.pressed()
121     pass
122
123   def handleNewConnection(self,source,condition):
124     #source is a socket in GTK v 1 and a fd in version 2
125     conn, addr = source.accept()
126     sys.stdout.write(conn.recv(1))
127     conn.send("bing\n")
128     return gtk.TRUE
129
130 # from http://www.pythonbrasil.com.br/moin.cgi/MonitorandoSocketsComPygtk
131
132
133   def send(self, data=None, widget=None):
134      text = self.entry.get_text()
135      self.do_send(text)
136      self.entry.set_text('')
137
138      #
139
140   def do_send(self, data):
141
142      # envia ''data'' para todos os clientes conectados
143
144      for addr, (conn, tag) in self.clients.iteritems():
145             conn.send(data)
146
147   def server(self):
148
149      # inicializa o servidor
150      port = 5150
151
152      self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
153      self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
154      self.sock.bind(('localhost', port))
155      self.sock.listen(0)
156      print "listening on ", port
157
158      # 
159      #
160
161      self.server_tag = gtk.input_add(self.sock, gtk.gdk.INPUT_READ, self.accept)
162
163      # mantemos uma lista dos clientes conectados
164
165      self.clients = {}
166
167   def accept(self, source, condition):
168
169      #
170      # esperando para ser aceito
171
172      conn, addr = source.accept()
173      self.insert("%s:%s conectado\n" % addr)
174
175      # insere o cliente na lista e registra o método self.write como 
176      # callback para quando existirem dados esperando para serem lidos
177
178      self.do_prompt()
179      self.clients[addr] = (conn, gtk.input_add(conn, gtk.gdk.INPUT_READ, self.write))
180
181   def write(self, source, condition):
182
183      # método chamado quando um cliente envia dados 
184
185      data = source.recv(1024)
186      if data.strip() == 'bye' or not len(data):
187
188             # se o cliente enviar um ''bye'', desconecte-o :)
189
190             source.close()
191             for addr, (conn, tag) in self.clients.iteritems():
192                 if source is conn:
193                     gtk.input_remove(tag)
194                     self.insert('%s:%s desconectado\n' % addr)
195                     del self.clients[addr]
196                     
197                     self.server_tag = gtk.input_add(self.sock, gtk.gdk.INPUT_READ, self.accept)
198                     break
199      elif data.strip() == 'quit':
200         self.quit()
201      else:
202             for (addr, port), (conn, tag) in self.clients.iteritems():
203                 if source is conn:
204                     self.insert('%s:%s >>> %s\n'%(addr, port, data.strip()))
205                     self.handle_command(data.strip())
206                     break
207      
208      return gtk.TRUE
209
210   def insert(self, data):
211      statusbar = self.wTree.get_widget("statusbar1")
212      if self.messageid:
213         statusbar.remove(1, self.messageid)
214      self.messageid=statusbar.push(1,data)
215
216   def quit(self, *args):
217      sys.stdout.write("quiting...\n")
218      gtk.input_remove(self.server_tag)
219      for addr, (conn, tag) in self.clients.iteritems():
220             gtk.input_remove(tag)
221             conn.close()
222      self.sock.close()
223
224      gtk.mainquit()
225      sys.stdout.write("quit!\n")
226
227   def do_prompt(self):
228     self.do_send("# ")
229
230   def do_help(self):
231     help = """
232
233 Valid commands are:
234  ABOUT         ROM information
235  B[S][nn]      beep [synchronously] for a duration nn (optional)
236  C[S][nn]      silence [synchronously] for a duration nn (optional)
237  Dxxxxxxxxxx   show a message on the display
238  ECHO {ON|OFF} turn echo on or off
239  GETROM        download the ROM source code using xmodem
240  H[...]        this help screen
241 *JUMPxxxx      jumps to a subroutine at location xxxx
242 *PEEKxxxx      returns the value of the byte at location xxxx
243 *POKExxxxyy    sets the value of location xxxx to yy
244  PING          pongs
245  S[...]        query all internal switch states
246 +Vnn           vend an item
247 +VALL          vend all items
248 *Wxxxxxxxxxxxx set a new password for authenticated vends. xxx=16 chars
249                password will be converted to uppercase
250
251 Very few functions are available when the machine is in standalone 
252 mode (DIP SW 1 is set)
253 + denotes that this item requires authentication if DIP SW 2 is set
254 * denotes that DIP SW 3 must be set to use these
255 Commands starting with # are ignored (comments)
256 """
257     self.do_send(help)
258   
259   def do_about(self):
260     about = """
261
262 The Virtual Vending Machine Company
263
264 Mark Tearle, June 2004
265 """
266     self.do_send(about)
267
268   def do_vend_all(self):
269      for i in range(11,99):
270         self.do_send("101 Vending "+str(i)+"\n")
271         self.do_send("153 Home sensors failing\n")
272      self.do_send("102 Vend all motors complete\n")
273   
274   def do_vend(self,command):
275      fail = None
276      if fail:
277         self.do_send("153 Home sensors failing\n")
278      else:
279         self.insert("Vending "+command)
280         self.do_send("100 Vend successful\n")
281     
282   def do_display(self,string):
283      display = self.wTree.get_widget("label1")
284      display.set_text("%-10.10s" % (string))
285      self.do_send('300 Written\n')
286
287   def do_beep(self,command):
288      sys.stdout.write("\a")
289      self.do_send('500 Beeped\n')
290
291   def do_silence(self,command):
292      pass
293
294   def do_switches(self):
295      self.do_send("600 3F 3F\n")
296
297   def do_pong(self):
298      self.do_send("000 PONG!\n")
299
300   def handle_command(self, command):
301      command = string.upper(command)
302      print command
303      if string.find(command, "HELP",0) == 0:
304         self.do_help()
305      elif string.find(command, "ABOUT",0) == 0:
306         self.do_about()
307      elif string.find(command, "PING",0) == 0:
308         self.do_pong()
309      elif string.find(command, "VALL",0) == 0:
310         self.do_vend_all()
311      elif string.find(command, "V",0) == 0:
312         self.do_vend(command)
313      elif string.find(command, "B",0) == 0:
314         self.do_beep(command)
315      elif string.find(command, "C",0) == 0:
316         self.do_silence(command)
317      elif string.find(command, "S",0) == 0:
318         self.do_switches()
319      elif string.find(command, "D",0) == 0:
320         self.do_display(command[1:])
321      self.do_prompt()
322         
323
324 # we start the app like this...
325 app=appgui()
326 gtk.mainloop()
327
328
329 # notes
330 # http://www.async.com.br/faq/pygtk/index.py?req=show&file=faq20.011.htp

UCC git Repository :: git.ucc.asn.au