
#ifndef USBJOYSTICK_H_INCLUDED
#define USBJOYSTICK_H_INCLUDED



#include "usb.h"
#include "usbhid.h"
#include "usbrdesc.h"
#include "Joystick.h"   // Joystick_Axis_*, Joystick_NotMapped
#include "binding.h"    // joystick_binding, Joystick_Binding_Max - 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 NONE_AVAILABLE  -1



#define Joystick_MaxSlots     8
#define Joystick_MaxButtons   32
#define Joystick_MaxAxes      20

// Axis types run from Joystick_Axis_Start to Joystick_Axis_End (0 is never used)
#define Joystick_Axis_Start   1
#define Joystick_Axis_End     11

#define JOY_USAGE_AXES       16
#define JOY_NAME_LEN         20
#define JOY_MAX_DATA_LENGTH  64


struct axisdata_struct
{
  int32_t    val;
  int32_t    min;
  int32_t    mid;
  int32_t    max;
  // risc os additions:
  uint32_t   read8_slope;
  int     read8_slope_div;
  uint32_t   read16_slope;
  int     read16_slope_div;
  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     invert;
  uint32_t   type;          // todo: make a type/enum for this?
  uint32_t   mouse_factor;
};



// What is sent to a device, and what was last sent - see c.rumble.
struct joy_output_struct
{
  uint8_t    endpoint;        // interrupt OUT endpoint on the same interface, 0 if none
  int        fp;              // DeviceFS output stream, 0 until the first send
  uint16_t   rumble_low;      // strengths last sent
  uint16_t   rumble_high;
  uint32_t   rumble_stop_at;  // OS_ReadMonotonicTime deadline, 0 if none
  uint8_t    rumble_stop_tries;   // stops that have failed in a row
  uint8_t    rumble_stop_repeats; // resends of a stop still to make
  uint8_t    led_armed;       // the player LED has been set up for this connection
  uint8_t    led_sends_left;  // sends of the player LED still to make
  uint8_t    led_due;         // a send is waiting for the callback
  uint32_t   led_next;        // OS_ReadMonotonicTime of the next send
};



struct joydata_struct
{
  uint32_t                 report_length;
  int                   has_report_id;  // indicates if first data byte is the reportid
  uint8_t                  report_id;      // that report id, valid when has_report_id
  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[Joystick_MaxButtons];
  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[Joystick_MaxAxes];
  uint32_t                 buttons[Joystick_MaxButtons];
  // 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;
  struct joy_output_struct output;
  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[Joystick_MaxButtons];
  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[Joystick_MaxButtons];
  // The binding table: editable/serialisable source of truth. binding_compile()
  // expands it into the resolved fields above (see h.binding).
  joystick_binding              bindings[Joystick_Binding_Max];
  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.
  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 flag for the standard API - 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
