Adjusts the great pinscape controller to work with a cheap linear potentiometer instead of the expensive CCD array

Dependencies:   USBDevice mbed

Fork of Pinscape_Controller by Mike R

Files at this revision

API Documentation at this revision

Comitter:
mjr
Date:
Fri Jul 11 03:26:11 2014 +0000
Child:
1:d913e0afb2ac
Commit message:
Initial testing setup, before starting on real configuration

Changed in this revision

MMA8451Q.lib Show annotated file Show diff for this revision Revisions of this file
USBDevice.lib Show annotated file Show diff for this revision Revisions of this file
USBJoystick.cpp Show annotated file Show diff for this revision Revisions of this file
USBJoystick.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
tls1410r.cpp Show annotated file Show diff for this revision Revisions of this file
tls1410r.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/MMA8451Q.lib	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/emilmont/code/MMA8451Q/#c4d879a39775
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBDevice.lib	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/USBDevice/#0c6524151939
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBJoystick.cpp	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,143 @@
+/* Copyright (c) 2010-2011 mbed.org, MIT License
+* Modified Mouse code for Joystick - WH 2012
+*
+* Permission is hereby granted, free of charge, to any person obtaining a copy of this software
+* and associated documentation files (the "Software"), to deal in the Software without
+* restriction, including without limitation the rights to use, copy, modify, merge, publish,
+* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the
+* Software is furnished to do so, subject to the following conditions:
+*
+* The above copyright notice and this permission notice shall be included in all copies or
+* substantial portions of the Software.
+*
+* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
+* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+ 
+#include "stdint.h"
+#include "USBJoystick.h"
+ 
+bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint16_t buttons) 
+{
+   _x = x;
+   _y = y;
+   _z = z;
+   _buttons = buttons;     
+ 
+   // send the report
+   return update();
+}
+ 
+bool USBJoystick::update() {
+   HID_REPORT report;
+ 
+   // Fill the report according to the Joystick Descriptor
+   report.data[0] = _buttons & 0xff;
+   report.data[1] = (_buttons >> 8) & 0xff;
+   report.data[2] = _x & 0xff;            
+   report.data[3] = _y & 0xff;            
+   report.data[4] = _z & 0xff;
+   report.length = 5; 
+ 
+   return send(&report);
+}
+ 
+bool USBJoystick::move(int16_t x, int16_t y) {
+     _x = x;
+     _y = y;
+     return update();
+}
+
+bool USBJoystick::setZ(int16_t z) {
+    _z = z;
+    return update();
+}
+ 
+bool USBJoystick::buttons(uint16_t buttons) {
+     _buttons = buttons;
+     return update();
+}
+ 
+ 
+void USBJoystick::_init() {
+ 
+   _x = 0;                       
+   _y = 0;     
+   _z = 0;
+   _buttons = 0x0000;
+}
+ 
+ 
+uint8_t * USBJoystick::reportDesc() 
+{    
+    static uint8_t reportDescriptor[] = 
+    {         
+         USAGE_PAGE(1), 0x01,            // Generic desktop
+         USAGE(1), 0x04,                 // Joystick
+
+         COLLECTION(1), 0x01,            // Application
+      //     COLLECTION(1), 0x00,          // Physical
+           
+             USAGE_PAGE(1), 0x09,        // Buttons
+             USAGE_MINIMUM(1), 0x01,     // { buttons }
+             USAGE_MAXIMUM(1), 0x10,     // {  1-16   }
+             LOGICAL_MINIMUM(1), 0x00,   // 1-bit buttons - 0...
+             LOGICAL_MAXIMUM(1), 0x01,   // ...to 1
+             REPORT_SIZE(1), 0x01,       // 1 bit per report
+             REPORT_COUNT(1), 0x10,      // 16 reports
+             UNIT_EXPONENT(1), 0x00,     // Unit_Exponent (0)
+             UNIT(1), 0x00,              // Unit (None)                                           
+             INPUT(1), 0x02,             // Data, Variable, Absolute
+           
+             USAGE_PAGE(1), 0x01,        // Generic desktop
+             USAGE(1), 0x30,             // X
+             USAGE(1), 0x31,             // Y
+             USAGE(1), 0x32,             // Z
+             LOGICAL_MINIMUM(1), 0x81,   // each value ranges -127...
+             LOGICAL_MAXIMUM(1), 0x7f,   // ...to 127
+             REPORT_SIZE(1), 0x08,       // 8 bits per report
+             REPORT_COUNT(1), 0x03,      // 3 reports
+             INPUT(1), 0x02,             // Data, Variable, Absolute
+        
+             REPORT_COUNT(1), 0x08,      // input report count (LEDWiz messages)
+             0x09, 0x01,                 // usage
+             0x91, 0x01,                 // Output (array)
+
+     //      END_COLLECTION(0),
+         END_COLLECTION(0)
+      };
+ 
+      reportLength = sizeof(reportDescriptor);
+      return reportDescriptor;
+}
+ 
+ uint8_t * USBJoystick::stringImanufacturerDesc() {
+    static uint8_t stringImanufacturerDescriptor[] = {
+        0x10,                                            /*bLength*/
+        STRING_DESCRIPTOR,                               /*bDescriptorType 0x03*/
+        'm',0,'j',0,'r',0,'c',0,'o',0,'r',0,'p',0        /*bString iManufacturer - mjrcorp*/
+    };
+    return stringImanufacturerDescriptor;
+}
+
+uint8_t * USBJoystick::stringIserialDesc() {
+    static uint8_t stringIserialDescriptor[] = {
+        0x16,                                                           /*bLength*/
+        STRING_DESCRIPTOR,                                              /*bDescriptorType 0x03*/
+        '0',0,'1',0,'2',0,'3',0,'4',0,'5',0,'6',0,'7',0,'8',0,'9',0,    /*bString iSerial - 0123456789*/
+    };
+    return stringIserialDescriptor;
+}
+
+uint8_t * USBJoystick::stringIproductDesc() {
+    static uint8_t stringIproductDescriptor[] = {
+        0x1E,                                                       /*bLength*/
+        STRING_DESCRIPTOR,                                          /*bDescriptorType 0x03*/
+        'P',0,'i',0,'n',0,'M',0,'a',0,'s',0,'t',0,'e',0,'r',0,
+        ' ',0,'2',0,'0',0,'0',0,'0',0                               /*String iProduct - PinMaster 2000*/
+    };
+    return stringIproductDescriptor;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/USBJoystick.h	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,163 @@
+/* USBJoystick.h */
+/* USB device example: Joystick*/
+/* Copyright (c) 2011 ARM Limited. All rights reserved. */
+/* Modified Mouse code for Joystick - WH 2012 */
+ 
+#ifndef USBJOYSTICK_H
+#define USBJOYSTICK_H
+ 
+#include "USBHID.h"
+ 
+#define REPORT_ID_JOYSTICK  4
+ 
+/* Common usage */
+enum JOY_BUTTON {
+     JOY_B0 = 0x0001,
+     JOY_B1 = 0x0002,
+     JOY_B2 = 0x0004,
+     JOY_B3 = 0x0008,
+     JOY_B4 = 0x0010,
+     JOY_B5 = 0x0020,
+     JOY_B6 = 0x0040,
+     JOY_B7 = 0x0080,
+     JOY_B8 = 0x0100,
+     JOY_B9 = 0x0200,
+     JOY_B10 = 0x0400,
+     JOY_B11 = 0x0800,
+     JOY_B12 = 0x1000,
+     JOY_B13 = 0x2000,
+     JOY_B14 = 0x4000,
+     JOY_B15 = 0x8000
+};
+ 
+/* X, Y and T limits */
+/* These values do not directly map to screen pixels */
+/* Zero may be interpreted as meaning 'no movement' */
+#define JX_MIN_ABS    (-127)     /*!< The maximum value that we can move to the left on the x-axis */
+#define JY_MIN_ABS    (-127)     /*!< The maximum value that we can move up on the y-axis */
+#define JZ_MIN_ABS    (-127)     /*!< The minimum value for the Z axis */
+#define JX_MAX_ABS    (127)      /*!< The maximum value that we can move to the right on the x-axis */
+#define JY_MAX_ABS    (127)      /*!< The maximum value that we can move down on the y-axis */
+#define JZ_MAX_ABS    (127)      /*!< The maximum value for the Z axis */
+ 
+/**
+ *
+ * USBJoystick example
+ * @code
+ * #include "mbed.h"
+ * #include "USBJoystick.h"
+ *
+ * USBJoystick joystick;
+ *
+ * int main(void)
+ * {
+ *   while (1)
+ *   {
+ *      joystick.move(20, 0);
+ *      wait(0.5);
+ *   }
+ * }
+ *
+ * @endcode
+ *
+ *
+ * @code
+ * #include "mbed.h"
+ * #include "USBJoystick.h"
+ * #include <math.h>
+ *
+ * USBJoystick joystick;
+ *
+ * int main(void)
+ * {   
+ *   while (1) {
+ *       // Basic Joystick
+ *       joystick.update(tx, y, z, buttonBits);
+ *       wait(0.001);
+ *   }
+ * }
+ * @endcode
+ */
+ 
+ 
+class USBJoystick: public USBHID {
+   public:
+ 
+        /**
+         *   Constructor
+         *
+         * @param vendor_id Your vendor_id (default: 0x1234)
+         * @param product_id Your product_id (default: 0x0002)
+         * @param product_release Your product_release (default: 0x0001)
+         */
+         USBJoystick(uint16_t vendor_id = 0x1234, uint16_t product_id = 0x0100, uint16_t product_release = 0x0001): 
+             USBHID(8, 8, vendor_id, product_id, product_release, false)
+             { 
+                 _init();
+                 connect();
+             };
+         
+         /**
+         * Write a state of the mouse
+         *
+         * @param x x-axis position
+         * @param y y-axis position
+         * @param z z-axis position
+         * @param buttons buttons state, as a bit mask (combination with '|' of JOY_Bn values)
+         * @returns true if there is no error, false otherwise
+         */
+         bool update(int16_t x, int16_t y, int16_t z, uint16_t buttons);
+ 
+         /**
+         * Write a state of the mouse
+         *
+         * @returns true if there is no error, false otherwise
+         */
+         bool update();
+ 
+         /**
+         * Move the cursor to (x, y)
+         *
+         * @param x x-axis position
+         * @param y y-axis position
+         * @returns true if there is no error, false otherwise
+         */
+         bool move(int16_t x, int16_t y);
+         
+         /**
+         * Set the z position
+         *
+         * @param z z-axis osition
+         */
+         bool setZ(int16_t z);
+         
+         /**
+         * Press one or several buttons
+         *
+         * @param buttons button state, as a bitwise combination of JOY_Bn values
+         * @returns true if there is no error, false otherwise
+         */
+         bool buttons(uint16_t buttons);
+         
+         /*
+         * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength.
+         *
+         * @returns pointer to the report descriptor
+         */
+         virtual uint8_t * reportDesc();
+ 
+         /* USB descriptor string overrides */
+         virtual uint8_t *stringImanufacturerDesc();
+         virtual uint8_t *stringIserialDesc();
+         virtual uint8_t *stringIproductDesc();
+ 
+     private:
+         int8_t _x;                       
+         int8_t _y;     
+         int8_t _z;
+         uint16_t _buttons;
+         
+         void _init();                 
+};
+ 
+#endif
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,188 @@
+#include "mbed.h"
+#include "USBJoystick.h"
+#include "MMA8451Q.h"
+#include "tls1410r.h"
+
+PwmOut led1(LED1), led2(LED2), led3(LED3);
+DigitalOut out1(PTE29);
+
+
+
+static int pbaIdx = 0;
+
+// on/off state for each LedWiz output
+static uint8_t ledOn[32];
+
+// profile (brightness/blink) state for each LedWiz output
+static uint8_t ledVal[32] = {
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0,
+    0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static double ledState(int idx)
+{
+    if (ledOn[idx]) {
+        // on - map profile brightness state to PWM level
+        uint8_t val = ledVal[idx];
+        if (val >= 1 && val <= 48)
+            return 1.0 - val/48.0;
+        else if (val >= 129 && val <= 132)
+            return 0.0;
+        else
+            return 1.0;
+    }
+    else {
+        // off
+        return 1.0;
+    }
+}
+
+static void updateLeds()
+{
+    led1 = ledState(0);
+    led2 = ledState(1);
+    led3 = ledState(2);
+}
+
+int main(void)
+{
+    led1 = 1;
+    led2 = 1;
+    led3 = 1;
+    Timer timer;
+
+    // set up a timer for spacing USB reports   
+    timer.start();
+    float t0 = timer.read_ms();    
+    float tout1 = timer.read_ms();
+
+    // Create the joystick USB client.  Show a read LED while connecting, and
+    // change to green when connected.
+    led1 = 0.75;
+    USBJoystick js(0xFAFA, 0x00F7, 0x0001);
+    led1 = 1;
+    led2 = 0.75;
+    
+    // create the accelerometer object
+    const int MMA8451_I2C_ADDRESS = (0x1d<<1);
+    MMA8451Q accel(PTE25, PTE24, MMA8451_I2C_ADDRESS);
+    printf("MMA8451 ID: %d\r\n", accel.getWhoAmI());
+    
+    // create the CCD array object
+    TLS1410R ccd(PTE20, PTE21, PTB0);
+
+    // process sensor reports and LedWiz requests forever
+    int x = 0, y = 127, z = 0;
+    for (;;)
+    {
+        // Look for an incoming report.  Continue processing input as
+        // long as there's anything pending - this ensures that we
+        // handle input in as timely a fashion as possible by deferring
+        // output tasks as long as there's input to process.
+        HID_REPORT report;
+        while (js.readNB(&report) && report.length == 8)
+        {
+            uint8_t *data = report.data;
+            if (data[0] == 64) {
+                // LWZ-SBA - first four bytes are bit-packed on/off flags
+                // for the outputs; 5th byte is the pulse speed (0-7)
+                //printf("LWZ-SBA %02x %02x %02x %02x ; %02x\r\n",
+                //       data[1], data[2], data[3], data[4], data[5]);
+
+                // update all on/off states
+                for (int i = 0, bit = 1, ri = 1 ; i < 32 ; ++i, bit <<= 1)
+                {
+                    if (bit == 0x100) {
+                        bit = 1;
+                        ++ri;
+                    }
+                    ledOn[i] = ((data[ri] & bit) != 0);
+                }
+    
+                // update the physical LED state
+                updateLeds();
+                
+                // reset the PBA counter
+                pbaIdx = 0;
+            }
+            else {
+                // LWZ-PBA - full state dump; each byte is one output
+                // in the current bank.  pbaIdx keeps track of the bank;
+                // this is incremented implicitly by each PBA message.
+                //printf("LWZ-PBA[%d] %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
+                //       pbaIdx, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
+
+                // update all output profile settings
+                for (int i = 0 ; i < 8 ; ++i)
+                    ledVal[pbaIdx + i] = data[i];
+
+                // update the physical LED state if this is the last bank                    
+                if (pbaIdx == 24)
+                    updateLeds();
+
+                // advance to the next bank
+                pbaIdx = (pbaIdx + 8) & 31;
+            }
+        }
+        
+#if 1
+        // check the accelerometer
+        {
+            // read the accelerometer
+            float xa = accel.getAccX();
+            float ya = accel.getAccY();
+            
+            // figure the new joystick position
+            int xnew = (int)(127 * xa);
+            int ynew = (int)(127 * ya);
+            
+            // send an update if the position has changed
+            if (xnew != x || ynew != y)
+            {
+                x = xnew;
+                y = ynew;
+
+                // send the status report
+                js.update(x, y, z, 0);
+            }
+        }
+#else
+        // Send a joystick report if it's been long enough since the
+        // last report        
+        if (timer.read_ms() - t0 > 250)
+        {
+            // send the current joystick status report
+            js.update(x, y, z, 0);
+
+            // update our internal joystick position record
+            x += dx;
+            y += dy;
+            z += dz;
+            if (x > xmax || x < xmin) {
+                dx = -dx;
+                x += 2*dx;
+            }
+            if (y > ymax || y < ymin) {
+                dy = -dy;
+                y += 2*dy;
+            }
+            if (z > zmax || z < zmin) {
+                dz = -dz;
+                z += 2*dz;
+            }
+
+            // note the time of the last report
+            t0 = timer.read_ms();
+        }            
+#endif
+
+        // pulse E29
+        if (timer.read_ms() - tout1 > 2000)
+        {
+            out1 = !out1;
+            tout1 = timer.read_ms();
+        }
+    }    
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/04dd9b1680ae
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tls1410r.cpp	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,74 @@
+#include "mbed.h"
+#include "tls1410r.h"
+
+TLS1410R::TLS1410R(PinName siPort, PinName clockPort, PinName aoPort)
+    : si(siPort), clock(clockPort), ao(aoPort)
+{
+    // clear out power-on noise by clocking through all pixels twice
+    clear();
+    clear();
+}
+
+void TLS1410R::clear()
+{
+    // clock in an SI pulse
+    si = 1;
+    clock = 1;
+    clock = 0;
+    si = 0;
+    
+    // clock out all pixels
+    for (int i = 0 ; i < nPix+1 ; ++i) {
+        clock = 1;
+        clock = 0;
+    }
+}
+
+void TLS1410R::read(uint16_t *pix, int n, int integrate_us)
+{
+    // Start an integration cycle - pulse SI, then clock all pixels.  The
+    // CCD will integrate light starting 18 clocks after the SI pulse, and
+    // continues integrating until the next SI pulse, which cannot occur
+    // until all pixels have been clocked.
+    si = 1;
+    clock = 1;
+    clock = 0;
+    si = 0;
+    for (int i = 0 ; i < nPix+1 ; ++i) {
+        clock = 1;
+        clock = 0;
+    }
+        
+    // delay by the specified additional integration time
+    wait_us(integrate_us);
+    
+    // end the current integration cycle and hold the integrated values
+    si = 1;
+    clock = 1;
+    clock = 0;
+    si = 0;
+    
+    // figure how many pixels to skip on each read
+    int skip = nPix/n - 1;
+
+    // read the pixels
+    for (int src = 0, dst = 0 ; src < nPix ; ++src)
+    {
+        // read this pixel
+        pix[dst++] = ao;
+        
+        // clock in the next pixel
+        clock = 1;
+        clock = 0;
+        
+        // clock skipped pixels
+        for (int i = 0 ; i < skip ; ++i) {
+            clock = 1;
+            clock = 0;
+        }
+    }
+    
+    // clock out one extra pixel to make sure the device is ready for another go
+    clock = 1;
+    clock = 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tls1410r.h	Fri Jul 11 03:26:11 2014 +0000
@@ -0,0 +1,41 @@
+/*
+ *  TLS1410R interface class.
+ *
+ *  This provides a high-level interface for the Taos TLS1410R linear CCD array sensor.
+ */
+ 
+ #include "mbed.h"
+ 
+ #ifndef TLS1410R_H
+ #define TLS1410R_H
+ 
+class TLS1410R
+{
+public:
+    // set up with the two DigitalOut ports (SI and clock), and the
+    // analog in port for reading the currently selected pixel value
+    TLS1410R(PinName siPort, PinName clockPort, PinName aoPort);
+
+    // Integrate light and read the pixels.  Fills in pix[] with the pixel values,
+    // scaled 0-0xffff.  n is the number of pixels to read; if this is less than
+    // the total number of pixels npix, we'll read every mth pixel, where m = npix/n.
+    // E.g., if you want 640 pixels out of 1280 on the sensor, we'll read every
+    // other pixel.  If you want 320, we'll read every fourth pixel.
+    // Before reading, we'll pause for integrate_us additional microseconds during
+    // the integration phase; use 0 for no additional integration time. 
+    void read(uint16_t *pix, int n, int integrate_us);
+
+    // clock through all pixels to clear the array
+    void clear();
+
+    // number of pixels in the array
+    static const int nPix = 1280;
+    
+    
+private:
+    DigitalOut si;
+    DigitalOut clock;
+    AnalogIn ao;
+};
+ 
+#endif /* TLS1410R_H */