 REM >"Acorn2Test"

 REM This program exercises the native slot-based introspection API (see
 REM doc.APIs section 5): Joystick_Enumerate, Joystick_DeviceInfo,
 REM Joystick_AxisInfo, Joystick_AxisValues and Joystick_GetMapping - real
 REM SWIs, called here by name so this test tracks any future renumbering
 REM automatically.

 REM A "slot" is the raw USB attachment order (0..JOY_MAX-1, see
 REM h.usbjoystick) - not a stick number.

 ON ERROR REPORT : PRINT " at line ";ERL : END

 REM Constants mirrored from h.usbjoystick and h.adc - keep in step if
 REM those ever change.
 JOY_MAX% = 8
 JOY_BUTTONS% = 32
 ADC_CHANNELS% = 4
 ADC_BUTTONS% = 2
 UNMAPPED% = -1000

 PRINT "*** Testing Joystick_Enumerate"
 SYS "Joystick_Enumerate" TO mask%,generation%
 PRINT "Slot mask: "; ~mask%; " (bit N set = slot N in use)   Generation: "; generation%
 PRINT

 IF mask% = 0 THEN PRINT "No joysticks currently attached - nothing more to test." : END

 PRINT "*** Testing Joystick_DeviceInfo on every in-use slot"
 FOR slot% = 0 TO JOY_MAX%-1
   IF (mask% AND (1 << slot%)) THEN PROCdeviceinfo(slot%)
 NEXT slot%
 PRINT

 PRINT "*** Testing Joystick_AxisInfo on every in-use slot"
 FOR slot% = 0 TO JOY_MAX%-1
   IF (mask% AND (1 << slot%)) THEN PROCaxisinfo(slot%)
 NEXT slot%
 PRINT

 PRINT "*** Testing Joystick_AxisValues on every in-use slot"
 FOR slot% = 0 TO JOY_MAX%-1
   IF (mask% AND (1 << slot%)) THEN PROCaxisvalues(slot%)
 NEXT slot%
 PRINT

 PRINT "*** Testing Joystick_GetMapping on every in-use slot"
 FOR slot% = 0 TO JOY_MAX%-1
   IF (mask% AND (1 << slot%)) THEN PROCgetmapping(slot%)
 NEXT slot%
 PRINT

 PRINT "*** All done"

 END




 REM struct joystick_device_info (h.joyswis) - size/manufacturer/product/
 REM serial/vendor_id/product_id/num_axes/num_buttons/num_hats/
 REM capabilities/guid[16], all naturally 4-byte aligned.
 DEF PROCdeviceinfo(slot%)
   LOCAL flags%, size%, d%, guidaddr%, guid$, b%

   SYS "Joystick_DeviceInfo",slot% TO flags%,size%,d%

   PRINT "---DeviceInfo slot "; slot%
   PRINT "Record size       : "; size%; " bytes"
   PRINT "Manufacturer      : "; FNstring0(d%!4)
   PRINT "Product           : "; FNstring0(d%!8)
   PRINT "Serial            : "; FNstring0(d%!12)
   PRINT "Vendor id         : "; ~d%!16
   PRINT "Product id        : "; ~d%!20
   PRINT "Number of axes    : "; d%!24
   PRINT "Number of buttons : "; d%!28
   PRINT "Number of hats    : "; d%!32
   PRINT "Capabilities      : "; ~d%!36; " (bit0=rumble bit1=LED bit2=battery bit3=touchpad bit4=sensors)"

   guidaddr% = d% + 40
   guid$ = ""
   FOR b% = 0 TO 15
     guid$ = guid$ + FNhex2(guidaddr%?b%)
   NEXT b%
   PRINT "GUID              : "; guid$

 ENDPROC




 REM struct joystick_axis_info (h.joyswis) - hid_usage_page/hid_usage/
 REM type/name/min/mid/max/is_digital, 32 bytes per record.
 DEF PROCaxisinfo(slot%)
   LOCAL flags%, size%, numaxes%, d%, a%, rec%

   SYS "Joystick_AxisInfo",slot% TO flags%,size%,numaxes%,d%

   PRINT "---AxisInfo slot "; slot%
   PRINT "Record size: "; size%; " bytes   Number of axes: "; numaxes%

   FOR a% = 0 TO numaxes%-1
     rec% = d% + (size% * a%)
     PRINT "  axis "; a%; ": HID page="; ~rec%!0; " usage="; ~rec%!4; " type="; rec%!8;
     PRINT " name="; FNstring0(rec%!12);
     PRINT " min="; rec%!16; " mid="; rec%!20; " max="; rec%!24;
     PRINT " digital="; rec%!28
   NEXT a%

 ENDPROC




 REM int32_t values[numaxes] plus a full button bitmask (h.joyswis).
 DEF PROCaxisvalues(slot%)
   LOCAL flags%, size%, numaxes%, d%, buttons%, a%

   SYS "Joystick_AxisValues",slot% TO flags%,size%,numaxes%,d%,buttons%

   PRINT "---AxisValues slot "; slot%
   PRINT "Number of axes: "; numaxes%; "   Buttons: "; ~buttons%; " as bin: "; FNbin(buttons%,32)

   FOR a% = 0 TO numaxes%-1
     PRINT "  axis "; a%; ": val="; d%!(size%*a%)
   NEXT a%

 ENDPROC




 REM struct joystick_mapping (h.joyswis) - offsets below follow that
 REM struct's field order exactly; keep both in step if it changes.
 DEF PROCgetmapping(slot%)
   LOCAL flags%, size%, m%, b%

   SYS "Joystick_GetMapping",slot% TO flags%,size%,m%

   PRINT "---GetMapping slot "; slot%
   PRINT "Record size            : "; size%; " bytes"
   PRINT "Legacy stick number    : "; FNmapped(m%!0)
   PRINT "8-bit  API axes  X/Y   : "; FNmapped(m%!4); " / "; FNmapped(m%!8)
   PRINT "16-bit API axes  X/Y   : "; FNmapped(m%!12); " / "; FNmapped(m%!16)

   PRINT "Mapped buttons ("; m%!148; " mapped):"
   FOR b% = 0 TO JOY_BUTTONS%-1
     IF (m%!(20+4*b%)) <> UNMAPPED% THEN PRINT "  classic bit "; b%; " <- physical button "; m%!(20+4*b%)
   NEXT b%

   PRINT "ADC channel mapping:"
   FOR b% = 0 TO ADC_CHANNELS%-1
     IF (m%!(152+4*b%)) <> UNMAPPED% THEN PRINT "  channel "; b%; " <- axis "; m%!(152+4*b%); "  range "; m%!(168+4*b%); " .. "; m%!(184+4*b%)
   NEXT b%

   PRINT "ADC fire buttons:"
   FOR b% = 0 TO ADC_BUTTONS%-1
     IF (m%!(200+4*b%)) <> UNMAPPED% THEN PRINT "  fire "; b%; " <- physical button "; m%!(200+4*b%)
   NEXT b%

   PRINT "Mouse mapping: X="; FNmapped(m%!208); " Y="; FNmapped(m%!212); " Select="; FNmapped(m%!216); " Menu="; FNmapped(m%!220); " Adjust="; FNmapped(m%!224)
   PRINT "Mouse control active   : "; (m%!228 <> 0)

   PRINT "Key mapping: Up="; FNmapped(m%!232); " Down="; FNmapped(m%!236); " Left="; FNmapped(m%!240); " Right="; FNmapped(m%!244)
   FOR b% = 0 TO JOY_BUTTONS%-1
     IF (m%!(248+4*b%)) <> UNMAPPED% THEN PRINT "  key button "; b%; " <- key code "; m%!(248+4*b%)
   NEXT b%

   PRINT "Automap                : "; (m%!376 <> 0)

 ENDPROC




 DEF FNstring0(s%)
 LOCAL s$
 WHILE ?s% : s$ += CHR$?s% : s% += 1 : ENDWHILE
 = s$




 DEF FNbin(b%,bits%)
   LOCAL b$
   b$=""
   FOR i%=bits%-1 TO 0 STEP -1
     IF ((b%>>i%) AND 1) THEN
       b$ = b$ + "1"
     ELSE
       b$ = b$ + "-"
     ENDIF
   NEXT i%
 =b$




 REM One byte as 2 hex digits, no leading "&".
 DEF FNhex2(byte%)
 = RIGHT$("0"+STR$~(byte% AND &FF),2)




 REM UNMAPPED% -> "unmapped", else the value as a string.
 DEF FNmapped(n%)
 IF n% = UNMAPPED% THEN = "unmapped" ELSE = STR$(n%)

