@@ -13,6 +13,7 @@ public class Joycon {
1313 float timing = 60.0f ;
1414
1515 bool isPro = false ;
16+ bool isUSB = false ;
1617
1718 public enum DebugType : int {
1819 NONE ,
@@ -219,7 +220,7 @@ public byte[] GetData() {
219220 public int packetCounter = 0 ;
220221 //
221222
222- public Joycon ( IntPtr handle_ , bool imu , bool localize , float alpha , bool left , int id = 0 , bool isPro = false ) {
223+ public Joycon ( IntPtr handle_ , bool imu , bool localize , float alpha , bool left , int id = 0 , bool isPro = false , bool usb = false ) {
223224 handle = handle_ ;
224225 imu_enabled = imu ;
225226 do_localize = localize ;
@@ -229,6 +230,7 @@ public Joycon(IntPtr handle_, bool imu, bool localize, float alpha, bool left, i
229230
230231 PadId = id ;
231232 this . isPro = isPro ;
233+ isUSB = usb ;
232234 }
233235 public void DebugPrint ( String s , DebugType d ) {
234236 if ( debug_type == DebugType . NONE ) return ;
@@ -257,42 +259,72 @@ public Vector3 GetGyro() {
257259 public Vector3 GetAccel ( ) {
258260 return acc_g ;
259261 }
260- public Quaternion GetVector ( ) {
261- Vector3 v1 = new Vector3 ( j_b . X , i_b . X , k_b . X ) ;
262- Vector3 v2 = - ( new Vector3 ( j_b . Z , i_b . Z , k_b . Z ) ) ;
263- if ( v2 != Vector3 . Zero ) {
264- MyQuaternion temp = MyQuaternion . LookRotation ( v1 , v2 ) ;
265- return new Quaternion ( temp . eulerAngles , temp . Length ) ;
266- } else {
267- return Quaternion . Identity ;
268- }
269- }
270262 public int Attach ( byte leds_ = 0x0 ) {
271263 state = state_ . ATTACHED ;
264+
265+ // Make sure command is received
266+ HIDapi . hid_set_nonblocking ( handle , 0 ) ;
267+
272268 byte [ ] a = { 0x0 } ;
273- // Input report mode
274- Subcommand ( 0x3 , new byte [ ] { 0x30 } , 1 , false ) ;
275- Subcommand ( 0x3 , new byte [ ] { 0x03 , 0x00 , 0x00 , 0x01 } , 4 , false ) ; // higher gyro performance rate
276- a [ 0 ] = 0x1 ;
277- dump_calibration_data ( ) ;
269+
278270 // Connect
279- a [ 0 ] = 0x01 ;
280- Subcommand ( 0x1 , a , 1 ) ;
281- a [ 0 ] = 0x02 ;
282- Subcommand ( 0x1 , a , 1 ) ;
283- a [ 0 ] = 0x03 ;
284- Subcommand ( 0x1 , a , 1 ) ;
271+ if ( ! isUSB ) {
272+ // Input report mode
273+ Subcommand ( 0x03 , new byte [ ] { 0x30 } , 1 , false ) ;
274+ a [ 0 ] = 0x1 ;
275+ dump_calibration_data ( ) ;
276+ } else {
277+ Subcommand ( 0x03 , new byte [ ] { 0x3f } , 1 , false ) ;
278+
279+ a = Enumerable . Repeat ( ( byte ) 0 , 64 ) . ToArray ( ) ;
280+ Console . WriteLine ( "Using USB." ) ;
281+
282+ a [ 0 ] = 0x80 ;
283+ a [ 1 ] = 0x01 ;
284+ HIDapi . hid_write ( handle , a , new UIntPtr ( 2 ) ) ;
285+ HIDapi . hid_read ( handle , a , new UIntPtr ( 64 ) ) ;
286+
287+ if ( a [ 2 ] != 0x3 ) {
288+ PadMacAddress = new PhysicalAddress ( new byte [ ] { a [ 9 ] , a [ 8 ] , a [ 7 ] , a [ 6 ] , a [ 5 ] , a [ 4 ] } ) ;
289+ }
290+
291+ // USB Pairing
292+ a = Enumerable . Repeat ( ( byte ) 0 , 64 ) . ToArray ( ) ;
293+ a [ 0 ] = 0x80 ; a [ 1 ] = 0x02 ; // Handshake
294+ HIDapi . hid_write ( handle , a , new UIntPtr ( 2 ) ) ;
295+
296+ a [ 0 ] = 0x80 ; a [ 1 ] = 0x03 ; // 3Mbit baud rate
297+ HIDapi . hid_write ( handle , a , new UIntPtr ( 2 ) ) ;
298+
299+ a [ 0 ] = 0x80 ; a [ 1 ] = 0x02 ; // Handshake at new baud rate
300+ HIDapi . hid_write ( handle , a , new UIntPtr ( 2 ) ) ;
301+
302+ a [ 0 ] = 0x80 ; a [ 1 ] = 0x04 ; // Prevent HID timeout
303+ HIDapi . hid_write ( handle , a , new UIntPtr ( 2 ) ) ;
304+
305+ dump_calibration_data ( ) ;
306+ }
307+
285308 a [ 0 ] = leds_ ;
286309 Subcommand ( 0x30 , a , 1 ) ;
287310 Subcommand ( 0x40 , new byte [ ] { ( imu_enabled ? ( byte ) 0x1 : ( byte ) 0x0 ) } , 1 , true ) ;
288311 Subcommand ( 0x3 , new byte [ ] { 0x30 } , 1 , true ) ;
289312 Subcommand ( 0x48 , new byte [ ] { 0x1 } , 1 , true ) ;
313+
314+ if ( ! isUSB )
315+ Subcommand ( 0x41 , new byte [ ] { 0x03 , 0x00 , 0x00 , 0x01 } , 4 , false ) ; // higher gyro performance rate
316+
290317 DebugPrint ( "Done with init." , DebugType . COMMS ) ;
318+
319+ HIDapi . hid_set_nonblocking ( handle , 1 ) ;
320+
291321 return 0 ;
292322 }
323+
293324 public void SetFilterCoeff ( float a ) {
294325 filterweight = a ;
295326 }
327+
296328 public void Detach ( ) {
297329 stop_polling = true ;
298330 PrintArray ( max , format : "Max {0:S}" , d : DebugType . IMU ) ;
@@ -301,13 +333,21 @@ public void Detach() {
301333 //Subcommand(0x30, new byte[] { 0x0 }, 1); // Turn off LEDS after pair
302334 Subcommand ( 0x40 , new byte [ ] { 0x0 } , 1 ) ;
303335 Subcommand ( 0x48 , new byte [ ] { 0x0 } , 1 ) ;
336+
337+ if ( isUSB ) {
338+ byte [ ] a = Enumerable . Repeat ( ( byte ) 0 , 64 ) . ToArray ( ) ;
339+ a [ 0 ] = 0x80 ; a [ 1 ] = 0x05 ; // Allow device to talk to BT again
340+ HIDapi . hid_write ( handle , a , new UIntPtr ( 2 ) ) ;
341+ }
342+
304343 //Subcommand(0x3, new byte[] { 0x3f }, 1); // Turn on basic HID mode - not needed
305344 }
306345 if ( state > state_ . DROPPED ) {
307346 HIDapi . hid_close ( handle ) ;
308347 }
309348 state = state_ . NOT_ATTACHED ;
310349 }
350+
311351 private byte ts_en ;
312352 private byte ts_de ;
313353 private System . DateTime ts_prev ;
@@ -328,6 +368,7 @@ private int ReceiveRaw() {
328368 }
329369 return ret ;
330370 }
371+
331372 private Thread PollThreadObj ;
332373 private void Poll ( ) {
333374 int attempts = 0 ;
@@ -362,23 +403,19 @@ public void Update() {
362403 rep . CopyBuffer ( report_buf ) ;
363404 }
364405 if ( imu_enabled ) {
365- if ( do_localize ) {
366- ProcessIMU ( report_buf ) ;
367- } else {
368- ExtractIMUValues ( report_buf , 0 ) ;
369- // 3 values for 5ms precision instead of 15ms
370- /*for (int n = 0; n < 3; n++) {
371- ExtractIMUValues(report_buf, n);
372-
373- Timestamp = rep.ts + (ulong) n * 5000; // 5ms difference
374-
375- if (n == 0)
376- ProcessButtonsAndStick(report_buf);
377-
378- packetCounter++;
379- Program.server.NewReportIncoming(this);
380- }*/
381- }
406+ ExtractIMUValues ( report_buf , 0 ) ;
407+ // 3 values for 5ms precision instead of 15ms
408+ /*for (int n = 0; n < 3; n++) {
409+ ExtractIMUValues(report_buf, n);
410+
411+ Timestamp = rep.ts + (ulong) n * 5000; // 5ms difference
412+
413+ if (n == 0)
414+ ProcessButtonsAndStick(report_buf);
415+
416+ packetCounter++;
417+ Program.server.NewReportIncoming(this);
418+ }*/
382419 }
383420 if ( ts_de == report_buf [ 1 ] ) {
384421 DebugPrint ( string . Format ( "Duplicate timestamp dequeued. TS: {0:X2}" , ts_de ) , DebugType . THREADING ) ;
@@ -483,90 +520,27 @@ private void ExtractIMUValues(byte[] report_buf, int n = 0) {
483520 else
484521 offset = right_hor_offset ;
485522
486- //Console.WriteLine("{0} {1} {2}", gyr_r[0], gyr_r[1], gyr_r[2]);
487-
488523 for ( int i = 0 ; i < 3 ; ++ i ) {
489524 switch ( i ) {
490525 case 0 :
491526 acc_g . X = ( acc_r [ i ] - offset [ i ] ) * ( 1.0f / ( acc_sensiti [ i ] - acc_neutral [ i ] ) ) * 4.0f ;
492- gyr_g . X = gyr_r [ i ] * ( 816.0f / ( gyr_sensiti [ i ] - gyr_neutral [ i ] ) ) ;
527+ gyr_g . X = ( gyr_r [ i ] - gyr_neutral [ i ] ) * ( 816.0f / ( gyr_sensiti [ i ] - gyr_neutral [ i ] ) ) ;
493528
494529 break ;
495530 case 1 :
496531 acc_g . Y = ( acc_r [ i ] - offset [ i ] ) * ( 1.0f / ( acc_sensiti [ i ] - acc_neutral [ i ] ) ) * 4.0f ;
497- gyr_g . Y = - gyr_r [ i ] * ( 816.0f / ( gyr_sensiti [ i ] - gyr_neutral [ i ] ) ) ;
532+ gyr_g . Y = - ( gyr_r [ i ] - gyr_neutral [ i ] * 0.5f ) * ( 816.0f / ( gyr_sensiti [ i ] - gyr_neutral [ i ] ) ) ;
498533
499534 break ;
500535 case 2 :
501536 acc_g . Z = ( acc_r [ i ] - offset [ i ] ) * ( 1.0f / ( acc_sensiti [ i ] - acc_neutral [ i ] ) ) * 4.0f ;
502- gyr_g . Z = - gyr_r [ i ] * ( 816.0f / ( gyr_sensiti [ i ] - gyr_neutral [ i ] ) ) ;
537+ gyr_g . Z = - ( gyr_r [ i ] - gyr_neutral [ i ] ) * ( 816.0f / ( gyr_sensiti [ i ] - gyr_neutral [ i ] ) ) ;
503538
504539 break ;
505540 }
506541 }
507542 }
508543
509- private float err ;
510- public Vector3 i_b , j_b , k_b , k_acc ;
511- private Vector3 d_theta ;
512- private Vector3 i_b_ ;
513- private Vector3 w_a , w_g ;
514- private Quaternion vec ;
515-
516- private int ProcessIMU ( byte [ ] report_buf ) {
517-
518- // Direction Cosine Matrix method
519- // http://www.starlino.com/dcm_tutorial.html
520-
521- if ( ! imu_enabled | state < state_ . IMU_DATA_OK )
522- return - 1 ;
523-
524- if ( report_buf [ 0 ] != 0x30 ) return - 1 ; // no gyro data
525-
526- // read raw IMU values
527- int dt = ( report_buf [ 1 ] - timestamp ) ;
528- if ( report_buf [ 1 ] < timestamp ) dt += 0x100 ;
529-
530- for ( int n = 0 ; n < 3 ; ++ n ) {
531- ExtractIMUValues ( report_buf , n ) ;
532-
533- float dt_sec = 0.005f * dt ;
534- sum [ 0 ] += gyr_g . X * dt_sec ;
535- sum [ 1 ] += gyr_g . Y * dt_sec ;
536- sum [ 2 ] += gyr_g . Z * dt_sec ;
537-
538- if ( isLeft && ! isPro ) { // not sure about this
539- gyr_g . Y *= - 1 ;
540- gyr_g . Z *= - 1 ;
541- acc_g . Y *= - 1 ;
542- acc_g . Z *= - 1 ;
543- }
544-
545- if ( first_imu_packet ) {
546- i_b = new Vector3 ( 1 , 0 , 0 ) ;
547- j_b = new Vector3 ( 0 , 1 , 0 ) ;
548- k_b = new Vector3 ( 0 , 0 , 1 ) ;
549- first_imu_packet = false ;
550- } else {
551- k_acc = - Vector3 . Normalize ( acc_g ) ;
552- w_a = Vector3 . Cross ( k_b , k_acc ) ;
553- w_g = - gyr_g * dt_sec ;
554- d_theta = ( filterweight * w_a + w_g ) / ( 1f + filterweight ) ;
555- k_b += Vector3 . Cross ( d_theta , k_b ) ;
556- i_b += Vector3 . Cross ( d_theta , i_b ) ;
557- j_b += Vector3 . Cross ( d_theta , j_b ) ;
558- //Correction, ensure new axes are orthogonal
559- err = Vector3 . Dot ( i_b , j_b ) * 0.5f ;
560- i_b_ = Vector3 . Normalize ( i_b - err * j_b ) ;
561- j_b = Vector3 . Normalize ( j_b - err * i_b ) ;
562- i_b = i_b_ ;
563- k_b = Vector3 . Cross ( i_b , j_b ) ;
564- }
565- dt = 1 ;
566- }
567- timestamp = report_buf [ 1 ] + 2 ;
568- return 0 ;
569- }
570544 public void Begin ( ) {
571545 if ( PollThreadObj == null ) {
572546 PollThreadObj = new Thread ( new ThreadStart ( Poll ) ) ;
@@ -575,10 +549,12 @@ public void Begin() {
575549 Console . WriteLine ( "Starting poll thread." ) ;
576550 }
577551 }
552+
578553 public void Recenter ( ) {
579554 first_imu_packet = true ;
580555 }
581- private float [ ] CenterSticks ( UInt16 [ ] vals , bool special = false ) {
556+
557+ private float [ ] CenterSticks ( UInt16 [ ] vals , bool special = false ) {
582558 ushort [ ] t = stick_cal ;
583559
584560 if ( special )
@@ -597,12 +573,14 @@ private float[] CenterSticks(UInt16[] vals, bool special=false) {
597573 }
598574 return s ;
599575 }
576+
600577 public void SetRumble ( float low_freq , float high_freq , float amp , int time = 0 ) {
601578 if ( state <= Joycon . state_ . ATTACHED ) return ;
602579 if ( rumble_obj . timed_rumble == false || rumble_obj . t < 0 ) {
603580 rumble_obj = new Rumble ( low_freq , high_freq , amp , time ) ;
604581 }
605582 }
583+
606584 private void SendRumble ( byte [ ] buf ) {
607585 byte [ ] buf_ = new byte [ report_len ] ;
608586 buf_ [ 0 ] = 0x10 ;
@@ -613,6 +591,7 @@ private void SendRumble(byte[] buf) {
613591 PrintArray ( buf_ , DebugType . RUMBLE , format : "Rumble data sent: {0:S}" ) ;
614592 HIDapi . hid_write ( handle , buf_ , new UIntPtr ( report_len ) ) ;
615593 }
594+
616595 private byte [ ] Subcommand ( byte sc , byte [ ] buf , uint len , bool print = true ) {
617596 byte [ ] buf_ = new byte [ report_len ] ;
618597 byte [ ] response = new byte [ report_len ] ;
@@ -630,6 +609,7 @@ private byte[] Subcommand(byte sc, byte[] buf, uint len, bool print = true) {
630609 else if ( print ) { PrintArray ( response , DebugType . COMMS , report_len - 1 , 1 , "Response ID 0x" + string . Format ( "{0:X2}" , response [ 0 ] ) + ". Data: 0x{0:S}" ) ; }
631610 return response ;
632611 }
612+
633613 private void dump_calibration_data ( ) {
634614 byte [ ] buf_ = ReadSPI ( 0x80 , ( isLeft ? ( byte ) 0x12 : ( byte ) 0x1d ) , 9 ) ; // get user calibration data if possible
635615 bool found = false ;
@@ -730,6 +710,7 @@ private void dump_calibration_data() {
730710 PrintArray ( gyr_neutral , len : 3 , d : DebugType . IMU , format : "Factory gyro neutral position: {0:S}" ) ;
731711 }
732712 }
713+
733714 private byte [ ] ReadSPI ( byte addr1 , byte addr2 , uint len , bool print = false ) {
734715 byte [ ] buf = { addr2 , addr1 , 0x00 , 0x00 , ( byte ) len } ;
735716 byte [ ] read_buf = new byte [ len ] ;
@@ -745,6 +726,7 @@ private byte[] ReadSPI(byte addr1, byte addr2, uint len, bool print = false) {
745726 if ( print ) PrintArray ( read_buf , DebugType . COMMS , len ) ;
746727 return read_buf ;
747728 }
729+
748730 private void PrintArray < T > ( T [ ] arr , DebugType d = DebugType . NONE , uint len = 0 , uint start = 0 , string format = "{0:S}" ) {
749731 if ( d != debug_type && debug_type != DebugType . ALL ) return ;
750732 if ( len == 0 ) len = ( uint ) arr . Length ;
0 commit comments