
#ifndef JOYSWIS_H_INCLUDED
#define JOYSWIS_H_INCLUDED

#include "usbjoystick.h"   // JOY_AXES, JOY_BUTTONS, joydata_struct
#include "adc.h"           // ADC_CHANNELS, ADC_BUTTONS


// The SWI configuration is set up to match the Acorn standard
#define USBJoystickSWI_Base  0x43F40
#define USBJoystickSWI_Name  Joystick

#define MODULE_SWI(name) (name - USBJoystickSWI_Base)


// this is only needed to work around CMHG not defining it
// because the standard RISC OS headers define Joystick_Read (base)
#define Joystick_Status                 0x043f43

// Same workaround, for every native SWI added in the revamp - CMHG's
// swi-decoding-table only builds the string table OS_SWINumberFromString/
// ToString use; it does NOT generate C-level constants for switch/case
// use in module_swi(), even for names listed there. Only genuinely
// pre-registered SWIs (like Read/CalibrateTopRight/CalibrateBottomLeft
// above) get that for free from standard headers. Offsets must match the
// order these names appear in cmhg.USBJoystickHdr's swi-decoding-table.
#define Joystick_Enumerate              (USBJoystickSWI_Base + 4)
#define Joystick_DeviceInfo             (USBJoystickSWI_Base + 5)
#define Joystick_AxisInfo               (USBJoystickSWI_Base + 6)
#define Joystick_AxisValues             (USBJoystickSWI_Base + 7)
#define Joystick_GetMapping             (USBJoystickSWI_Base + 8)
// Assign a device to a legacy Joystick_Read stick number (a device attribute,
// not a binding - see c.cmdmap).
#define Joystick_SetStick               (USBJoystickSWI_Base + 9)

// R0 selects which classic API's emulation flag to touch; R1 is the same
// -1 (query) / 0 (off) / 1 (on) convention every Emulate* used
// individually before. One request/response shape regardless of R0's
// value - a legitimate use of a selector register, unlike the old
// Joystick_Read reason 2/3/4 experiment below, where different reasons
// returned different response *shapes*.
//
// No Acorn selector: Joystick_Read/CalibrateTopRight/CalibrateBottomLeft
// are always active once this module is loaded. Unlike the three below,
// which each trap something that could genuinely belong to other real
// hardware or another module (Serial Port/Joy via UKSWIV raw numbers,
// ADC via ByteV/OSBYTE), Joystick_Read is this module's own registered
// SWI chunk - there's no "get out of the way" scenario for it to serve,
// since nothing else could legitimately be answering it instead.
#define Joystick_Emulate                (USBJoystickSWI_Base + 10)

// Config-store persistence (see doc.Config, c.config). Offsets must match
// the order these names appear in cmhg.USBJoystickHdr's swi-decoding-table.
#define Joystick_SaveMapping            (USBJoystickSWI_Base + 11)
// "Default map" = the mapping auto-generated from a device's own shape (what
// the internal auto_map() computes) - named for what it IS in this generic
// API, not for that internal function.
#define Joystick_RevertToDefaultMap     (USBJoystickSWI_Base + 12)
#define Joystick_ReloadConfig           (USBJoystickSWI_Base + 13)

// Binding-table API (see h.binding, c.binding). Offsets must match the order
// these names appear in cmhg.USBJoystickHdr's swi-decoding-table.
#define Joystick_ReadBindings           (USBJoystickSWI_Base + 14)
#define Joystick_WriteBindings          (USBJoystickSWI_Base + 15)
#define Joystick_AddBinding             (USBJoystickSWI_Base + 16)

// Read-only preview of what Joystick_RevertToDefaultMap would produce,
// without touching live state, the config store, or any other slot - lets a
// caller reset a not-yet-applied draft mapping (e.g. JoySetup's Default
// button) so a subsequent Cancel can still discard it.
#define Joystick_ReadDefaultBindings    (USBJoystickSWI_Base + 17)

// Global output gates - independent of the binding table, and off by
// default. A device can have mouse/key bindings configured (so they're
// ready to go) without those bindings actually driving anything until the
// matching gate here is turned on; turning a gate off releases anything it
// currently holds (see c.mouse, c.keys). Deliberately a SEPARATE SWI from
// Joystick_Emulate: Emulate is about impersonating a CLASSIC pre-USB
// joystick API (Serial Port/Joy/ADC) for old software; this is about the
// module's own NATIVE mouse/keyboard output, which isn't emulating any
// RISC OS API at all - just directly driving the pointer/keyboard, the same
// way a real mouse or keyboard does.
#define Joystick_Control                (USBJoystickSWI_Base + 18)

// Persist the module-wide settings (currently: the Emulate + Control gates)
// to the config store's [global] section - see doc.Config. Independent of
// Joystick_SaveMapping, which only ever touches one device's own section,
// so the two can never clash over the same part of the file.
#define Joystick_SaveSettings           (USBJoystickSWI_Base + 19)

#define JOYSTICK_EMULATE_SERIALPORT   0
#define JOYSTICK_EMULATE_JOY          1
#define JOYSTICK_EMULATE_ADC          2

// Separate enum from JOYSTICK_EMULATE_* on purpose (see Joystick_Control
// above) even though the numbers overlap - the two SWIs have independent R0
// namespaces, and using different names keeps them from being confused at
// the call site.
#define JOYSTICK_CONTROL_MOUSE        0
#define JOYSTICK_CONTROL_KEYBOARD     1


#define ACORN_SWI_READ_REASON_8            0
#define ACORN_SWI_READ_REASON_16           1

#define ACORN_AXIS_VALUES_8             255
#define ACORN_AXIS_MIN_VALUE_8         -127
#define ACORN_AXIS_MAX_VALUE_8          127
#define ACORN_AXIS_HAT_SCALE_8           64
#define ACORN_REST_8                      0

#define ACORN_BUTTONS   32

#define ACORN_AXIS_VALUES_16            65536
#define ACORN_AXIS_MIN_VALUE_16             0
#define ACORN_AXIS_MAX_VALUE_16         65535
#define ACORN_AXIS_HAT_MIN_16           12288
#define ACORN_AXIS_HAT_MID_16           32768
#define ACORN_AXIS_HAT_MAX_16           53247
#define ACORN_AXIS_MID_VALUE_16         32768   // single-axis centre; an unmapped 16-bit axis rests here
#define ACORN_AXES_REST_16              (int)0x80008000
#define ACORN_BUTTONS_REST_16           0


// Capability bits for joystick_device_info.capabilities. Bits beyond
// JOYCAP_RUMBLE are reserved (always 0 for now) rather than left
// undefined, so LED/battery/etc support in a later phase can populate an
// already-agreed bit instead of needing a new response shape.
#define JOYCAP_RUMBLE    (1u << 0)
#define JOYCAP_LED       (1u << 1)
#define JOYCAP_BATTERY   (1u << 2)
#define JOYCAP_TOUCHPAD  (1u << 3)
#define JOYCAP_SENSORS   (1u << 4)

struct joystick_device_info {
  uint32_t size;
  char     *manufacturer;
  char     *product;
  char     *serial;           // "" if the device has no real iSerialNumber
  uint32_t vendor_id;
  uint32_t product_id;
  uint32_t num_axes;
  uint32_t num_buttons;
  uint32_t num_hats;           // count of HAT/D-pad style controls (0-2)
  uint32_t capabilities;       // JOYCAP_* bitfield
  uint8_t  guid[16];           // SDL-style synthesised identity - see joyapi_build_guid()
};

struct joystick_axis_info {
  uint32_t hid_usage_page;    // raw HID usage page - transport-agnostic
  uint32_t hid_usage;         // vocabulary (see doc.APIs); 0 if not known
  uint32_t type;              // AXIS_* - our classification (handles multiple axes sharing one HID usage, e.g. dual sticks)
  char     *name;
  int32_t  min, mid, max;
  int   is_digital;        // synthesised HAT/D-pad axis (-1/0/1 only)
};

// One-shot snapshot of everything a device is currently mapped to, in the
// resolved (decoded) form - one "get everything" read, as opposed to the
// binding table which Joystick_ReadBindings returns as editable records.
struct joystick_mapping {
  int32_t  legacy_stick_number;         // NOT_MAPPED if none

  int32_t  axes8_x, axes8_y;            // axis index, or NOT_MAPPED
  int32_t  axes16_x, axes16_y;

  int32_t  buttons[JOY_BUTTONS];        // positional button map
  uint32_t num_buttons_mapped;

  int32_t  adc_channel[ADC_CHANNELS];       // axis index mapped to this
  int32_t  adc_channel_start[ADC_CHANNELS]; // channel, or NOT_MAPPED
  int32_t  adc_channel_end[ADC_CHANNELS];
  int32_t  adc_fire[ADC_BUTTONS];

  int32_t  mouse_x, mouse_y;
  int32_t  mouse_select, mouse_menu, mouse_adjust;
  int   mouse_control_active;

  int32_t  key_up, key_down, key_left, key_right;
  int32_t  key_buttons[JOY_BUTTONS];

  int   automap;
};


_kernel_oserror* swi_joystick_read(_kernel_swi_regs *r);
_kernel_oserror* joystick_read_acorn_8(_kernel_swi_regs *r, uint32_t i);
_kernel_oserror* joystick_read_acorn_16(_kernel_swi_regs *r, uint32_t i);

int32_t scaled_value_8(struct axisdata_struct *a);
int32_t scaled_value_16(struct axisdata_struct *a);
int32_t scaled_value_pc(struct axisdata_struct *a);


_kernel_oserror* swi_joystick_status(_kernel_swi_regs *r);
uint32_t encode_stick_serial_port(int32_t i);


_kernel_oserror* swi_joystick_enumerate(_kernel_swi_regs *r);
_kernel_oserror* swi_joystick_device_info(_kernel_swi_regs *r);
_kernel_oserror* swi_joystick_axis_info(_kernel_swi_regs *r);
_kernel_oserror* swi_joystick_axis_values(_kernel_swi_regs *r);
_kernel_oserror* swi_joystick_get_mapping(_kernel_swi_regs *r);

void joyapi_build_guid(uint32_t slot, uint8_t guid[16]);
uint32_t joyapi_capabilities(uint32_t slot);

#endif
