Library to handle SpaceBall, SpaceMouse and SpaceOrb on serial port. Gets access to 3D rotation and translation vector as well as button status. (USB is not supported)

Dependents:   SpaceBall_Example

Library to handle SpaceBall, SpaceMouse and SpaceOrb on serial port. Gets access to 3D rotation and translation vector as well as button status. (USB is not supported)

All handling and decoding is done in the RX interrupt and the vector values can be read out asynchronously with different coordinate mappings.

Example:

#include "mbed.h"
#include "SpaceBall.h"
 
PwmOut led[] = {(LED1), (LED2), (LED3), (LED4) };
SpaceBall SBall(p9, p10);   // tx, rx, bSOrb
 
int main() {
    SBall.Init();
    
    while(1) {
 
        led[0] = abs( SBall[TX] ) + abs( SBall[TY] ) + abs( SBall[TZ] );
        led[1] = abs( SBall[RX] );
        led[2] = abs( SBall[RY] );
        led[3] = abs( SBall[RZ] );
        
        wait_us(500);
    }
}

In this exaple the 4 LEDs are powered dependent on force at the Spaceball. LED1 shows the sum of all translation forces. LED2 to LED4 shows the rotation forces.

For more information about SpaceBall devices see manufactorers page http://www.3dconnexion.com

For connecting a SpaceBall (or SpaceMouse or SpaceOrb) to mbed see page wiki/Serial-Connection

Example: SpaceBall 4000

/media/uploads/jocis/spaceball1.jpg

Committer:
jocis
Date:
Sat Dec 01 18:23:50 2012 +0000
Revision:
1:e6282b645d9b
Child:
2:a7c0fcd157f7
Implemented SpaceMouse and SpaceOrb

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jocis 1:e6282b645d9b 1 #include "SpaceBall.h"
jocis 1:e6282b645d9b 2
jocis 1:e6282b645d9b 3 #define Sleep(x) wait_ms(x*10)
jocis 1:e6282b645d9b 4
jocis 1:e6282b645d9b 5 extern Serial pc;
jocis 1:e6282b645d9b 6
jocis 1:e6282b645d9b 7 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 8
jocis 1:e6282b645d9b 9
jocis 1:e6282b645d9b 10
jocis 1:e6282b645d9b 11 /*
jocis 1:e6282b645d9b 12 Convert characters to nibbles
jocis 1:e6282b645d9b 13 */
jocis 1:e6282b645d9b 14 int DecodeSM(char c)
jocis 1:e6282b645d9b 15 {
jocis 1:e6282b645d9b 16 int n;
jocis 1:e6282b645d9b 17
jocis 1:e6282b645d9b 18 switch (c) {
jocis 1:e6282b645d9b 19 case '0': n = 0; break;
jocis 1:e6282b645d9b 20 case 'A': n = 1; break;
jocis 1:e6282b645d9b 21 case 'B': n = 2; break;
jocis 1:e6282b645d9b 22 case '3': n = 3; break;
jocis 1:e6282b645d9b 23 case 'D': n = 4; break;
jocis 1:e6282b645d9b 24 case '5': n = 5; break;
jocis 1:e6282b645d9b 25 case '6': n = 6; break;
jocis 1:e6282b645d9b 26 case 'G': n = 7; break;
jocis 1:e6282b645d9b 27 case 'H': n = 8; break;
jocis 1:e6282b645d9b 28 case '9': n = 9; break;
jocis 1:e6282b645d9b 29 case ':': n = 10; break;
jocis 1:e6282b645d9b 30 case 'K': n = 11; break;
jocis 1:e6282b645d9b 31 case '<': n = 12; break;
jocis 1:e6282b645d9b 32 case 'M': n = 13; break;
jocis 1:e6282b645d9b 33 case 'N': n = 14; break;
jocis 1:e6282b645d9b 34 case '?': n = 15; break;
jocis 1:e6282b645d9b 35 default: n = 0; break;
jocis 1:e6282b645d9b 36 }
jocis 1:e6282b645d9b 37
jocis 1:e6282b645d9b 38 return(n);
jocis 1:e6282b645d9b 39 }
jocis 1:e6282b645d9b 40
jocis 1:e6282b645d9b 41 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 42
jocis 1:e6282b645d9b 43 void SpaceBall::InitSB()
jocis 1:e6282b645d9b 44 {
jocis 1:e6282b645d9b 45 m_packlen=1;
jocis 1:e6282b645d9b 46 m_resetoccured=0;
jocis 1:e6282b645d9b 47
jocis 1:e6282b645d9b 48 m_spaceball4000 = 0; /* re-determine which type it is */
jocis 1:e6282b645d9b 49 m_leftymode4000 = 0; /* re-determine if its in lefty mode */
jocis 1:e6282b645d9b 50
jocis 1:e6282b645d9b 51 if (!m_resetoccured) {
jocis 1:e6282b645d9b 52
jocis 1:e6282b645d9b 53 // pc.printf("Sending reset command to spaceball...\n");
jocis 1:e6282b645d9b 54
jocis 1:e6282b645d9b 55 m_resetoccured=1;
jocis 1:e6282b645d9b 56 _serial.printf ( "@\r" ); /* force reset */
jocis 1:e6282b645d9b 57 }
jocis 1:e6282b645d9b 58
jocis 1:e6282b645d9b 59 Sleep(10);
jocis 1:e6282b645d9b 60
jocis 1:e6282b645d9b 61 // pc.printf("Sending initialization sequence to spaceball...\n");
jocis 1:e6282b645d9b 62
jocis 1:e6282b645d9b 63 _serial.printf ( "CB\r" );
jocis 1:e6282b645d9b 64 Sleep(10);
jocis 1:e6282b645d9b 65 _serial.printf ( "NT\r" );
jocis 1:e6282b645d9b 66 Sleep(10);
jocis 1:e6282b645d9b 67 _serial.printf ( "FTp\r" );
jocis 1:e6282b645d9b 68 Sleep(10);
jocis 1:e6282b645d9b 69 _serial.printf ( "FRp\r" );
jocis 1:e6282b645d9b 70 Sleep(10);
jocis 1:e6282b645d9b 71 _serial.printf ( "P@r@r\r" );
jocis 1:e6282b645d9b 72 Sleep(10);
jocis 1:e6282b645d9b 73 _serial.printf ( "MSSV\r" );
jocis 1:e6282b645d9b 74 Sleep(10);
jocis 1:e6282b645d9b 75 _serial.printf ( "Z\r" );
jocis 1:e6282b645d9b 76 Sleep(10);
jocis 1:e6282b645d9b 77 _serial.printf ( "BcCcC\r" );
jocis 1:e6282b645d9b 78
jocis 1:e6282b645d9b 79 Sleep(10);
jocis 1:e6282b645d9b 80 _serial.printf ( "\rvz\r" );
jocis 1:e6282b645d9b 81 Sleep(10);
jocis 1:e6282b645d9b 82 _serial.printf ( "vQ\r" );
jocis 1:e6282b645d9b 83 Sleep(10);
jocis 1:e6282b645d9b 84 _serial.printf ( "kQ\r" );
jocis 1:e6282b645d9b 85 Sleep(10);
jocis 1:e6282b645d9b 86 _serial.printf ( "m3\r" );
jocis 1:e6282b645d9b 87 }
jocis 1:e6282b645d9b 88
jocis 1:e6282b645d9b 89 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 90
jocis 1:e6282b645d9b 91 void SpaceBall::ProcessSB ( char data )
jocis 1:e6282b645d9b 92 {
jocis 1:e6282b645d9b 93 switch (data) {
jocis 1:e6282b645d9b 94 case '\r': //0xd:
jocis 1:e6282b645d9b 95 _data[_idx] = 0;
jocis 1:e6282b645d9b 96 ProcessPacketSB();
jocis 1:e6282b645d9b 97 _idx = 0;
jocis 1:e6282b645d9b 98 _escape = 0;
jocis 1:e6282b645d9b 99 break;
jocis 1:e6282b645d9b 100 case '^':
jocis 1:e6282b645d9b 101 if (!_escape) {
jocis 1:e6282b645d9b 102 _escape = 1;
jocis 1:e6282b645d9b 103 break;
jocis 1:e6282b645d9b 104 }
jocis 1:e6282b645d9b 105 _escape = 0;
jocis 1:e6282b645d9b 106 case 'M':
jocis 1:e6282b645d9b 107 case 'Q':
jocis 1:e6282b645d9b 108 case 'S':
jocis 1:e6282b645d9b 109 if (_escape) {
jocis 1:e6282b645d9b 110 _escape = 0;
jocis 1:e6282b645d9b 111 data &= 0x1f;
jocis 1:e6282b645d9b 112 }
jocis 1:e6282b645d9b 113 default:
jocis 1:e6282b645d9b 114 if (_escape)
jocis 1:e6282b645d9b 115 _escape = 0;
jocis 1:e6282b645d9b 116 if (_idx < SPACEBALL_MAX_LENGTH)
jocis 1:e6282b645d9b 117 _data[_idx++] = data;
jocis 1:e6282b645d9b 118 break;
jocis 1:e6282b645d9b 119 }
jocis 1:e6282b645d9b 120 }
jocis 1:e6282b645d9b 121
jocis 1:e6282b645d9b 122 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 123
jocis 1:e6282b645d9b 124 void SpaceBall::ProcessPacketSB ( void )
jocis 1:e6282b645d9b 125 {
jocis 1:e6282b645d9b 126 int i;
jocis 1:e6282b645d9b 127
jocis 1:e6282b645d9b 128 if (_idx < 2) return;
jocis 1:e6282b645d9b 129
jocis 1:e6282b645d9b 130 switch (_data[0]) {
jocis 1:e6282b645d9b 131
jocis 1:e6282b645d9b 132 case 'D': /* Ball data */
jocis 1:e6282b645d9b 133 if (_idx != 15) return;
jocis 1:e6282b645d9b 134 for (i = 0; i < 6; i++) {
jocis 1:e6282b645d9b 135 m_axis[i] = (short)( (_data[2*i + 3] << 8) | _data[2*i + 2] );
jocis 1:e6282b645d9b 136 }
jocis 1:e6282b645d9b 137 DoChangedAxis();
jocis 1:e6282b645d9b 138 break;
jocis 1:e6282b645d9b 139
jocis 1:e6282b645d9b 140 case 'd': /* Ball data */
jocis 1:e6282b645d9b 141 //pc.printf("d%d",_idx);
jocis 1:e6282b645d9b 142 if (_idx != 25) return;
jocis 1:e6282b645d9b 143 for (i = 0; i < 6; i++) {
jocis 1:e6282b645d9b 144 m_axis[i] = (short)( (
jocis 1:e6282b645d9b 145 DecodeSM(_data[4*i+4]) | (DecodeSM(_data[4*i+3])<<4) | (DecodeSM(_data[4*i+2])<<8) | (DecodeSM(_data[4*i+1])<<12) )
jocis 1:e6282b645d9b 146 ^ 0x8000 );
jocis 1:e6282b645d9b 147 }
jocis 1:e6282b645d9b 148 DoChangedAxis();
jocis 1:e6282b645d9b 149 break;
jocis 1:e6282b645d9b 150
jocis 1:e6282b645d9b 151 case 'K': /* Button data */
jocis 1:e6282b645d9b 152 if (_idx != 3) return;
jocis 1:e6282b645d9b 153 /* Spaceball 2003A, 2003B, 2003 FLX, 3003 FLX, 4000 FLX */
jocis 1:e6282b645d9b 154 /* button packet. (4000 only for backwards compatibility) */
jocis 1:e6282b645d9b 155 /* The lowest 5 bits of the first byte are buttons 5-9 */
jocis 1:e6282b645d9b 156 /* Button '8' on a Spaceball 2003 is the rezero button */
jocis 1:e6282b645d9b 157 /* The lowest 4 bits of the second byte are buttons 1-4 */
jocis 1:e6282b645d9b 158 /* For Spaceball 2003, we'll map the buttons 1-7 normally */
jocis 1:e6282b645d9b 159 /* skip 8, as its a hardware "rezero button" on that device */
jocis 1:e6282b645d9b 160 /* and call the "pick" button "8". */
jocis 1:e6282b645d9b 161 /* On the Spaceball 3003, the "right" button also triggers */
jocis 1:e6282b645d9b 162 /* the "pick" bit. We OR the 2003/3003 rezero bits together */
jocis 1:e6282b645d9b 163
jocis 1:e6282b645d9b 164 /* if we have found a Spaceball 4000, then we ignore the 'K' */
jocis 1:e6282b645d9b 165 /* packets entirely, and only use the '.' packets. */
jocis 1:e6282b645d9b 166 if (m_spaceball4000)
jocis 1:e6282b645d9b 167 break;
jocis 1:e6282b645d9b 168
jocis 1:e6282b645d9b 169 m_buttons =
jocis 1:e6282b645d9b 170 ((_data[1] & 0x10) << 8) | /* 2003 pick button is ??? */
jocis 1:e6282b645d9b 171 ((_data[1] & 0x20) << 9) | /* 3003 rezero button */
jocis 1:e6282b645d9b 172 ((_data[1] & 0x08) << 11) | /* 2003 rezero button */
jocis 1:e6282b645d9b 173 ((_data[1] & 0x07) << 4) | /* 5,6,7 (2003/4000) */
jocis 1:e6282b645d9b 174 ((_data[2] & 0x30) << 8) | /* 3003 Left/Right buttons */
jocis 1:e6282b645d9b 175 ((_data[2] & 0x0F)); /* 1,2,3,4 (2003/4000) */
jocis 1:e6282b645d9b 176
jocis 1:e6282b645d9b 177 //bChanged = true;
jocis 1:e6282b645d9b 178 DoChangedButtons();
jocis 1:e6282b645d9b 179 /*
jocis 1:e6282b645d9b 180 input_report_key(dev, BTN_1, (data[2] & 0x01) || (data[2] & 0x20));
jocis 1:e6282b645d9b 181 input_report_key(dev, BTN_2, data[2] & 0x02);
jocis 1:e6282b645d9b 182 input_report_key(dev, BTN_3, data[2] & 0x04);
jocis 1:e6282b645d9b 183 input_report_key(dev, BTN_4, data[2] & 0x08);
jocis 1:e6282b645d9b 184 input_report_key(dev, BTN_5, data[1] & 0x01);
jocis 1:e6282b645d9b 185 input_report_key(dev, BTN_6, data[1] & 0x02);
jocis 1:e6282b645d9b 186 input_report_key(dev, BTN_7, data[1] & 0x04);
jocis 1:e6282b645d9b 187 input_report_key(dev, BTN_8, data[1] & 0x10);
jocis 1:e6282b645d9b 188 */
jocis 1:e6282b645d9b 189 break;
jocis 1:e6282b645d9b 190
jocis 1:e6282b645d9b 191 case 'k': /* Button data */
jocis 1:e6282b645d9b 192 //pc.printf("k%d",_idx);
jocis 1:e6282b645d9b 193 pc.printf("<%s>\r\n",_data);
jocis 1:e6282b645d9b 194 if (_idx != 4) return;
jocis 1:e6282b645d9b 195 m_buttons = DecodeSM(_data[1]) | (DecodeSM(_data[2])<<4) | (DecodeSM(_data[3])<<8);
jocis 1:e6282b645d9b 196
jocis 1:e6282b645d9b 197 DoChangedButtons();
jocis 1:e6282b645d9b 198 break;
jocis 1:e6282b645d9b 199
jocis 1:e6282b645d9b 200 case '.': /* Advanced button data */
jocis 1:e6282b645d9b 201 if (_idx != 3) return;
jocis 1:e6282b645d9b 202 /* Spaceball 4000 FLX "expanded" button packet, with 12 buttons */
jocis 1:e6282b645d9b 203
jocis 1:e6282b645d9b 204 /* extra packet validity check, since we use this packet type */
jocis 1:e6282b645d9b 205 /* to override the 'K' button packets, and determine if its a */
jocis 1:e6282b645d9b 206 /* Spaceball 4000 or not... */
jocis 1:e6282b645d9b 207
jocis 1:e6282b645d9b 208 /* if we got a valid '.' packet, this must be a Spaceball 4000 */
jocis 1:e6282b645d9b 209 m_spaceball4000 = 1; /* Must be talking to a Spaceball 4000 */
jocis 1:e6282b645d9b 210
jocis 1:e6282b645d9b 211 /* Spaceball 4000 series "expanded" button press event */
jocis 1:e6282b645d9b 212 /* includes data for 12 buttons, and left/right orientation */
jocis 1:e6282b645d9b 213 m_buttons =
jocis 1:e6282b645d9b 214 (((~_data[1]) & 0x20) << 10) | /* "left handed" mode */
jocis 1:e6282b645d9b 215 ((_data[1] & 0x1F) << 7) | /* 8,9,10,11,12 */
jocis 1:e6282b645d9b 216 ((_data[2] & 0x3F) ) | /* 1,2,3,4,5,6 (4000) */
jocis 1:e6282b645d9b 217 ((_data[2] & 0x80) >> 1); /* 7 (4000) */
jocis 1:e6282b645d9b 218
jocis 1:e6282b645d9b 219 /* set "lefty" orientation mode if "lefty bit" is _clear_ */
jocis 1:e6282b645d9b 220 if ((_data[1] & 0x20) == 0)
jocis 1:e6282b645d9b 221 m_leftymode4000 = 1; /* left handed mode */
jocis 1:e6282b645d9b 222 else
jocis 1:e6282b645d9b 223 m_leftymode4000 = 0; /* right handed mode */
jocis 1:e6282b645d9b 224
jocis 1:e6282b645d9b 225 //bChanged = true;
jocis 1:e6282b645d9b 226 DoChangedButtons();
jocis 1:e6282b645d9b 227 /*
jocis 1:e6282b645d9b 228 input_report_key(dev, BTN_1, data[2] & 0x01);
jocis 1:e6282b645d9b 229 input_report_key(dev, BTN_2, data[2] & 0x02);
jocis 1:e6282b645d9b 230 input_report_key(dev, BTN_3, data[2] & 0x04);
jocis 1:e6282b645d9b 231 input_report_key(dev, BTN_4, data[2] & 0x08);
jocis 1:e6282b645d9b 232 input_report_key(dev, BTN_5, data[2] & 0x10);
jocis 1:e6282b645d9b 233 input_report_key(dev, BTN_6, data[2] & 0x20);
jocis 1:e6282b645d9b 234 input_report_key(dev, BTN_7, data[2] & 0x80);
jocis 1:e6282b645d9b 235 input_report_key(dev, BTN_8, data[1] & 0x01);
jocis 1:e6282b645d9b 236 input_report_key(dev, BTN_9, data[1] & 0x02);
jocis 1:e6282b645d9b 237 input_report_key(dev, BTN_A, data[1] & 0x04);
jocis 1:e6282b645d9b 238 input_report_key(dev, BTN_B, data[1] & 0x08);
jocis 1:e6282b645d9b 239 input_report_key(dev, BTN_C, data[1] & 0x10);
jocis 1:e6282b645d9b 240 input_report_key(dev, BTN_MODE, data[1] & 0x20);
jocis 1:e6282b645d9b 241 */
jocis 1:e6282b645d9b 242 break;
jocis 1:e6282b645d9b 243
jocis 1:e6282b645d9b 244 case 'E': /* Device error */
jocis 1:e6282b645d9b 245 case 'e': /* Device error */
jocis 1:e6282b645d9b 246 //printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
jocis 1:e6282b645d9b 247 break;
jocis 1:e6282b645d9b 248
jocis 1:e6282b645d9b 249 case '?': /* Bad command packet */
jocis 1:e6282b645d9b 250 //printk(KERN_ERR "spaceball: Bad command. [%s]\n", spaceball->data + 1);
jocis 1:e6282b645d9b 251 break;
jocis 1:e6282b645d9b 252
jocis 1:e6282b645d9b 253 case 'C': /* Communications mode packet */
jocis 1:e6282b645d9b 254 case 'F': /* Spaceball sensitization packet */
jocis 1:e6282b645d9b 255 case 'P': /* Spaceball update rate packet */
jocis 1:e6282b645d9b 256 case 'M': /* Spaceball movement mode packet */
jocis 1:e6282b645d9b 257 case 'N': /* Null region packet */
jocis 1:e6282b645d9b 258 case '\r': /* carriage return at poweron */
jocis 1:e6282b645d9b 259 case '\v': /* XON at poweron */
jocis 1:e6282b645d9b 260 /* eat and ignore these packets */
jocis 1:e6282b645d9b 261 break;
jocis 1:e6282b645d9b 262
jocis 1:e6282b645d9b 263 case '@': /* Reset packet */
jocis 1:e6282b645d9b 264 case 'z': /* Reset packet */
jocis 1:e6282b645d9b 265 /* if we get a reset packet, we have to re-initialize */
jocis 1:e6282b645d9b 266 /* the device, and assume that its completely schizophrenic */
jocis 1:e6282b645d9b 267 /* at this moment, we must reset it again at this point */
jocis 1:e6282b645d9b 268 m_resetoccured=1;
jocis 1:e6282b645d9b 269 //JKReset();
jocis 1:e6282b645d9b 270 //Init();
jocis 1:e6282b645d9b 271 break;
jocis 1:e6282b645d9b 272
jocis 1:e6282b645d9b 273 case 'b': /* Beep */
jocis 1:e6282b645d9b 274 case 'c': /* */
jocis 1:e6282b645d9b 275 case 'p': /* */
jocis 1:e6282b645d9b 276 case 'm': /* mode changed */
jocis 1:e6282b645d9b 277 case 'n': /* Zero radius */
jocis 1:e6282b645d9b 278 case 'q': /* Sensitivity */
jocis 1:e6282b645d9b 279 case 'v': /* Version number follows */
jocis 1:e6282b645d9b 280 /* eat and ignore these packets */
jocis 1:e6282b645d9b 281 break;
jocis 1:e6282b645d9b 282
jocis 1:e6282b645d9b 283 default:
jocis 1:e6282b645d9b 284 pc.printf("<%s>\r\n",_data);
jocis 1:e6282b645d9b 285 break;
jocis 1:e6282b645d9b 286
jocis 1:e6282b645d9b 287 }
jocis 1:e6282b645d9b 288
jocis 1:e6282b645d9b 289 }
jocis 1:e6282b645d9b 290
jocis 1:e6282b645d9b 291 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 292 ///////////////////////////////////////////////////////////////////////////////
jocis 1:e6282b645d9b 293 ///////////////////////////////////////////////////////////////////////////////