
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "swis.h"
#include "Global/RISCOS.h"
#include "Global/Keyboard.h"

#include "oslib/os.h"

#include "debugrep.h"
#include "usbjoystick.h"
#include "usbjoystickHdr.h"
#include "joyhelp.h"
#include "joyswis.h"
#include "mouse.h"
#include "adc.h"
#include "device.h"


#include "cmds.h"


_kernel_oserror *command_handler(const char *args, int32_t argc, int32_t cmdno, void *pw)
{
  IGNORE(pw);

  switch (cmdno) {
    case CMD_USBJoystick_Read:
      return command_read(args, argc);

    case CMD_USBJoystick_EmulateAcorn:
      return command_emulate_acorn(args, argc);

    case CMD_USBJoystick_EmulateSerialPort:
      return command_emulate_serial_port(args, argc);

    case CMD_USBJoystick_EmulateJoy:
      return command_emulate_joy(args, argc);

    case CMD_USBJoystick_EmulateADC:
      return command_emulate_adc(args, argc);

    case CMD_USBJoystick_List:
      return command_list(args, argc);

    case CMD_USBJoystick_MapStick:
      return command_map_stick(args, argc);

    case CMD_USBJoystick_MapAxes8:
      return command_map_axes(args, argc, FALSE);

    case CMD_USBJoystick_MapAxes16:
      return command_map_axes(args, argc, TRUE);

    case CMD_USBJoystick_MapADC:
      return command_map_adc(args, argc);

    case CMD_USBJoystick_MapButtons:
      return command_map_buttons(args, argc);

    case CMD_USBJoystick_MapADCButtons:
      return command_map_adc_buttons(args, argc);

    case CMD_USBJoystick_Flip:
      return command_flip(args, argc);

    case CMD_USBJoystick_Mapped:
      return command_mapped(args, argc);

    case CMD_USBJoystick_MapMouse:
      return command_map_mouse(args, argc);

    case CMD_USBJoystick_MouseControl:
      return command_mouse_control(args, argc);

    case CMD_USBJoystick_Debug:
      return command_debug(args, argc);

    case CMD_USBJoystick_KeyControls:
      return command_key_controls(args, argc);

    default:
      printf("Unimplemented command!\n");
  }

  return NULL;
}





_kernel_oserror *command_read(const char *args, int32_t argc)
{
  if (argc != 1) {
    debug_printf("command_read: Bad arguments, argc isn't 1 (it is %d)\n", argc);
    return &err_badnoparms;
  }

  os_error *error = NULL;
  uint32_t i;
  uint32_t ret = sscanf(args, "%d", &i);
  if (ret != 1) {
    debug_printf("command_read: Bad arguments, didn't read 1 arg (read %d)\n", ret);
    return &err_badnoparms;
  }

  if (i >= JOY_MAX) {
    debug_printf("command_read: Bad arguments, id (%d) is out of range\n", i);
    return &err_badnoparms;
  }

  if (!joy_data[i].in_use) {
    debug_printf("command_read: Joystick id (%d) isn't active\n", i);
    return &err_joynotactive;
  }

  if (!joy_data[i].open) {
    debug_printf("command_read: Joystick id (%d) isn't open\n", i);
    return &err_joynotopen;
  }

  debug_printf("command_read: i %u\n", i);

  printf("Joytstick id %u (%s - %s)\n", i, joy_data[i].manufacturer, joy_data[i].product);

  for (uint32_t a=0; a<joy_data[i].num_axes; a++) {
    printf("Axis %02d %6s : ", a, joy_data[i].axes[a].name);
    printf("Val %8d  ", joy_data[i].axes[a].val);
    printf("Min %8d  ", joy_data[i].axes[a].min);
    printf("Mid %8d  ", joy_data[i].axes[a].mid);
    printf("Max %8d  ", joy_data[i].axes[a].max);
    printf("Flip=");
    if (joy_data[i].axes[a].flip)
      printf("on");
    else
      printf("off");

    printf("\n");
  }

  printf("Buttons: ");
  for (uint32_t b=0; b<joy_data[i].num_buttons; b++) {
    printf("%u=%u ", b, joy_data[i].buttons[b]);
  }
  printf("\n");

  IGNORE(error);

  return NULL;
}




_kernel_oserror *command_key_controls(const char *args, int32_t argc)
{
  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id
  int32_t up = NOT_MAPPED;
  int32_t down = NOT_MAPPED;
  int32_t left = NOT_MAPPED;
  int32_t right = NOT_MAPPED;
  int32_t b[ACORN_BUTTONS];

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_key_controls: Bad arguments, id (%d) is out of range\n", id);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) up = atoi(t);

  t = strtok(NULL, s);
  if (t) down = atoi(t);

  t = strtok(NULL, s);
  if (t) left = atoi(t);

  t = strtok(NULL, s);
  if (t) right = atoi(t);

  uint32_t cmd_buttons = argc - 5;

  for (uint32_t i=0; i<ACORN_BUTTONS; i++) {
    if (i < cmd_buttons) {
      t = strtok(NULL, s);
      if (t) {
        b[i] = atoi(t);
      }
    }
    else {
      b[i] = NOT_MAPPED;
    }
  }
  if (!joy_data[id].in_use) {
    debug_printf("command_key_controls: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_key_controls: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // set up key mappings for this stick id
  joy_data[id].key_up = up;
  joy_data[id].key_down = down;
  joy_data[id].key_left = left;
  joy_data[id].key_right = right;

  for (int32_t j=0; j<ACORN_BUTTONS; j++) {
    joy_data[id].key_buttons[j] = b[j];
  }

  return NULL;
}






_kernel_oserror *command_mouse_control(const char *args, int32_t argc)
{
  IGNORE(argc);
  uint32_t i = JOY_MAX;

  osbool off = (strncmp(args, "off", 3) == 0);

  if (off) {
    // switch off control
    debug_printf("command_mouse_control: Switching off\n");
    mouse_joy = NOT_MAPPED;

    // ensure all mouse buttons are 'up'
    if (mouse_select)
      _swix(OS_CallAVector, _INR(0,1) | _IN(9), KeyV_KeyUp, KeyNo_LeftMouse, KEYV);

    if (mouse_menu)
      _swix(OS_CallAVector, _INR(0,1) | _IN(9), KeyV_KeyUp, KeyNo_CentreMouse, KEYV);

    if (mouse_adjust)
      _swix(OS_CallAVector, _INR(0,1) | _IN(9), KeyV_KeyUp, KeyNo_RightMouse, KEYV);
  }
  else {
    uint32_t ret = sscanf(args, "%d", &i);

    if (ret != 1) {
      debug_printf("command_mouse_control: Bad arguments, didn't read stick id\n", ret);
      return &err_badnoparms;
    }

    if (i >= JOY_MAX) {
      debug_printf("command_mouse_control: Bad arguments, id (%d) is out of range\n", i);
      return &err_badnoparms;
    }

    if (!joy_data[i].in_use) {
      debug_printf("command_mouse_control: Joystick id (%d) isn't active\n", i);
      return &err_joynotactive;
    }

    if (!joy_data[i].open) {
      debug_printf("command_mouse_control: Joystick id (%d) isn't open\n", i);
      return &err_joynotopen;
    }

    // switch on control

    // note current pointer type (to use in future pointer updates)
    os_error *getptr_e = xospointer_get(&initial_pointer_type);
    if (getptr_e)
      debug_printf("command_mouse_control: Error getting pointer type: %s\n", getptr_e->errmess);

    // todo: ONLY do this if the mouse x+y axes are mapped? buttons?
    debug_printf("command_mouse_control: Switching on (stick %u)\n", i);
    mouse_joy = i;
  }

  return NULL;
}






_kernel_oserror *command_map_mouse(const char *args, int32_t argc)
{
  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id
  uint32_t x = JOY_AXES;
  uint32_t y = JOY_AXES;
  uint32_t select = JOY_BUTTONS;
  uint32_t menu = JOY_BUTTONS;
  uint32_t adjust = JOY_BUTTONS;

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_map_mouse: Bad arguments, id (%d) is too big\n", id);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) x = atoi(t);
  if (x >= joy_data[id].num_axes) {
    debug_printf("command_map_mouse: Bad arguments, x (%d) is too big\n", x);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) y = atoi(t);
  if (y >= joy_data[id].num_axes) {
    debug_printf("command_map_mouse: Bad arguments, y (%d) is too big\n", y);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) select = atoi(t);
  if (select >= joy_data[id].num_buttons) {
    debug_printf("command_map_mouse: Bad arguments, select (%d) is too big\n", select);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) menu = atoi(t);
  if (menu >= joy_data[id].num_buttons) {
    debug_printf("command_map_mouse: Bad arguments, menu (%d) is too big\n", menu);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) adjust = atoi(t);
  if (adjust >= joy_data[id].num_buttons) {
    debug_printf("command_map_mouse: Bad arguments, adjust (%d) is too big\n", adjust);
    return &err_badnoparms;
  }

  if (!joy_data[id].in_use) {
    debug_printf("command_map_mouse: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_map_mouse: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // map
  joy_data[id].mapped_mouse_x = x;
  joy_data[id].mapped_mouse_y = y;
  joy_data[id].mapped_mouse_select = select;
  joy_data[id].mapped_mouse_menu = menu;
  joy_data[id].mapped_mouse_adjust = adjust;

  // todo: take in additional parameters (sensitivity + factor for x and y axes)

  IGNORE(argc);
  return NULL;
}





_kernel_oserror *command_map_buttons(const char *args, int32_t argc)
{
  if (argc < 2 || argc > 17) {
    debug_printf("command_map_buttons: Bad arguments, argc is less than 2 or greater than 17 (it is %d)\n", argc);
    return &err_badnoparms;
  }

  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id
  uint32_t b[ACORN_BUTTONS];

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_map_buttons: Bad arguments, id (%d) is out of range\n", id);
    return &err_badnoparms;
  }

  // read button numbers from remaining arguments
  uint32_t cmd_buttons = argc - 1;

  for (uint32_t i=0; i<cmd_buttons; i++) {
    // i is the mapped button number
    t = strtok(NULL, s);
    if (t) {
      uint32_t button = atoi(t);
      if (button >= JOY_BUTTONS) {
        debug_printf("command_map_buttons: Bad arguments, button (%d) is too big\n", button);
        return &err_badnoparms;
      }
      b[i] = button;
    }
  }

  if (!joy_data[id].in_use) {
    debug_printf("command_map_buttons: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_map_buttons: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // clear out ALL mappings for this number
  for (uint32_t i=0; i<ACORN_BUTTONS; i++)
    joy_data[id].mapped_buttons[i] = NOT_MAPPED;

  // map the supplied button list up
  for (uint32_t i=0; i<cmd_buttons; i++)
    joy_data[id].mapped_buttons[i] = b[i];

  return NULL;
}







_kernel_oserror *command_map_axes(const char *args, int32_t argc, osbool sixteenbit)
{
  if (argc != 3) {
    debug_printf("command_map_axes: Bad arguments, argc is not 3 (it is %d)\n", argc);
    return &err_badnoparms;
  }

  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id
  uint32_t x = JOY_AXES;
  uint32_t y = JOY_AXES;

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_map_axes: Bad arguments, id (%d) is too big\n", id);
    return &err_badnoparms;
  }

  // todo: limit x axis index to max axis for the particular joystick?
  t = strtok(NULL, s);
  if (t) x = atoi(t);
  if (x >= JOY_AXES) {
    debug_printf("command_map_axes: Bad arguments, x (%d) is too big\n", x);
    return &err_badnoparms;
  }

  // todo: limit y axis index to max axis for the particular joystick?
  t = strtok(NULL, s);
  if (t) y = atoi(t);
  if (y >= JOY_AXES) {
    debug_printf("command_map_axes: Bad arguments, y (%d) is too big\n", y);
    return &err_badnoparms;
  }

  if (!joy_data[id].in_use) {
    debug_printf("command_map_axes: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_map_axes: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // map these axes
  if (!sixteenbit) {
    joy_data[id].mapped_x_8 = x;
    joy_data[id].mapped_y_8 = y;
  }
  else {
    joy_data[id].mapped_x_16 = x;
    joy_data[id].mapped_y_16 = y;
  }

  return NULL;
}






_kernel_oserror *command_map_adc_buttons(const char *args, int32_t argc)
{
  // MapADCButtons <stick> <fire0> [<fire1>]

  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id
  uint32_t b[ADC_BUTTONS];

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_map_adc_buttons: Bad arguments, id (%d) is out of range\n", id);
    return &err_badnoparms;
  }

  // read button numbers from remaining arguments
  uint32_t cmd_buttons = argc - 1;

  for (uint32_t i=0; i<cmd_buttons; i++) {
    // i is the mapped button number
    t = strtok(NULL, s);
    if (t) {
      uint32_t button = atoi(t);
      if (button >= joy_data[id].num_buttons) {
        debug_printf("command_map_adc_buttons: Bad arguments, button %u (%u) is too big\n", i, button);
        return &err_badnoparms;
      }
      b[i] = button;
    }
  }

  if (!joy_data[id].in_use) {
    debug_printf("command_map_adc_buttons: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_map_adc_buttons: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // map the supplied button list up
  for (uint32_t i=0; i<cmd_buttons; i++) {
    adc_map.buttons[i].button = b[i];
    adc_map.buttons[i].joy_id = id;
  }

  return NULL;
}




_kernel_oserror *command_map_adc(const char *args, int32_t argc)
{
  // *USBJoystick_MapADC <channel> <stick id> <axis> [<start>] [<end>]

  const char s[2] = " ";
  char *t = NULL;

  uint32_t channel = 0;
  uint32_t id = JOY_MAX;          // the usb joystick id
  uint32_t axis = 0;
  int32_t start = 0;
  int32_t end = 0;

  t = strtok((char*)args, s);
  if (t) channel = atoi(t);
  if (channel >= ADC_CHANNELS) {
    debug_printf("command_map_adc: Bad arguments, channel (%u) is too big\n", channel);
    return &err_badnoparms;
  }

  id = atoi(strtok(NULL, s));
  if (id >= JOY_MAX) {
    debug_printf("command_map_adc: Bad arguments, stick id (%d) is too big\n", id);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) axis = atoi(t);
  if (axis >= joy_data[id].num_axes) {
    debug_printf("command_map_adc: Bad arguments, axis (%u) is too big\n", axis);
    return &err_badnoparms;
  }

  if (argc >= 4) {
    t = strtok(NULL, s);
    if (t) start = atoi(t);
    if (start < joy_data[id].axes[axis].min || start > joy_data[id].axes[axis].max) {
      debug_printf("command_map_adc: Bad arguments, start (%d) is out of range\n", start);
      return &err_badnoparms;
    }
  }
  else {
    start = joy_data[id].axes[axis].min;
  }

  if (argc >= 5) {
    t = strtok(NULL, s);
    if (t) end = atoi(t);
    if (end < joy_data[id].axes[axis].min || start > joy_data[id].axes[axis].max) {
      debug_printf("command_map_adc: Bad arguments, end (%d) is out of range\n", end);
      return &err_badnoparms;
    }
  }
  else {
    end = joy_data[id].axes[axis].max;
  }

  if (!joy_data[id].in_use) {
    debug_printf("command_map_adc: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_map_adc: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // all parameters are sane, so update map
  adc_map.channels[channel].joy_id = id;
  adc_map.channels[channel].axis = axis;
  if (end > start) {
    adc_map.channels[channel].start = start;
    adc_map.channels[channel].end = end;
    adc_map.channels[channel].flip = FALSE;
  }
  else {
    adc_map.channels[channel].end = start;
    adc_map.channels[channel].start = end;
    adc_map.channels[channel].flip = TRUE;
  }

  int32_t range = adc_map.channels[channel].end - adc_map.channels[channel].start;
  adc_map.channels[channel].slope_div = (range > ADC_AXIS_VALUES);

  if (adc_map.channels[channel].slope_div)
    adc_map.channels[channel].slope = round_up_down((float)range / (float)ADC_AXIS_VALUES);
  else
    adc_map.channels[channel].slope = round_up_down((float)ADC_AXIS_VALUES / (float)range);

  return NULL;
}



_kernel_oserror *command_flip(const char *args, int32_t argc)
{
  if (argc != 3) {
    debug_printf("command_flip: Bad arguments, argc is not 3 (it is %d)\n", argc);
    return &err_badnoparms;
  }

  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id
  uint32_t axis = JOY_AXES;

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_flip: Bad arguments, id (%d) is too big\n", id);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) axis = atoi(t);
  if (axis >= JOY_AXES) {
    debug_printf("command_flip: Bad arguments, axis (%d) is too big\n", axis);
    return &err_badnoparms;
  }

  // must have an on/off argument, so check if it's on or off
  t = strtok(NULL, s);
  osbool arg_on = (strncmp(t, "on", 2) == 0);
  osbool arg_off = (strncmp(t, "off", 3) == 0);

  if (!arg_on && !arg_off) {
    debug_printf("command_flip: Bad arguments, not on or off (it is %t)\n", argc);
    return &err_badnoparms;
  }

  debug_printf("command_flip: Setting flip on id %d, axis %d to %d\n", id, axis, arg_on);
  joy_data[id].axes[axis].flip = arg_on;

  return NULL;
}





_kernel_oserror *command_map_stick(const char *args, int32_t argc)
{
  if (argc != 2) {
    debug_printf("command_map_stick: Bad arguments, argc is not 2 (it is %d)\n", argc);
    return &err_badnoparms;
  }

  const char s[2] = " ";
  char *t = NULL;

  uint32_t id = JOY_MAX;      // the usb joystick id (0-based)
  int32_t number = JOY_MAX;           // the legacy api number (0-based)

  t = strtok((char*)args, s);
  if (t) id = atoi(t);
  if (id >= JOY_MAX) {
    debug_printf("command_map_stick: Bad arguments, id (%d) is too big\n", id);
    return &err_badnoparms;
  }

  t = strtok(NULL, s);
  if (t) number = atoi(t);
  if (number >= JOY_MAX) {
    debug_printf("command_map_stick: Bad arguments, number (%d) is out of range\n", number);
    return &err_badnoparms;
  }

  if (!joy_data[id].in_use) {
    debug_printf("command_map_stick: Joystick id (%d) isn't active\n", id);
    return &err_joynotactive;
  }

  if (!joy_data[id].open) {
    debug_printf("command_map_stick: Joystick id (%d) isn't open\n", id);
    return &err_joynotopen;
  }

  // clear out any other mappings for this number
  for (uint32_t i=0; i<JOY_MAX; i++) {
    if (joy_data[i].mapped_number == number) {
      joy_data[i].mapped_number = NOT_MAPPED;
    }
  }

  // map this one up
  joy_data[id].mapped_number = number;

  return NULL;
}










_kernel_oserror *command_emulate_acorn(const char *args, int32_t argc)
{
  if (argc == 0) {
    printf("EmulateAcorn is ");
    if (emulate_acorn_on)
      printf("on\n");
    else
      printf("off\n");
    return NULL;
  }

  // must have one argument, so check if it's on or off
  int32_t arg_on = (strncmp(args, "on", 2) == 0);
  int32_t arg_off = (strncmp(args, "off", 3) == 0);

  if (!arg_on && !arg_off) {
    debug_printf("EmulateAcorn: Bad argument - must be on or off\n");
    return &err_badnoparms;
  }

  if (arg_on && emulate_acorn_on) {
    debug_printf("EmulateAcorn: Bad argument - already on\n");
    return &err_badnoparms;
  }

  if (arg_off && !emulate_acorn_on) {
    debug_printf("EmulateAcorn: Bad argument - already off\n");
    return &err_badnoparms;
  }

  emulate_acorn_on = arg_on;
  return NULL;
}




_kernel_oserror *command_emulate_serial_port(const char *args, int32_t argc)
{
  if (argc == 0) {
    printf("EmulateSerialPort is ");
    if (emulate_serial_port_on)
      printf("on\n");
    else
      printf("off\n");
    return NULL;
  }

  // must have one argument, so check if it's on or off
  int32_t arg_on = (strncmp(args, "on", 2) == 0);
  int32_t arg_off = (strncmp(args, "off", 3) == 0);

  if (!arg_on && !arg_off) {
    debug_printf("EmulateSerialPort: Bad argument - must be on or off\n");
    return &err_badnoparms;
  }

  if (arg_on && emulate_serial_port_on) {
    debug_printf("EmulateSerialPort: Bad argument - already on\n");
    return &err_badnoparms;
  }

  if (arg_off && !emulate_serial_port_on) {
    debug_printf("EmulateSerialPort: Bad argument - already off\n");
    return &err_badnoparms;
  }

  emulate_serial_port_on = arg_on;
  return NULL;
}






_kernel_oserror *command_emulate_joy(const char *args, int32_t argc)
{
  if (argc == 0) {
    printf("EmulateJoy is ");
    if (emulate_joy_on)
      printf("on\n");
    else
      printf("off\n");
    return NULL;
  }

  // must have one argument, so check if it's on or off
  int32_t arg_on = (strncmp(args, "on", 2) == 0);
  int32_t arg_off = (strncmp(args, "off", 3) == 0);

  if (!arg_on && !arg_off) {
    debug_printf("EmulateJoy: Bad argument - must be on or off\n");
    return &err_badnoparms;
  }

  if (arg_on && emulate_joy_on) {
    debug_printf("EmulateJoy: Bad argument - already on\n");
    return &err_badnoparms;
  }

  if (arg_off && !emulate_joy_on) {
    debug_printf("EmulateJoy: Bad argument - already off\n");
    return &err_badnoparms;
  }

  emulate_joy_on = arg_on;
  return NULL;
}




_kernel_oserror *command_emulate_adc(const char *args, int32_t argc)
{
  if (argc == 0) {
    printf("EmulateADC is ");
    if (emulate_adc_on)
      printf("on\n");
    else
      printf("off\n");
    return NULL;
  }

  // must have one argument, so check if it's on or off
  int32_t arg_on = (strncmp(args, "on", 2) == 0);
  int32_t arg_off = (strncmp(args, "off", 3) == 0);

  if (!arg_on && !arg_off) {
    debug_printf("EmulateADC: Bad argument - must be on or off\n");
    return &err_badnoparms;
  }

  if (arg_on && emulate_adc_on) {
    debug_printf("EmulateADC: Bad argument - already on\n");
    return &err_badnoparms;
  }

  if (arg_off && !emulate_adc_on) {
    debug_printf("EmulateADC: Bad argument - already off\n");
    return &err_badnoparms;
  }

  emulate_adc_on = arg_on;
  return NULL;
}





_kernel_oserror *command_debug(const char *args, int32_t argc)
{
  if (argc >= 1) {
    int32_t desired_id = -1;
    uint32_t ret = sscanf(args, "%d", &desired_id);
    if (ret != 1) {
      debug_printf("Debug: Bad arguments, didn't read 1 args (read %d)\n", ret);
      return &err_badnoparms;
    }
  
    if (desired_id < 0 || desired_id >= JOY_MAX) {
      debug_printf("Debug: Bad arguments, id (%d) is too big\n", desired_id);
      return &err_badnoparms;
    }

    debug_printf("Debug: Printing out single stick id %d\n", desired_id);
    debug_joystick(desired_id);
  }
  else {
    osbool any = FALSE;
  
    for (uint32_t i=0; i<JOY_MAX; i++) {
      if (joy_data[i].in_use == TRUE) {
        debug_printf("Debug: Printing out all active sticks, currently on stick id %d\n", i);
        debug_joystick(i);
        any = TRUE;
      }
    }
  
    if (any == FALSE) {
      printf("No active joysticks.\n");
    }
  }

  return NULL;
}





_kernel_oserror *command_list(const char *args, int32_t argc)
{
  if (argc >= 1) {
    int32_t desired_id = -1;
    uint32_t ret = sscanf(args, "%d", &desired_id);
    if (ret != 1) {
      debug_printf("command_list: Bad arguments, didn't read 1 args (read %d)\n", ret);
      return &err_badnoparms;
    }
  
    if (desired_id < 0 || desired_id >= JOY_MAX) {
      debug_printf("command_list: Bad arguments, id (%d) is too big\n", desired_id);
      return &err_badnoparms;
    }

    debug_printf("command_list: Printing out single stick id %d\n", desired_id);
    print_joystick(desired_id);
  }
  else {
    osbool any = FALSE;
  
    for (uint32_t i=0; i<JOY_MAX; i++) {
      if (joy_data[i].in_use == TRUE) {
        debug_printf("command_list: Printing out all active sticks, currently on stick id %d\n", i);
        print_joystick(i);
        any = TRUE;
      }
    }
  
    if (any == FALSE) {
      printf("No active joysticks.\n");
    }
  }

  return NULL;
}




_kernel_oserror *command_mapped(const char *args, int32_t argc)
{
  if (argc >= 1) {
    int32_t i = -1;
    uint32_t ret = sscanf(args, "%d", &i);
    if (ret != 1) {
      debug_printf("command_mapped: Bad arguments, didn't read 1 args (read %d)\n", ret);
      return &err_badnoparms;
    }
  
    if (i < 0 || i >= JOY_MAX) {
      debug_printf("command_mapped: Bad arguments, id (%d) is too big\n", i);
      return &err_badnoparms;
    }

    debug_printf("command_mapped: Printing out single stick id %d\n", i);
    printf("Joystick id %u (%s - %s)\n", i, joy_data[i].manufacturer, joy_data[i].product);
    print_joystick_map(i);
  }
  else {
    osbool any = FALSE;
  
    for (uint32_t i=0; i<JOY_MAX; i++) {
      if (joy_data[i].in_use == TRUE && joy_data[i].mapped_number != NOT_MAPPED) {
        printf("Joystick id %u (%s - %s)\n", i, joy_data[i].manufacturer, joy_data[i].product);
        print_joystick_map(i);
        any = TRUE;
      }
    }
  
    if (any == FALSE) {
      printf("No mapped joysticks.\n");
    }
  }
  return NULL;
}





void print_joystick(uint32_t i)
{
  printf("Joystick id %u (%s - %s)\n", i, joy_data[i].manufacturer, joy_data[i].product);

  printf("  Local USB device name            : %s\n", joy_data[i].device_name);
  printf("  Interface                        : %d\n", joy_data[i].interface);
  printf("  endpoint                         : %d\n", joy_data[i].endpoint);
  printf("  Device manufacturer              : %s\n", joy_data[i].manufacturer);
  printf("  Device product name              : %s\n", joy_data[i].product);
  printf("  Device serial number             : %s\n", joy_data[i].serial);
  printf("  Driver                           : %s\n", joy_data[i].device->name);

  printf("  Number of axes                   : %d\n", joy_data[i].num_axes);
  printf("  Number of buttons                : %d\n", joy_data[i].num_buttons);
                                       
  printf("  HAT switch                       : ");
  if (joy_data[i].hat_item)            
    printf("Yes\n");                   
  else                                 
    printf("No\n");                    
                                       
  printf("  DPAD                             : ");
  if (joy_data[i].has_dpad)            
    printf("Yes\n");
  else
    printf("No\n");

  printf("  Mouse control enabled            : ");
  if (mouse_joy == i)
    printf("Yes\n");
  else
    printf("No\n");

  printf("  Keyboard controls                : ");
  if (joy_data[i].key_up != NOT_MAPPED)
    printf("Up=%u ", joy_data[i].key_up);
  if (joy_data[i].key_down != NOT_MAPPED)
    printf("Down=%u ", joy_data[i].key_down);
  if (joy_data[i].key_left != NOT_MAPPED)
    printf("Left=%u ", joy_data[i].key_left);
  if (joy_data[i].key_right != NOT_MAPPED)
    printf("Right=%u ", joy_data[i].key_right);

  for (int32_t j=0; j<ACORN_BUTTONS; j++) {
    if (joy_data[i].key_buttons[j] != NOT_MAPPED)
      printf("B%u=%u ", j, joy_data[i].key_buttons[j]);
  }
    printf("\n");

  //print_joystick_map(i);
}




void print_joystick_map(uint32_t i)
{
  printf("  Mapped to Joystick number        : ");
  if (joy_data[i].mapped_number == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d\n", joy_data[i].mapped_number);

  printf("  Mapped to Joystick  8-bit x-axis : ");
  if (joy_data[i].mapped_x_8 == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d (%s)\n", joy_data[i].mapped_x_8, joy_data[i].axes[joy_data[i].mapped_x_8].name);

  printf("  Mapped to Joystick  8-bit y-axis : ");
  if (joy_data[i].mapped_y_8 == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d (%s)\n", joy_data[i].mapped_y_8, joy_data[i].axes[joy_data[i].mapped_y_8].name);

  printf("  Mapped to Joystick 16-bit x-axis : ");
  if (joy_data[i].mapped_x_16 == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d (%s)\n", joy_data[i].mapped_x_16, joy_data[i].axes[joy_data[i].mapped_x_16].name);

  printf("  Mapped to Joystick 16-bit y-axis : ");
  if (joy_data[i].mapped_y_16 == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d (%s)\n", joy_data[i].mapped_y_16, joy_data[i].axes[joy_data[i].mapped_y_16].name);

  for (uint32_t j=0; j<ACORN_BUTTONS; j++) {
    if (joy_data[i].mapped_buttons[j] != NOT_MAPPED)
      printf("  Mapped to Joystick button %02d     : %02d\n", j, joy_data[i].mapped_buttons[j]);
  }

  for (uint32_t c=0; c<ADC_CHANNELS; c++) {
    if (adc_map.channels[c].joy_id == i) {
      printf("  Mapped to ADC channel %d          : ", c);
      if (adc_map.channels[c].axis == NOT_MAPPED)
        printf("N/A\n");
      else
        printf("%02d (%s) %d to %d\n", adc_map.channels[c].axis, joy_data[i].axes[adc_map.channels[c].axis].name, adc_map.channels[c].start, adc_map.channels[c].end);
    }
  }
  for (uint32_t b=0; b<ADC_BUTTONS; b++) {
    if (adc_map.buttons[b].joy_id == i) {
      printf("  Mapped to ADC fire %d             : ", b);
      if (adc_map.buttons[b].button == NOT_MAPPED)
        printf("N/A\n");
      else
        printf("%02u\n", adc_map.buttons[b].button);
    }
  }

  printf("  Mapped to mouse x-axis           : ");
  if (joy_data[i].mapped_mouse_x == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d (%s), sensitivity %u, factor %u\n", joy_data[i].mapped_mouse_x, joy_data[i].axes[joy_data[i].mapped_mouse_x].name, joy_data[i].axes[joy_data[i].mapped_mouse_x].mouse_sensitivity, joy_data[i].axes[joy_data[i].mapped_mouse_x].mouse_factor);

  printf("  Mapped to mouse y-axis           : ");
  if (joy_data[i].mapped_mouse_y == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d (%s), sensitivity %u, factor %u\n", joy_data[i].mapped_mouse_y, joy_data[i].axes[joy_data[i].mapped_mouse_y].name, joy_data[i].axes[joy_data[i].mapped_mouse_y].mouse_sensitivity, joy_data[i].axes[joy_data[i].mapped_mouse_y].mouse_factor);

  printf("  Mapped to mouse buttons          : SELECT=");
  if (joy_data[i].mapped_mouse_select == NOT_MAPPED)
    printf("N/A  ");
  else
    printf("%02d  ", joy_data[i].mapped_mouse_select);

  printf("MENU=");
  if (joy_data[i].mapped_mouse_menu == NOT_MAPPED)
    printf("N/A  ");
  else
    printf("%02d  ", joy_data[i].mapped_mouse_menu);

  printf("ADJUST=");
  if (joy_data[i].mapped_mouse_adjust == NOT_MAPPED)
    printf("N/A\n");
  else
    printf("%02d\n", joy_data[i].mapped_mouse_adjust);

}





void debug_joystick(uint32_t i)
{
  printf("Joystick id %u (%s - %s)\n", i, joy_data[i].manufacturer, joy_data[i].product);

  printf("  Path                    : %s\n", joy_data[i].usb_path);
  printf("  File handle             : %u\n", joy_data[i].fp);

  printf("  Data stream open        : ");
  if (joy_data[i].open)
    printf("Yes\n");
  else
    printf("No (is something else using it?)\n");

  printf("  Local USB device name   : %s\n", joy_data[i].device_name);
  printf("  Interface               : %d\n", joy_data[i].interface);
  printf("  endpoint                : %d\n", joy_data[i].endpoint);
  printf("  Device manufacturer     : %s\n", joy_data[i].manufacturer);
  printf("  Device product name     : %s\n", joy_data[i].product);
  printf("  Device serial number    : %s\n", joy_data[i].serial);
                                       
  printf("  USB vendor id           : 0x%04x\n", joy_data[i].vendor_id);
  printf("  USB product id          : 0x%04x\n", joy_data[i].product_id);
  printf("  USB device id           : 0x%04x\n", joy_data[i].device_id);

  printf("  Buffer handle           : %u\n", (uint32_t)(joy_data[i].buffer_handle));
  printf("  Buffer internal id      : %u\n", (uint32_t)(joy_data[i].buffer_internal_id));
  printf("  Buffer service routine  : 0x%08x\n", (uint32_t)(joy_data[i].buffer_service_routine));
  printf("  Buffer workspace        : 0x%08x\n", (uint32_t)(joy_data[i].buffer_workspace));

  printf("  DeviceFS handle         : 0x%08x\n", joy_data[i].devicefs_handle);
  printf("  Report data length      : %u\n", joy_data[i].report_length);

  printf("  Upcalls                 : %u (delta: %u)\n", joy_data[i].upcalls, joy_data[i].upcalls_delta);
  joy_data[i].upcalls_delta = 0;

  printf("  Good reads              : %u (delta: %u)\n", joy_data[i].good_reads, joy_data[i].good_reads_delta);
  joy_data[i].good_reads_delta = 0;

  printf("  Bad reads               : %u (delta: %u)\n", joy_data[i].bad_reads, joy_data[i].bad_reads_delta);
  joy_data[i].bad_reads_delta = 0;

  printf("  Raw report data         : ");
  for (int32_t b=0; b<joy_data[i].report_length; b++) {
    printf("%02x ", joy_data[i].data_buf[b]);
  }
  printf("\n");

  printf("  Number of axes          : %d\n", joy_data[i].num_axes);
  printf("  Number of buttons       : %d\n", joy_data[i].num_buttons);
                                       
  printf("  HAT switch              : ");
  if (joy_data[i].hat_item)            
    printf("Yes\n");                   
  else                                 
    printf("No\n");                    
                                       
  printf("  DPAD                    : ");
  if (joy_data[i].has_dpad)            
    printf("Yes\n");
  else
    printf("No\n");

  printf("  Axes:\n");

  for (int32_t a=0; a<joy_data[i].num_axes; a++) {
    printf("  Axis %02d %5s : ", a, joy_data[i].axes[a].name);
    printf("Slope 8 = %4u ", joy_data[i].axes[a].acorn_slope_8);
    if (joy_data[i].axes[a].acorn_slope_div_8)
      printf("(div), ");
    else
      printf("(mul), ");

    printf("Slope 16 = %4u ", joy_data[i].axes[a].acorn_slope_16);
    if (joy_data[i].axes[a].acorn_slope_div_16)
      printf("(div), ");
    else
      printf("(mul), ");

    printf("Mouse factor = %4u, Mouse sensitivity = %4u ", joy_data[i].axes[a].mouse_factor, joy_data[i].axes[a].mouse_sensitivity);

    printf("SP = %6d:%6d, ", joy_data[i].axes[a].serial_port_lower_bound, joy_data[i].axes[a].serial_port_upper_bound);

    printf("Flip = ");
    if (joy_data[i].axes[a].flip)
      printf(" on, ");
    else
      printf("off, ");

    struct hid_item *item = get_axis_item_by_type(i, joy_data[i].axes[a].type);
    if (item)
      printf("ReportId = %d", item->report_ID);
    else
      printf("(no item?)");

    printf("\n");
  }

  printf("  Button ReportIds : ");
  for (int32_t a=0; a<JOY_BUTTONS; a++) {
    if (joy_data[i].button_items[a])
      printf("%02d=%d ", a, joy_data[i].button_items[a]->report_ID);
  }
  printf("\n");
}


