
#ifndef USBJOYSTICK_H_INCLUDED
#define USBJOYSTICK_H_INCLUDED



#include "usb.h"
#include "usbhid.h"
#include "usbrdesc.h"
#include "binding.h"    // joy_binding, JB_MAX_BINDINGS - the mapping source of truth


// silence compiler warnings about unused parameters
#define IGNORE(x) do { (void)(x); } while(0)

// Vector readability
#define VECTOR_PASSON 1
#define VECTOR_CLAIM 0

// Boolean constants
#ifndef TRUE
#define TRUE  1
#endif
#ifndef FALSE
#define FALSE 0
#endif



#define NOT_MAPPED      -1000
#define NONE_AVAILABLE  -1



#define JOY_MAX               8
#define JOY_BUTTONS          32
#define JOY_USAGE_AXES       16
#define JOY_AXES             20
#define JOY_NAME_LEN         20
#define JOY_MAX_DATA_LENGTH  64


// our axes types: note that we must not use 0
#define AXIS_START    1

#define AXIS_HATX     1
#define AXIS_HATY     2
#define AXIS_DPADX    3
#define AXIS_DPADY    4
#define AXIS_X        5
#define AXIS_Y        6
#define AXIS_Z        7
#define AXIS_RX       8
#define AXIS_RY       9
#define AXIS_RZ       10
#define AXIS_SLIDER   11

#define AXIS_END      11



struct axisdata_struct
{
  int32_t    val;
  int32_t    min;
  int32_t    mid;
  int32_t    max;
  // risc os additions:
  uint32_t   acorn_slope_8;
  int     acorn_slope_div_8;
  uint32_t   acorn_slope_16;
  int     acorn_slope_div_16;
  uint32_t   pc_slope;
  int     pc_slope_div;
  int32_t    serial_port_upper_bound;
  int32_t    serial_port_lower_bound;
  int     is_digital;
  char       *name;
  int     flip;
  uint32_t   type;          // todo: make a type/enum for this?
  uint32_t   mouse_factor;
};



struct joydata_struct
{
  uint32_t                 report_length;
  int                   has_report_id;  // indicates if first data byte is the reportid
  char                     *data_buf;      // only for the report id+data
  struct hid_item          *axes_items[JOY_USAGE_AXES];  // only analogue axes
  struct hid_item          *button_items[JOY_BUTTONS];
  struct hid_item          *hat_item;
  struct hid_item          *dpad_up_item;
  struct hid_item          *dpad_down_item;
  struct hid_item          *dpad_left_item;
  struct hid_item          *dpad_right_item;
  int                   has_dpad;
  int                   has_hat;
  uint32_t                 hat_axis;   // if we have one, this is the x (y will be next)
  uint32_t                 dpad_axis;  // if we have one, this is the x (y will be next)
  uint32_t                 num_axes;
  uint32_t                 num_buttons;
  struct axisdata_struct   axes[JOY_AXES];
  uint32_t                 buttons[JOY_BUTTONS];
  // risc os additions follow:
  struct joy_device_struct *device;
  int                   in_use;
  int                   open;
  char                     device_name[USB_DEVICE_NAME_LENGTH];
  uint8_t                  interface;
  uint8_t                  endpoint;
  char                     usb_path[USB_DEVICEFS_PATH_MAX_LENGTH];
  int                    fp;
  int                      buffer_handle;
  int                      buffer_internal_id;
  void                     *buffer_service_routine;
  void                     *buffer_workspace;
  uint32_t                 devicefs_handle;
  uint32_t                 upcalls;
  uint32_t                 upcalls_delta;
  char                     manufacturer[USB_MAX_STRING_LEN];
  char                     product[USB_MAX_STRING_LEN];
  char                     serial[USB_MAX_STRING_LEN];
  uint32_t                 vendor_id;
  uint32_t                 product_id;
  uint32_t                 device_id;
  uint32_t                 good_reads;
  uint32_t                 good_reads_delta;
  uint32_t                 bad_reads;
  uint32_t                 bad_reads_delta;
  int32_t                  mapped_number;
  int32_t                  mapped_x_8;
  int32_t                  mapped_y_8;
  int32_t                  mapped_x_16;
  int32_t                  mapped_y_16;
  uint32_t                 mapped_buttons[JOY_BUTTONS];
  int32_t                  mapped_mouse_x;
  int32_t                  mapped_mouse_y;
  int32_t                  mapped_mouse_select;
  int32_t                  mapped_mouse_menu;
  int32_t                  mapped_mouse_adjust;
  int32_t                  key_up;
  int32_t                  key_down;
  int32_t                  key_left;
  int32_t                  key_right;
  int32_t                  key_buttons[JOY_BUTTONS];
  // The binding table: editable/serialisable source of truth. binding_compile()
  // expands it into the resolved fields above (see h.binding).
  joy_binding              bindings[JB_MAX_BINDINGS];
  uint32_t                 num_bindings;
  // TRUE while the table above is exactly what auto_map() last generated;
  // set TRUE there, cleared by any explicit mutator (binding_write/_add/
  // _clear/_remove) so it reflects whether this slot has ever diverged from
  // its default mapping. Surfaced as joystick_mapping.automap.
  int                      automap;
};



// the following will be initialised elsewhere

extern uint32_t joy_slot;        // which slot is currently being set up
extern uint32_t joy_generation;  // bumped on every attach/detach - see Joystick_Enumerate
extern uint32_t axis_max;
extern struct joydata_struct joy_data[];

// No emulate_acorn_on - Joystick_Read/CalibrateTopRight/CalibrateBottomLeft are always active, see h.joyswis.
extern int emulate_serial_port_on;
extern int emulate_joy_on;

// Global output gates, independent of the binding table - see h.joyswis
// (Joystick_Control) and c.mouse, c.keys. Default off.
extern int mouse_control_on;
extern int keyboard_control_on;

extern int bytev_claimed;
extern int upcall_claimed;
extern int ukswiv_claimed;

extern void* g_module_pw;



// Errors
//
// kernel.h defines: ErrorBase_Joystick as &43F40  (Acorn's error?)
//
// Message tokens are looked up via MessageTrans against this control
// block - see h.errors and c.errors for the actual error definitions.

extern int messages[4];



_kernel_oserror *module_initialise(const char *cmd_tail, int32_t podule_base, void *pw);
_kernel_oserror *module_finalise(int32_t fatal, int32_t podule, void *pw);
_kernel_oserror *module_swi(int32_t swi_offset, _kernel_swi_regs *r, void *pw);

#endif
