libmanta
A cross-platform API for the Snyderphonics Manta
|
00001 #include <cmath> 00002 #include "Manta.h" 00003 #include "MantaExceptions.h" 00004 00005 00006 /************************************************************************/ 00011 Manta::Manta(void) { 00012 for(int i = 0; i < 53; ++i) 00013 { 00014 LastInReport[i] = 0; 00015 MaxSensorValues[i] = AverageMaxSensorValues[i]; 00016 } 00017 for(int i = 53; i < 57; ++i) 00018 { 00019 LastInReport[i] = 0xFF; 00020 } 00021 for(unsigned int i = 0; i < sizeof(CurrentOutReport); ++i) 00022 { 00023 CurrentOutReport[i] = 0; 00024 } 00025 for(unsigned int i = 0; i < sizeof(VelocityWaiting) / sizeof(VelocityWaiting[0]); ++i) 00026 { 00027 VelocityWaiting[i] = false; 00028 } 00029 } 00030 00031 /************************************************************************/ 00035 void Manta::FrameReceived(int8_t *frame) 00036 { 00037 uint8_t *uframe = (uint8_t *)frame; 00038 for(int i = 1; i < 53; ++i) 00039 { 00040 uframe[i] = ScaleSensorValue(frame[i] + 128, i); 00041 } 00042 /* apply the offset to the slider bytes without scaling them */ 00043 for(int i = 53; i < 57; ++i) 00044 { 00045 uframe[i] = frame[i] + 128; 00046 } 00047 FrameEvent(uframe); 00048 /* input frames have one reportID byte at the beginning */ 00049 for(int i = 1; i < 53; ++i) 00050 { 00051 /* check to see if there's a previous sample waiting to have 00052 * the velocity algorithm run */ 00053 if(true == VelocityWaiting[i]) 00054 { 00055 if(i < 49) 00056 PadVelocityEvent((i - 1) / 8, (i - 1) % 8, i - 1, 00057 CalculateVelocity(LastInReport[i], uframe[i])); 00058 else 00059 ButtonVelocityEvent(i - 49, CalculateVelocity(LastInReport[i], uframe[i])); 00060 VelocityWaiting[i] = false; 00061 } 00062 00063 if(uframe[i] != LastInReport[i]) 00064 { 00065 /* check to see if this is a release */ 00066 if(0 == uframe[i]) 00067 { 00068 if(i < 49) 00069 PadVelocityEvent((i - 1) / 8, (i - 1) % 8, i - 1, 0); 00070 else 00071 ButtonVelocityEvent(i - 49, 0); 00072 } 00073 /* check to see if this is the first nonzero sample */ 00074 else if(0 == LastInReport[i]) 00075 { 00076 VelocityWaiting[i] = true; 00077 } 00078 if(i < 49) 00079 PadEvent((i - 1) / 8, (i - 1) % 8, i - 1, uframe[i]); 00080 else 00081 ButtonEvent(i - 49, uframe[i]); 00082 } 00083 LastInReport[i] = uframe[i]; 00084 } 00085 if(uframe[53] != LastInReport[53] || uframe[54] != LastInReport[54]) 00086 { 00087 SliderEvent(0, (uframe[53]) | ((uframe[54]) << 8 )); 00088 } 00089 if(uframe[55] != LastInReport[55] || uframe[56] != LastInReport[56]) 00090 { 00091 SliderEvent(1, (uframe[55]) | ((uframe[56]) << 8 )); 00092 } 00093 for(int i = 53; i < 57; ++i) 00094 { 00095 LastInReport[i] = uframe[i]; 00096 } 00097 } 00098 00099 /************************************************************************/ 00104 void Manta::SetPadLED(LEDState state, int ledID) 00105 { 00106 int row = ledID / 8; 00107 int column = ledID % 8; 00108 00109 if(ledID < 0 || ledID > 47) 00110 { 00111 throw std::invalid_argument("Invalid Pad Index"); 00112 } 00113 00114 switch(state) 00115 { 00116 case Amber: 00117 CurrentOutReport[AmberIndex + row] |= (1 << column); 00118 CurrentOutReport[RedIndex + row] &= ~(1 << column); 00119 break; 00120 case Red: 00121 CurrentOutReport[RedIndex + row] |= (1 << column); 00122 CurrentOutReport[AmberIndex + row] &= ~(1 << column); 00123 break; 00124 case Off: 00125 CurrentOutReport[AmberIndex + row] &= ~(1 << column); 00126 CurrentOutReport[RedIndex + row] &= ~(1 << column); 00127 break; 00128 default: 00129 throw std::invalid_argument("Invalid state"); 00130 } 00131 00132 if(IsConnected()) 00133 { 00134 WriteFrame(CurrentOutReport, false); 00135 } 00136 } 00137 00138 /************************************************************************/ 00145 void Manta::SetPadLEDRow(LEDState state, int row, uint8_t mask) 00146 { 00147 if(row < 0 || row > 5) 00148 { 00149 throw std::invalid_argument("Invalid Row Index"); 00150 } 00151 00152 MantaClient::DebugPrint("Called SetPadLEDRow(%s, %d, %X)", 00153 state == Off ? "Off" : state == Amber ? "Amber" : "Red", row, mask); 00154 MantaClient::DebugPrint("ByteReverse(0x%X) = 0x%X", 0xA0, byteReverse(0xA0)); 00155 switch(state) 00156 { 00157 case Amber: 00158 CurrentOutReport[AmberIndex + row] |= byteReverse(mask); 00159 CurrentOutReport[RedIndex + row] &= ~byteReverse(mask); 00160 break; 00161 case Red: 00162 CurrentOutReport[RedIndex + row] |= byteReverse(mask); 00163 CurrentOutReport[AmberIndex + row] &= ~byteReverse(mask); 00164 break; 00165 case Off: 00166 CurrentOutReport[RedIndex + row] &= ~byteReverse(mask); 00167 CurrentOutReport[AmberIndex + row] &= ~byteReverse(mask); 00168 break; 00169 default: 00170 throw std::invalid_argument("Invalid state"); 00171 } 00172 if(IsConnected()) 00173 { 00174 WriteFrame(CurrentOutReport, false); 00175 } 00176 } 00177 00178 /************************************************************************/ 00185 void Manta::SetPadLEDColumn(LEDState state, int column, uint8_t mask) 00186 { 00187 if(column < 0 || column > 7) 00188 { 00189 throw std::invalid_argument("Invalid Column Index"); 00190 } 00191 00192 MantaClient::DebugPrint("Called SetPadLEDColumn(%s, %d, %X)", 00193 state == Off ? "Off" : state == Amber ? "Amber" : "Red", column, mask); 00194 switch(state) 00195 { 00196 case Amber: 00197 for(int i = 0; i < 6; ++i) 00198 { 00199 if((mask >> i) & 0x01) 00200 { 00201 CurrentOutReport[AmberIndex + i] |= (0x01 << column); 00202 CurrentOutReport[RedIndex + i] &= ~(0x01 << column); 00203 } 00204 } 00205 break; 00206 case Red: 00207 for(int i = 0; i < 6; ++i) 00208 { 00209 if((mask >> i) & 0x01) 00210 { 00211 CurrentOutReport[RedIndex + i] |= (0x01 << column); 00212 CurrentOutReport[AmberIndex + i] &= ~(0x01 << column); 00213 } 00214 } 00215 break; 00216 case Off: 00217 for(int i = 0; i < 6; ++i) 00218 { 00219 if((mask >> i) & 0x01) 00220 { 00221 CurrentOutReport[RedIndex + i] &= ~(0x01 << column); 00222 CurrentOutReport[AmberIndex + i] &= ~(0x01 << column); 00223 } 00224 } 00225 break; 00226 default: 00227 throw std::invalid_argument("Invalid state"); 00228 } 00229 00230 if(IsConnected()) 00231 { 00232 WriteFrame(CurrentOutReport, false); 00233 } 00234 } 00235 00236 /************************************************************************/ 00243 void Manta::SetPadLEDFrame(LEDState state, LEDFrame mask) 00244 { 00245 switch(state) 00246 { 00247 case Amber: 00248 for(unsigned int i = 0; i < sizeof(LEDFrame); ++i) 00249 { 00250 CurrentOutReport[AmberIndex + i] = byteReverse(mask[i]); 00251 CurrentOutReport[RedIndex + i] &= ~byteReverse(mask[i]); 00252 } 00253 break; 00254 case Red: 00255 for(unsigned int i = 0; i < sizeof(LEDFrame); ++i) 00256 { 00257 CurrentOutReport[RedIndex + i] = byteReverse(mask[i]); 00258 CurrentOutReport[AmberIndex + i] &= ~byteReverse(mask[i]); 00259 } 00260 break; 00261 case Off: 00262 for(unsigned int i = 0; i < sizeof(LEDFrame); ++i) 00263 { 00264 CurrentOutReport[RedIndex + i] &= ~byteReverse(mask[i]); 00265 CurrentOutReport[AmberIndex + i] &= ~byteReverse(mask[i]); 00266 } 00267 break; 00268 default: 00269 throw std::invalid_argument("Invalid state"); 00270 } 00271 if(IsConnected()) 00272 { 00273 WriteFrame(CurrentOutReport, false); 00274 } 00275 } 00276 00277 /************************************************************************/ 00284 void Manta::SetSliderLED(LEDState state, int id, uint8_t mask) 00285 { 00286 if(id < 0 || id > 1) 00287 { 00288 throw std::invalid_argument("Invalid Slider Index"); 00289 } 00290 switch(state) 00291 { 00292 case Amber: 00293 CurrentOutReport[SliderIndex + id] |= byteReverse(mask); 00294 break; 00295 case Red: 00296 /* no Red slider LEDs, do nothing */ 00297 break; 00298 case Off: 00299 CurrentOutReport[SliderIndex + id] &= ~byteReverse(mask); 00300 break; 00301 default: 00302 throw std::invalid_argument("Invalid state"); 00303 } 00304 if(IsConnected()) 00305 { 00306 WriteFrame(CurrentOutReport, false); 00307 } 00308 } 00309 00310 /************************************************************************/ 00315 void Manta::SetButtonLED(LEDState state, int id) 00316 { 00317 if(id < 0 || id > 3) 00318 { 00319 throw std::invalid_argument("Invalid Button Index"); 00320 } 00321 00322 switch(state) 00323 { 00324 case Amber: 00325 CurrentOutReport[ButtonIndex] |= (0x01 << (id)); 00326 CurrentOutReport[ButtonIndex] &= ~(0x01 << (id + 4)); 00327 break; 00328 case Red: 00329 CurrentOutReport[ButtonIndex] |= (0x01 << (id + 4)); 00330 CurrentOutReport[ButtonIndex] &= ~(0x01 << (id)); 00331 break; 00332 case Off: 00333 CurrentOutReport[ButtonIndex] &= ~(0x01 << (id + 4)); 00334 CurrentOutReport[ButtonIndex] &= ~(0x01 << (id)); 00335 break; 00336 default: 00337 throw std::invalid_argument("Invalid state"); 00338 } 00339 if(IsConnected()) 00340 { 00341 WriteFrame(CurrentOutReport, false); 00342 } 00343 } 00344 00345 /************************************************************************/ 00348 void Manta::ResendLEDState(void) 00349 { 00350 if(IsConnected()) 00351 { 00352 WriteFrame(CurrentOutReport, false); 00353 } 00354 } 00355 00356 /************************************************************************/ 00359 void Manta::ClearButtonLEDs(void) 00360 { 00361 CurrentOutReport[ButtonIndex] = 0; 00362 00363 if(IsConnected()) 00364 { 00365 WriteFrame(CurrentOutReport, false); 00366 } 00367 } 00368 00369 /************************************************************************/ 00372 void Manta::ClearPadAndButtonLEDs(void) 00373 { 00374 for(unsigned int i = 0; i < sizeof(LEDFrame); ++i) 00375 { 00376 CurrentOutReport[AmberIndex + i] = 0; 00377 CurrentOutReport[RedIndex + i] = 0; 00378 } 00379 00380 CurrentOutReport[ButtonIndex] = 0; 00381 00382 if(IsConnected()) 00383 { 00384 WriteFrame(CurrentOutReport, false); 00385 } 00386 } 00387 00388 /************************************************************************/ 00391 void Manta::Recalibrate(void) 00392 { 00393 if(! IsConnected()) 00394 { 00395 throw MantaNotConnectedException(this); 00396 } 00397 00398 /* make sure these messages get queued so that they 00399 * don't just cancel each other out */ 00400 CurrentOutReport[ConfigIndex] |= 0x40; 00401 WriteFrame(CurrentOutReport, true); 00402 CurrentOutReport[ConfigIndex] &= ~0x40; 00403 WriteFrame(CurrentOutReport, true); 00404 } 00405 00406 /************************************************************************/ 00417 void Manta::SetLEDControl(LEDControlType control, bool state) 00418 { 00419 uint8_t flag; 00420 00421 switch(control) 00422 { 00423 case PadAndButton: 00424 flag = 0x01; 00425 break; 00426 case Slider: 00427 flag = 0x02; 00428 break; 00429 case Button: 00430 flag = 0x20; 00431 break; 00432 default: 00433 throw std::invalid_argument("Invalid Control Type"); 00434 } 00435 00436 if(state) 00437 CurrentOutReport[ConfigIndex] |= flag; 00438 else 00439 CurrentOutReport[ConfigIndex] &= ~flag; 00440 if(IsConnected()) 00441 { 00442 /* if we're disabling LEDControl, we want to make sure that this 00443 * message gets queued so that any pending LED messages get sent 00444 * down before we disable LEDs */ 00445 WriteFrame(CurrentOutReport, !state); 00446 } 00447 } 00448 00449 /************************************************************************/ 00455 void Manta::SetTurboMode(bool Enabled) 00456 { 00457 if(Enabled) 00458 CurrentOutReport[ConfigIndex] |= 0x04; 00459 else 00460 CurrentOutReport[ConfigIndex] &= ~0x04; 00461 if(IsConnected()) 00462 { 00463 WriteFrame(CurrentOutReport, false); 00464 } 00465 } 00466 00467 /************************************************************************/ 00477 void Manta::SetRawMode(bool Enabled) 00478 { 00479 if(Enabled) 00480 CurrentOutReport[ConfigIndex] |= 0x08; 00481 else 00482 CurrentOutReport[ConfigIndex] &= ~0x08; 00483 if(IsConnected()) 00484 { 00485 WriteFrame(CurrentOutReport, false); 00486 } 00487 } 00488 00489 /************************************************************************/ 00509 void Manta::SetMaxSensorValues(int *values) 00510 { 00511 for(int i = 0; i < 53; ++i) 00512 { 00513 MaxSensorValues[i] = values[i]; 00514 } 00515 } 00516 00517 uint8_t Manta::byteReverse(uint8_t inByte) 00518 { 00519 // Algorithm from Bit Twiddling Hacks 00520 uint8_t outByte = inByte; // first get LSB of inByte 00521 int s = 7; // extra shift needed at end 00522 00523 for (inByte >>= 1; inByte; inByte >>= 1) 00524 { 00525 outByte <<= 1; 00526 outByte |= inByte & 1; 00527 s--; 00528 } 00529 outByte <<= s; // shift when inByte's highest bits are zero 00530 return outByte; 00531 } 00532 00533 int Manta::CalculateVelocity(int LastValue, int CurrentValue) 00534 { 00535 float LOG1, LOG2; 00536 float MAX; 00537 float MIN; 00538 float RELATIVE1, RELATIVE2; 00539 float LOG_RELATIVE1, LOG_RELATIVE2; 00540 float SUM_RAW; 00541 float LOG_SUM_RAW; 00542 float LOG_SUM_RELATIVE; 00543 float UP1; 00544 float VELOCITY = 0; 00545 int VELint = 0; 00546 00547 00548 // now do the velocity calculation 00549 LOG1 = log(1.0 + (float)LastValue); 00550 LOG2 = log(1.0 + (float)CurrentValue); 00551 00552 MIN = LastValue; 00553 if (CurrentValue < MIN) 00554 { 00555 MIN = CurrentValue; 00556 } 00557 MAX = LastValue; 00558 if (CurrentValue > MAX) 00559 { 00560 MAX = CurrentValue; 00561 } 00562 RELATIVE1 = LastValue/MAX; 00563 RELATIVE2 = CurrentValue/MAX; 00564 LOG_RELATIVE1 = log(1.0 + RELATIVE1); 00565 LOG_RELATIVE2 = log(1.0 + RELATIVE2); 00566 SUM_RAW = LastValue+CurrentValue; 00567 LOG_SUM_RAW = log(1.0 + SUM_RAW); 00568 LOG_SUM_RELATIVE = log(1.0 + SUM_RAW/MAX); 00569 UP1 = 0; 00570 if (CurrentValue>LastValue) { UP1 = 1; } 00571 VELOCITY = 00572 -14.997037 + 00573 LastValue * 0.009361 + 00574 MIN * -0.014234 + 00575 LOG1 * 1.099763 + 00576 RELATIVE2 * -9.588311 + 00577 LOG_RELATIVE1 *-27.595303 + 00578 LOG_RELATIVE2 * -8.803761 + 00579 LOG_SUM_RELATIVE * 44.013138 + 00580 UP1 * 0.221622; 00581 //Then trim value to [0.4] range: 00582 if (VELOCITY < 0.) 00583 { 00584 VELOCITY = 0.; 00585 } 00586 if (VELOCITY > 4.) 00587 { 00588 VELOCITY = 4.; 00589 } 00590 //get it to 0. to 1. range 00591 VELOCITY = VELOCITY / 4.; 00592 // curve it exponentially 00593 VELOCITY = VELOCITY * VELOCITY; 00594 //get it to 0-126 range 00595 VELOCITY = VELOCITY * 126; 00596 //get it to 1-127 range 00597 VELOCITY = VELOCITY+ 1; 00598 //round to ints 00599 VELint = (int)VELOCITY; 00600 return VELint; 00601 } 00602 00603 int Manta::ScaleSensorValue(int rawValue, int index) 00604 { 00605 float div = (float)rawValue / MaxSensorValues[index]; 00606 return (int)((div * 210) + 0.5); 00607 } 00608 00609 const int Manta::AverageMaxSensorValues[53] = 00610 {0, 177, 184, 188, 189, 191, 190, 181, 181, 188, 193, 198, 200, 201, 199, 191, 00611 189, 192, 197, 202, 205, 206, 204, 199, 192, 202, 207, 211, 216, 215, 213, 00612 209, 201, 205, 210, 215, 220, 213, 218, 212, 204, 212, 216, 222, 227, 223, 00613 227, 221, 213, 200, 170, 190, 185}; 00614 00615 /************************************************************************/