changeset 828:a422d875d94d

barcode support on star. triggers mpd song Ignore-this: 1038c3d0501bba595fbf701e30acac6 darcs-hash:20120304114228-312f9-8fc9a9198be2044359f35aebcd1c428a58cb4ea2.gz
author drewp <drewp@bigasterisk.com>
date Sun, 04 Mar 2012 03:42:28 -0800
parents f97547561b1d
children 772b2065fca8
files service/starArduino/barcodePlayer.py service/starArduino/star/star.pde service/starArduino/starArduino.py
diffstat 3 files changed, 355 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/starArduino/barcodePlayer.py	Sun Mar 04 03:42:28 2012 -0800
@@ -0,0 +1,42 @@
+#!bin/python
+"""
+receives POSTs about barcodes that are scanned, plays songs on mpd
+"""
+
+from __future__ import division
+
+import cyclone.web, cyclone.httpclient, sys, json
+from twisted.python import log
+from twisted.internet import reactor
+from twisted.internet.defer import inlineCallbacks
+sys.path.append("/my/proj/homeauto/lib")
+from cycloneerr import PrettyErrorHandler
+
+
+
+class Index(PrettyErrorHandler, cyclone.web.RequestHandler):
+    def get(self):
+        
+        self.set_header("Content-Type", "application/xhtml+xml")
+        self.write(open("index.html").read())
+
+class BarcodeScan(PrettyErrorHandler, cyclone.web.RequestHandler):
+    @inlineCallbacks
+    def post(self):
+        print json.loads(self.request.body)
+
+        song = "cd/Kindermusik-The_Best_of_the_Best/14.Fiddle-de-dee.ogg"
+
+        print (yield cyclone.httpclient.fetch(url="http://star:9009/addAndPlay/%s" % song, method="POST")).body
+
+        self.write("ok")
+
+
+if __name__ == '__main__':
+    app = cyclone.web.Application([
+        (r'/', Index),
+        (r'/barcodeScan', BarcodeScan),
+        ], )
+    log.startLogging(sys.stdout)
+    reactor.listenTCP(9011, app)
+    reactor.run()
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/service/starArduino/star/star.pde	Sun Mar 04 03:42:28 2012 -0800
@@ -0,0 +1,241 @@
+/*
+board is like diecimila with atmega168
+
+*/
+#include <SoftwareSerial.h>
+int datapin  = 10; // DI
+int latchpin = 11; // LI
+int enablepin = 12; // EI
+int clockpin = 13; // CI
+
+unsigned long SB_CommandPacket;
+int SB_CommandMode;
+int SB_BlueCommand;
+int SB_RedCommand;
+int SB_GreenCommand;
+
+#define MAXCHANS 16
+int vals[MAXCHANS * 3];
+
+int addr = 0; // which vals element to set next
+int currentChans = MAXCHANS;
+
+unsigned char rotation = 0; // position of knob
+unsigned char lastRotPosition = 0; // 2*A+1*B
+
+#define TEMP_ENABLED 1
+
+#if TEMP_ENABLED
+#include <OneWire.h>
+#include <DallasTemperature.h>
+
+OneWire oneWire(4); // digital IO 4
+DallasTemperature sensors(&oneWire);
+DeviceAddress tempSensorAddress;
+#endif
+
+/*
+barcode red: +5V
+barcode white: gnd
+ */
+SoftwareSerial barcode =  SoftwareSerial(/* rx pin, green */ 3, 
+					 /* tx pin, black */ 2,
+					 /* inverse */ true);
+
+void shiftOutLocal(uint8_t dataPin, uint8_t clockPin, byte val)
+{
+  int i;
+  
+  for (i = 0; i < 8; i++)  {
+    digitalWrite(dataPin, !!(val & (1 << (7 - i))));
+    
+    digitalWrite(clockPin, HIGH);
+    digitalWrite(clockPin, LOW);            
+  }
+}
+
+void SB_SendPacket() {
+   SB_CommandPacket = SB_CommandMode & B11;
+   SB_CommandPacket = (SB_CommandPacket << 10)  | (SB_BlueCommand & 1023);
+   SB_CommandPacket = (SB_CommandPacket << 10)  | (SB_RedCommand & 1023);
+   SB_CommandPacket = (SB_CommandPacket << 10)  | (SB_GreenCommand & 1023);
+
+   shiftOutLocal(datapin, clockpin, SB_CommandPacket >> 24);
+   shiftOutLocal(datapin, clockpin, SB_CommandPacket >> 16);
+   shiftOutLocal(datapin, clockpin, SB_CommandPacket >> 8);
+   shiftOutLocal(datapin, clockpin, SB_CommandPacket);
+
+}
+void latch() {
+   delayMicroseconds(100);
+   digitalWrite(latchpin,HIGH); // latch data into registers
+   delayMicroseconds(100);
+   digitalWrite(latchpin,LOW); 
+}
+void refresh() {
+  /* send all pixels */
+  SB_CommandMode = B00;
+  for (int pixel=0; pixel < currentChans; pixel++) {
+    SB_RedCommand = vals[pixel * 3 + 0];
+    SB_GreenCommand = vals[pixel * 3 + 1];
+    SB_BlueCommand = vals[pixel * 3 + 2];
+    SB_SendPacket();
+  } 
+  latch();
+}
+#define F 1023
+#define PIXEL(i, r, g, b) { vals[i*3+0] = r; vals[i*3+1] = g; vals[i*3+2] = b; }
+
+void setCurrent(unsigned char r, unsigned char g, unsigned char b) { 
+ /* 127 = max */ 
+   SB_CommandMode = B01; // Write to current control registers
+   SB_RedCommand = r; 
+   SB_GreenCommand = g;
+   SB_BlueCommand = b;
+   SB_SendPacket();
+   latch();
+}
+void setup() {
+   pinMode(datapin, OUTPUT);
+   pinMode(latchpin, OUTPUT);
+   pinMode(enablepin, OUTPUT);
+   pinMode(clockpin, OUTPUT);
+
+   digitalWrite(latchpin, LOW);
+   digitalWrite(enablepin, LOW);
+
+   for (int i=0; i < MAXCHANS; i++) {
+     setCurrent(127, 127, 127);
+   }
+
+   PIXEL(0, F, 0, 0);
+   PIXEL(1, 0, F, 0);
+   PIXEL(2, 0, 0, F);
+   PIXEL(3, F, F, 0);
+   PIXEL(4, 0, F, F);
+   refresh(); 
+
+#if TEMP_ENABLED
+   sensors.begin();
+   sensors.getAddress(tempSensorAddress, 0);
+   sensors.setResolution(tempSensorAddress, 12);
+#endif
+
+   Serial.begin(9600);
+   Serial.flush();
+
+   pinMode(5, INPUT);
+   pinMode(6, INPUT);
+   pinMode(7, INPUT);
+   pinMode(8, INPUT);
+   pinMode(9, INPUT);
+   digitalWrite(6, HIGH); 
+   digitalWrite(8, HIGH); 
+   digitalWrite(9, HIGH); 
+
+
+   barcode.begin(1200);
+   digitalWrite(2, 0); // inverse logic: don't hold this high
+
+   /*
+   barcode.write("\x1b\x42\x0d"); // blink
+   */
+   /*
+   barcode.write("\x1b\x46\x0d"); // off
+   */ 
+}
+
+void loop() {
+  /*
+    send 0xff, 
+    then a byte for the number of channels you're going to send,
+    then nchans*3 bytes of r-g-b levels from 0x00-0xfe.
+
+    second byte 0xfe means to return temp in F, followed by \n
+    second byte 0xfd means to return a line describing the state of buttons
+    second byte 0xfc means to beep the barcode scanner
+    second byte 0xfb means to fetch any recent scanned barcode
+   */
+
+  unsigned char curPos = (digitalRead(8) << 1) | digitalRead(9);
+
+  if (curPos == 0 && lastRotPosition == 2) { rotation--; }
+  if (curPos == 0 && lastRotPosition == 1) { rotation++; }
+  if (curPos == 1 && lastRotPosition == 0) { rotation--; }
+  if (curPos == 1 && lastRotPosition == 3) { rotation++; }
+  if (curPos == 3 && lastRotPosition == 1) { rotation--; }
+  if (curPos == 3 && lastRotPosition == 2) { rotation++; }
+  if (curPos == 2 && lastRotPosition == 3) { rotation--; }
+  if (curPos == 2 && lastRotPosition == 0) { rotation++; }
+
+  lastRotPosition = curPos;
+
+  int inb = Serial.read();
+  if (inb == -1) {
+    return;
+  }
+  if (inb == 0xff) {
+    addr = -1;
+    return;
+  }
+  if (addr == -1) {
+    if (inb == 0xfe) {
+#if TEMP_ENABLED
+      sensors.requestTemperatures();
+      float tempF = sensors.getTempF(tempSensorAddress);
+      Serial.print(tempF);
+      Serial.print("\n");
+#endif
+      addr = -1;
+      return;
+    }
+    if (inb == 0xfb) {
+      if (barcode.available() < 1) {
+	Serial.print("{\"barcode\":\"\"}\n");
+      } else {
+	Serial.print("{\"barcode\":\"");
+	char last=1;
+	while (barcode.available() > 0) {
+	  last = barcode.read();
+	  Serial.print((int)last);
+	  Serial.print(" ");
+	}
+	Serial.print("\"}\n");
+      } 
+      return;
+    }
+    if (inb == 0xfc) {
+      barcode.write("\x1b\x54\x0d");// beep
+      barcode.write("\x1b\x3f\x0d"); // requisition
+      Serial.print("{\"ok\":1}\n");
+    }
+
+    if (inb == 0xfd) {
+      // read ariremote buttons, where some buttons are combined on
+      // the same pins
+      digitalWrite(5, HIGH); Serial.print(digitalRead(5));  
+      Serial.print(" ");
+      digitalWrite(5, LOW);  Serial.print(!digitalRead(5)); 
+      Serial.print(" ");
+      digitalWrite(7, HIGH); Serial.print(digitalRead(7));  
+      Serial.print(" ");
+      digitalWrite(7, LOW);  Serial.print(!digitalRead(7)); 
+      Serial.print(" ");
+      Serial.print(!digitalRead(6)); 
+      Serial.print(" ");
+      Serial.print((int)rotation);
+      Serial.print("\n");
+    }
+    currentChans = inb;
+    addr = 0;
+    return; 
+  }
+  
+  vals[addr] = inb * 4; // SB levels are 10-bit. log scale might be better
+  addr ++; 
+  if (addr >= currentChans * 3) {
+    refresh();  
+    addr = 0;
+  }
+  
+}
--- a/service/starArduino/starArduino.py	Sun Mar 04 03:41:33 2012 -0800
+++ b/service/starArduino/starArduino.py	Sun Mar 04 03:42:28 2012 -0800
@@ -6,7 +6,8 @@
 
 import sys, jsonlib
 from twisted.internet import reactor, task
-import cyclone.web
+from twisted.internet.task import LoopingCall
+import cyclone.web, restkit
 
 sys.path.append("/my/proj/pixel/shiftweb")
 from drvarduino import ShiftbriteArduino
@@ -45,22 +46,91 @@
         self.set_header("Content-Type", "text/plain")
         self.write("updated %r" % colors)
     
+class Barcode(PrettyErrorHandler, cyclone.web.RequestHandler):
+    def get(self):
+        self.set_header("Content-Type", "text/plain")
+        ser = self.settings.arduino.ser
+        ser.write("\x60\x02")
+        self.write(str(ser.readJson()))
+
+class BarcodeBeep(PrettyErrorHandler, cyclone.web.RequestHandler):
+    def put(self):
+        self.set_header("Content-Type", "text/plain")
+        ser = self.settings.arduino.ser
+        ser.write("\x60\x03")
+        self.write(str(ser.readJson()))
+
+def barcodeWatch(arduino, postBarcode):
+    try:
+        arduino.ser.write("\xff\xfb")
+        ret = arduino.readJson()
+        if ret['barcode']:
+            if ret['barcode'] == "27 80 48 13 ":
+                pass # scanner's beep response
+            else:
+                arduino.ser.write("\xff\xfc")
+                arduino.readJson() # my beep response
+                s = ''.join(chr(int(x)) for x in ret['barcode'].split())
+                for code in s.split('\x02'):
+                    if not code:
+                        continue
+                    if not code.endswith('\x03'):
+                        print "couldn't read %r" % code
+                        return
+                    codeType = {'A':'UPC-A',
+                                'B':'JAN-8',
+                                'E':'UPC-E',
+                                'N':'NW-7',
+                                'C':'CODE39',
+                                'I':'ITF',
+                                'K':'CODE128',
+                                }[code[0]]
+                    code = code[1:-1]
+                    postBarcode.post(payload=jsonlib.dumps(
+                        {'barcodeType':codeType, 'code':code}),
+                                     headers={"content-type" :
+                                              "application/json"})
+
+    except ValueError, e:
+        print "err", e
+
+    
 class Graph(PrettyErrorHandler, cyclone.web.RequestHandler):    
     def get(self):
         raise NotImplementedError
     
 if __name__ == '__main__':
-    sb = ShiftbriteArduino(numChannels=3)
+    class A(ShiftbriteArduino):
+        # from loggingserial.py
+        def readJson(self):
+            line = ''
+            while True:
+                c = self.ser.read(1)
+                #print "gotchar", repr(c)
+                if c:
+                    line += c
+                    if c == "\n":
+                        break
+                else:
+                    raise ValueError("timed out waiting for chars")
+            return jsonlib.loads(line)
+
+    sb = A(numChannels=3)
 
     colors = [(0,0,0)] * sb.numChannels
 
     aw = ArduinoWatcher(sb)
     task.LoopingCall(aw.poll).start(1.0/20)
+
+    postBarcode = restkit.Resource('http://star:9011/barcodeScan')
+    task.LoopingCall(barcodeWatch, sb, postBarcode).start(interval=.5)
     
     reactor.listenTCP(9014, cyclone.web.Application([
         (r'/', Index),
         (r'/temperature', Temperature),
         (r'/brite/(\d+)', Brite),
+        (r'/barcode', Barcode),
+        (r'/barcode/beep', BarcodeBeep),
         (r'/graph', Graph),
         ], arduino=sb, colors=colors))
     reactor.run()