
Adjusts the great pinscape controller to work with a cheap linear potentiometer instead of the expensive CCD array
Fork of Pinscape_Controller by
Revision 11:bd9da7088e6e, committed 2014-08-26
- Comitter:
- mjr
- Date:
- Tue Aug 26 22:24:54 2014 +0000
- Parent:
- 10:976666ffa4ef
- Child:
- 12:669df364a565
- Commit message:
- Button inputs added
Changed in this revision
--- a/USBJoystick/USBJoystick.cpp Sat Aug 23 01:24:36 2014 +0000 +++ b/USBJoystick/USBJoystick.cpp Tue Aug 26 22:24:54 2014 +0000 @@ -20,30 +20,34 @@ #include "stdint.h" #include "USBJoystick.h" -bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint16_t buttons, uint16_t status) +bool USBJoystick::update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status) { _x = x; _y = y; _z = z; - _buttons = buttons; + _buttonsLo = (uint16_t)(buttons & 0xffff); + _buttonsHi = (uint16_t)((buttons >> 16) & 0xffff); _status = status; // send the report return update(); } -bool USBJoystick::update() { +const int reportLen = 14; +bool USBJoystick::update() +{ HID_REPORT report; - + // Fill the report according to the Joystick Descriptor #define put(idx, val) (report.data[idx] = (val) & 0xff, report.data[(idx)+1] = ((val) >> 8) & 0xff) put(0, _status); put(2, 0); // second byte of status isn't used in normal reports - put(4, _buttons); - put(6, _x); - put(8, _y); - put(10, _z); - report.length = 12; + put(4, _buttonsLo); + put(6, _buttonsHi); + put(8, _x); + put(10, _y); + put(12, _z); + report.length = reportLen; // send the report return sendTO(&report, 100); @@ -60,7 +64,7 @@ put(0, s); // now fill out the remaining words with exposure values - report.length = 12; + report.length = reportLen; for (int ofs = 2 ; ofs + 1 < report.length ; ofs += 2) { uint16_t p = (idx < npix ? pix[idx++] : 0); @@ -82,8 +86,9 @@ return update(); } -bool USBJoystick::buttons(uint16_t buttons) { - _buttons = buttons; +bool USBJoystick::buttons(uint32_t buttons) { + _buttonsLo = (uint16_t)(buttons & 0xffff); + _buttonsHi = (uint16_t)((buttons >> 16) & 0xffff); return update(); } @@ -93,7 +98,8 @@ _x = 0; _y = 0; _z = 0; - _buttons = 0x0000; + _buttonsLo = 0x0000; + _buttonsHi = 0x0000; _status = 0; } @@ -140,11 +146,11 @@ USAGE_PAGE(1), 0x09, // Buttons USAGE_MINIMUM(1), 0x01, // { buttons } - USAGE_MAXIMUM(1), 0x10, // { 1-16 } + USAGE_MAXIMUM(1), 0x20, // { 1-32 } 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 + REPORT_COUNT(1), 0x20, // 32 reports UNIT_EXPONENT(1), 0x00, // Unit_Exponent (0) UNIT(1), 0x00, // Unit (None) INPUT(1), 0x02, // Data, Variable, Absolute
--- a/USBJoystick/USBJoystick.h Sat Aug 23 01:24:36 2014 +0000 +++ b/USBJoystick/USBJoystick.h Tue Aug 26 22:24:54 2014 +0000 @@ -106,7 +106,7 @@ * @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, uint16_t status); + bool update(int16_t x, int16_t y, int16_t z, uint32_t buttons, uint16_t status); /** * Write an exposure report. We'll fill out a report with as many pixels as @@ -149,7 +149,7 @@ * @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); + bool buttons(uint32_t buttons); /* * To define the report descriptor. Warning: this method has to store the length of the report descriptor in reportLength. @@ -167,7 +167,8 @@ int16_t _x; int16_t _y; int16_t _z; - uint16_t _buttons; + uint16_t _buttonsLo; + uint16_t _buttonsHi; uint16_t _status; void _init();
--- a/main.cpp Sat Aug 23 01:24:36 2014 +0000 +++ b/main.cpp Tue Aug 26 22:24:54 2014 +0000 @@ -277,11 +277,70 @@ DigitalIn calBtn(PTE29); DigitalOut calBtnLed(PTE23); -// LED-Wiz emulation output pin assignments. The LED-Wiz protocol -// can support up to 32 outputs. The KL25Z can physically provide -// about 48 (in addition to the ports we're already using for the -// CCD sensor and the calibration button), but to stay compatible -// with the LED-Wiz protocol we'll stop at 32. +// Joystick button input pin assignments. You can wire up to +// 32 GPIO ports to buttons (equipped with momentary switches). +// Connect each switch between the desired GPIO port and ground +// (J9 pin 12 or 14). When the button is pressed, we'll tell the +// host PC that the corresponding joystick button as pressed. We +// debounce the keystrokes in software, so you can simply wire +// directly to pushbuttons with no additional external hardware. +// +// Note that we assign 24 buttons by default, even though the USB +// joystick interface can handle up to 32 buttons. VP itself only +// allows mapping of up to 24 buttons in the preferences dialog +// (although it can recognize 32 buttons internally). If you want +// more buttons, you can reassign pins that are assigned by default +// as LedWiz outputs. To reassign a pin, find the pin you wish to +// reassign in the LedWizPortMap array below, and change the pin name +// there to NC (for Not Connected). You can then change one of the +// "NC" entries below to the reallocated pin name. The limit is 32 +// buttons total. +// +// Note: PTD1 (pin J2-12) should NOT be assigned as a button input, +// as this pin is physically connected on the KL25Z to the on-board +// indicator LED's blue segment. This precludes any other use of +// the pin. +PinName buttonMap[] = { + PTC2, // J10 pin 10, joystick button 1 + PTB3, // J10 pin 8, joystick button 2 + PTB2, // J10 pin 6, joystick button 3 + PTB1, // J10 pin 4, joystick button 4 + + PTE30, // J10 pin 11, joystick button 5 + PTE22, // J10 pin 5, joystick button 6 + + PTE5, // J9 pin 15, joystick button 7 + PTE4, // J9 pin 13, joystick button 8 + PTE3, // J9 pin 11, joystick button 9 + PTE2, // J9 pin 9, joystick button 10 + PTB11, // J9 pin 7, joystick button 11 + PTB10, // J9 pin 5, joystick button 12 + PTB9, // J9 pin 3, joystick button 13 + PTB8, // J9 pin 1, joystick button 14 + + PTC12, // J2 pin 1, joystick button 15 + PTC13, // J2 pin 3, joystick button 16 + PTC16, // J2 pin 5, joystick button 17 + PTC17, // J2 pin 7, joystick button 18 + PTA16, // J2 pin 9, joystick button 19 + PTA17, // J2 pin 11, joystick button 20 + PTE31, // J2 pin 13, joystick button 21 + PTD6, // J2 pin 17, joystick button 22 + PTD7, // J2 pin 19, joystick button 23 + + PTE1, // J2 pin 20, joystick button 24 + + NC, // not used, joystick button 25 + NC, // not used, joystick button 26 + NC, // not used, joystick button 27 + NC, // not used, joystick button 28 + NC, // not used, joystick button 29 + NC, // not used, joystick button 30 + NC, // not used, joystick button 31 + NC // not used, joystick button 32 +}; + +// LED-Wiz emulation output pin assignments. // // The LED-Wiz protocol allows setting individual intensity levels // on all outputs, with 48 levels of intensity. This can be used @@ -294,6 +353,15 @@ // requested by the host. Use these for devices that don't have any // use for intensity settings anyway, such as contactors and knockers. // +// Ports with pins assigned as "NC" are not connected. That is, +// there's no physical pin for that LedWiz port number. You can +// send LedWiz commands to turn NC ports on and off, but doing so +// will have no effect. The reason we leave some ports unassigned +// is that we don't have enough physical GPIO pins to fill out the +// full LedWiz complement of 32 ports. Many pins are already taken +// for other purposes, such as button inputs or the plunger CCD +// interface. +// // The mapping between physical output pins on the KL25Z and the // assigned LED-Wiz port numbers is essentially arbitrary - you can // customize this by changing the entries in the array below if you @@ -337,6 +405,21 @@ // file, for example) to address the port. PWM-capable ports are // marked as such - we group the PWM-capable ports into the first // 10 LED-Wiz port numbers. +// +// If you wish to reallocate a pin in the array below to some other +// use, such as a button input port, simply change the pin name in +// the entry to NC (for Not Connected). This will disable the given +// logical LedWiz port number and free up the physical pin. +// +// If you wish to reallocate a pin currently assigned to the button +// input array, simply change the entry for the pin in the buttonMap[] +// array above to NC (for "not connected"), and plug the pin name into +// a slot of your choice in the array below. +// +// Note: PTD1 (pin J2-12) should NOT be assigned as an LedWiz output, +// as this pin is physically connected on the KL25Z to the on-board +// indicator LED's blue segment. This precludes any other use of +// the pin. // struct { PinName pin; @@ -363,17 +446,17 @@ { PTC6, false }, // pin J1-11, LW port 19 { PTC10, false }, // pin J1-13, LW port 20 { PTC11, false }, // pin J1-15, LW port 21 - { PTC12, false }, // pin J2-1, LW port 22 - { PTC13, false }, // pin J2-3, LW port 23 - { PTC16, false }, // pin J2-5, LW port 24 - { PTC17, false }, // pin J2-7, LW port 25 - { PTA16, false }, // pin J2-9, LW port 26 - { PTA17, false }, // pin J2-11, LW port 27 - { PTE31, false }, // pin J2-13, LW port 28 - { PTD6, false }, // pin J2-17, LW port 29 - { PTD7, false }, // pin J2-19, LW port 30 - { PTE0, false }, // pin J2-18, LW port 31 - { PTE1, false } // pin J2-20, LW port 32 + { PTE0, false }, // pin J2-18, LW port 22 + { NC, false }, // Not used, LW port 23 + { NC, false }, // Not used, LW port 24 + { NC, false }, // Not used, LW port 25 + { NC, false }, // Not used, LW port 26 + { NC, false }, // Not used, LW port 27 + { NC, false }, // Not used, LW port 28 + { NC, false }, // Not used, LW port 29 + { NC, false }, // Not used, LW port 30 + { NC, false }, // Not used, LW port 31 + { NC, false } // Not used, LW port 32 }; @@ -431,6 +514,12 @@ virtual void set(float val) { p = val; } DigitalOut p; }; +class LwUnusedOut: public LwOut +{ +public: + LwUnusedOut() { } + virtual void set(float val) { } +}; // output pin array static LwOut *lwPin[32]; @@ -440,10 +529,13 @@ { for (int i = 0 ; i < countof(lwPin) ; ++i) { - PinName p = ledWizPortMap[i].pin; - lwPin[i] = (ledWizPortMap[i].isPWM - ? (LwOut *)new LwPwmOut(p) - : (LwOut *)new LwDigOut(p)); + PinName p = (i < countof(ledWizPortMap) ? ledWizPortMap[i].pin : NC); + if (p == NC) + lwPin[i] = new LwUnusedOut(); + else if (ledWizPortMap[i].isPWM) + lwPin[i] = new LwPwmOut(p); + else + lwPin[i] = new LwDigOut(p); } } @@ -482,6 +574,100 @@ lwPin[i]->set(wizState(i)); } + +// --------------------------------------------------------------------------- +// +// Button input +// + +// button input map array +DigitalIn *buttonDigIn[32]; + +// initialize the button inputs +void initButtons() +{ + // create the digital inputs + for (int i = 0 ; i < countof(buttonDigIn) ; ++i) + { + if (i < countof(buttonMap) && buttonMap[i] != NC) + buttonDigIn[i] = new DigitalIn(buttonMap[i]); + else + buttonDigIn[i] = 0; + } +} + + +// read the raw button input state +uint32_t readButtonsRaw() +{ + // start with all buttons off + uint32_t buttons = 0; + + // scan the button list + uint32_t bit = 1; + for (int i = 0 ; i < countof(buttonDigIn) ; ++i, bit <<= 1) + { + if (buttonDigIn[i] != 0 && !buttonDigIn[i]->read()) + buttons |= bit; + } + + // return the button list + return buttons; +} + +// Read buttons with debouncing. We keep a circular buffer +// of recent input readings. We'll AND together the status of +// each button over the past 50ms. A button that has been on +// continuously for 50ms will be reported as ON. All others +// will be reported as OFF. +uint32_t readButtonsDebounced() +{ + struct reading { + int dt; // time since previous reading + uint32_t b; // button state at this reading + }; + static Timer t; // timer for tracking time between readings + static reading readings[8]; // circular buffer of readings + static int ri = 0; // reading buffer index (next write position) + + // get the write pointer + reading *r = &readings[ri]; + + // figure the time since the last reading, and read the raw button state + r->dt = t.read_ms(); + uint32_t b = r->b = readButtonsRaw(); + + // start timing the next interval + t.start(); + t.reset(); + + // AND together readings over 50ms + int ms = 0; + for (int i = 0 ; i < countof(readings) && ms < 50 ; ++i) + { + // find the next prior reading, wrapping in the circular buffer + int j = ri - i; + if (j < 0) + j = countof(readings) - 1; + + reading *rj = &readings[j]; + + // AND the buttons for this reading + b &= rj->b; + + // count the time + ms += rj->dt; + } + + // advance the write position for next time + ri += 1; + if (ri > countof(readings)) + ri = 0; + + // return the debounced result + return b; +} + // --------------------------------------------------------------------------- // // Non-volatile memory (NVM) @@ -915,6 +1101,9 @@ // initialize the LedWiz ports initLwOut(); + // initialize the button input ports + initButtons(); + // we don't need a reset yet bool needReset = false; @@ -1464,6 +1653,9 @@ x = xa; y = ya; + // update the buttons + uint32_t buttons = readButtonsDebounced(); + // Send the status report. Note that the nominal x and y axes // are reversed - this makes it more intuitive to set up in VP. // If we mount the Freesale card flat on the floor of the cabinet @@ -1471,7 +1663,7 @@ // arrangement of our nominal axes aligns with VP's standard // setting, so that we can configure VP with X Axis = X on the // joystick and Y Axis = Y on the joystick. - js.update(y, x, z, 0, statusFlags); + js.update(y, x, z, buttons, statusFlags); // If we're in pixel dump mode, report all pixel exposure values if (reportPix)