{
    "$schema": "http://json-schema.org/draft-07/schema#",
    "$id": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.2/dvrk-console.schema.json",
    "title": "dVRK console 2.2",
    "type": "object",
    "description": "Configuration file format for the dVRK console.  See [dVRK wiki](https://github.com/jhu-dVRK/sawIntuitiveResearchKit/wiki).<ul><li>This format is used by the application `sawIntuitiveResearchKitQtConsoleJSON` and the ROS application `dvrk_robot dvrk_console_json`<li>For details of implementation, see code under `sawIntuitiveResearchKit/components/code/mtsIntuitiveResearchKitConsole.cpp`<li>[Schema file](dvrk-console.schema.json)</ul>",
    "additionalProperties": false,
    "properties": {
        "io": {
            "type": "object",
            "description": "Configuration for the input/output (IO)",
            "additionalProperties": false,
            "properties": {

                "port": {
                    "type":"string",
                    "description": "Port used communicate between the computer and the dVRK controllers.  Accepted values are \"fw\", \"fw:X\" (X is FireWire port), \"udp\" or \"udp:xx.xx.xx.xx\" (xx.xx.xx.xx is the IP address of the dVRK controller.  Default controller address is 169.254.0.100.  Values are parsed by `BasePort::ParseOptions` in library Amp1394.",
                    "pattern": "^fw$|^fw:[0-9]$|^udp$|^udp:[0-9]{2,3}.[0-9]{2,3}.[0-9]{2,3}.[0-9]{2,3}",
                    "examples": [
                        {
                            "port": "udp"
                        },
                        {
                            "port": "fw"
                        }
                    ]
                },

                "firewire-protocol": {
                    "type": "string",
                    "description": "Protocol used for all FireWire communications.  This applies wether the controllers are connected to the computer using FireWired or Ethernet (UDP with Link-Local).  This is an advanced setting and most users should avoid defining it.<ul><li>`sequential-read-write`: the PC reads data from each board (2 FPGA/QLA per controller), performs its computations (conversions, safety checks, PID, ...) and then writes sequentially to each board (N reads, N writes). This is the only protocol supported on older firmware (3 and below).<li>`sequential-read-broadcast-write`: the PC reads sequentially but performs a single write for all the boards. The write message is an array of values sent to the boards, each board access the data it needs by index (N reads, 1 write). This is the default protocol for the dVRK controllers with firmware 4 and above.<li>`broadcast-query-read-write`: the PC sends a single query/synchronization to all boards, read values are aggregated in single packet over the bus and there's a single write (1 query, 1 read, 1 write). This is the fastest protocol available but some FireWire cards seem to have trouble synchronizing the read packets. You will have to test it on your hardware to see if it supports this protocol or not.  `broadcast-read-write` is the older name for this protocol and is provided for backward compatibility.</ul>",
                    "enum": ["sequential-read-write", "srw",
			     "sequential-read-broadcast-write", "srbw",
			     "broadcast-query-read-write", "bqrw",
			     "broadcast-read-write", "brw"],
                    "default": "sequential-read-broadcast-write"
                },

                "close-all-relays": {
                    "type": "boolean",
                    "description": "Close all the e-stop safety relays on all the controllers found on the current port (FireWire or Ethernet).  This allows the user to skip the terminal based command: `qlacommand -c close-relays`.",
                    "default": false
                },

                "footpedals": {
                    "type": "string",
                    "description": "IO configuration file used to define inputs from the foot pedals.  See files `sawRobotIO1394-*-foot-pedals.xml` in directory `share/io`.  The console use a search path that includes the `sawIntuitiveResearchKit/share` directory so you can specify any relative path from the `share` directory.",
                    "examples": [
                        {
                            "footpedals": "io/sawRobotIO1394-MTMR-foot-pedals.xml"
                        },
                        {
                            "footpedals": "io/sawRobotIO1394-MTML-foot-pedals.xml"
                        }
                    ]
                },

                "physical-footpedals-required": {
                    "type": "boolean",
                    "description": "Indicates if the console should have a foot pedal configuration file when one or more tele-operation components have been declared.  If the user doesn't want the physical foot pedals but had declared some tele-operation components, set this parameter to `false`.  The console will still need events emulating the foot pedals but these can be generated using the GUI or through ROS.",
                    "default": true
                },

                "period": {
                    "type": "number",
                    "description": "Periodicity for the IO and PID loop.  Defined in seconds, i.e. interval between two iterations.  The default is defined in `mtsIntuitiveResearchKit.h` and is set so the loop frequency is 1500Hz, ~0.66ms so 0.00066s.  This is an advanced setting and most users should avoid defining it.",
                    "exclusiveMinimum": 0.0,
                    "examples": [
                        {
                            "period": 0.001
                        }
                    ]
                },

                "watchdog-timeout": {
                    "type": "number",
                    "description": "Maximum laps of time allowed between to read/write access to the controller.  It is used to detect abnormally slow IOs or disconnected cables.  The value is sent to the controllers and the controllers will turn off power if the communication loop time exceeds the watchdog timeout.  Defined in seconds.  The default is defined in `mtsIntuitiveResearchKit.h` and is set to 30ms.  This is an advanced setting and most users should avoid defining it.  Setting it to zero disables the watchdog and should only be used by experts.  The maximum value is 300ms, i.e. 0.3s",
                    "minimum": 0.0,
                    "maximum": 0.3,
                    "examples": [
                        {
                            "watchdog-timeout": 0.05
                        }
                    ]
                },

                "configuration-files": {
                    "type": "array",
                    "description": "Extra configuration files to configure the IO component.  See examples in directory `share/io`.",
                    "items": {
                        "type": "string"
                    }
                }
            }

        },

        "console-inputs": {
            "type": "object",
            "description": "Alternative sources for the main console inputs, \"operator-present\", \"clutch\" and \"camera\".  Each input event normally comes from the da Vinci foot pedals connected to the dVRK controller using the attribute \"io\": \"footpedals\" but they can be replaced by other sources.  To define another source, you need another component with a provided interface that has one write event named \"Button\".",
            "additionalProperties": false,
            "properties": {
                "operator-present": {
                    "description": "Alternate source for the \"operator-present\" sensor event",
                    "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/dvrk-interface-button.schema.json#/properties"
                },
                "clutch": {
                    "description": "Alternate source for the \"clutch\" pedal event",
                    "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/dvrk-interface-button.schema.json#/properties"
                },
                "camera": {
                    "description": "Alternate source for the \"camera\" pedal event",
                    "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/dvrk-interface-button.schema.json#/properties"
                }
            }
        },

        "operator-present": {
            "description": "Configuration required to use the built-in da Vinci surgeon's console head sensor",
            "type": "object",
            "additionalProperties": false,
            "required": ["io"],
            "properties": {
                "io": {
                    "description": "IO configuration file used to define inputs for the da Vinci head sensor.  This requires a custom cable and will only work with a full da Vinci system.  The head sensor component was introduced in version 1.6.  See [dVRK wiki](https://github.com/jhu-dvrk/sawIntuitiveResearchKit/wiki/HeadSensor).",
                    "type": "string",
                    "examples": [
                        {
                            "operator-present": {
                                "io": "io/sawRobotIO1394-MTMR-dv-head-sensor.xml"
                            }
                        }
                    ]
                }
            }
        },

        "endoscope-focus": {
            "description": "Configuration required to use the da Vinci endoscope focus controller",
            "type": "object",
            "additionalProperties": false,
            "required": ["io"],
            "properties": {
                "io": {
                    "description": "IO configuration file used to define outputs for the da Vinci endoscope focus controllers.  This requires a custom cable and will only work with da Vinci focus controller.  The endoscope focus component was introduced in version 1.6.  See [dVRK wiki](https://github.com/jhu-dvrk/sawIntuitiveResearchKit/wiki/Endoscope-Focus-Controller).",
                    "type": "string",
                    "examples": [
                        {
                            "endoscope-focus": {
                                "io": "io/sawRobotIO1394-MTML-dv-endoscope-focus.xml"
                            }
                        }
                    ]
                }
            }
        },

        "component-manager": {
            "description": "See *cisstMultiTask* [component manager](cisst-component-manager.html)",
            "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/cisst-component-manager.schema.json#/properties/component-manager"
        },

        "arms": {
            "type": "array",
            "description": "List of arms for the console",
            "items": {
                "type": "object",
                "description": "Configuration for a single arm",
                "required": ["name", "type"],
                "additionalProperties": false,
                "properties": {

                    "name": {
                        "type": "string",
                        "description": "Name of the arm.  For dVRK arms, use one of MTML, MTML, PSM1, PSM2, PSM3 or ECM",
                        "examples": [
                            {
                                "name": "MTMR"
                            }
                        ]
                    },

                    "type": {
                        "type": "string",
                        "enum": ["MTM", "PSM", "ECM",
                                 "MTM_DERIVED", "PSM_DERIVED", "ECM_DERIVED",
                                 "MTM_GENERIC", "PSM_GENERIC", "ECM_GENERIC",
                                 "PSM_SOCKET", "SUJ_Classic", "SUJ_Si", "SUJ_Fixed", "FOCUS_CONTROLLER"],
                        "description": "Type of arm.  This determines which class should be used to instantiate the arm.<ul><li>`MTM`, `PSM` and `ECM` correspond to the default classes provided for the dVRK arms.  These are the most common ones.<li>`xxx_DERIVED` corresponds to classes derived from the base classes provided in the dVRK stack.  Users can derive the base arm classes to alter their behavior.  In this case, the console knows that the derived class has all the features from the base class so the connections to the PID, IO, Qt widget and ROS bridge are the same as those for the base class.<li>`xxx_GENERIC` corresponds to classes not derived from the dVRK base classes.  The console will not create any IO, PID components for this arm.  The console will use a generic Qt Widget and add ROS topics if and only if the provided interface has CRTK compatible commands and events.  Examples include Force Dimension devices ([sawForceDimensionSDK](https://github.com/jhu-saw/sawForceDimensionSDK)) and the Sensable Omni ([sawSensablePhantom](https://github.com/jhu-saw/sawSensablePhantom)).<li>`PSM_SOCKET` is a special case used for simple tele-operation between two processes (likely between two computers).  One dVRK console will have to instantiate a PSM server and the other a PSM client.<li>`SUJ_Classic` and `SUJ_Si` are for the clinical systems [Setup Joints](https://github.com/jhu-dvrk/sawIntuitiveResearchKit/wiki/SUJ)<li>`SUJ_Fixed` is for arms on a custom mount</ul>For `xxx_DERIVED` and `xxx_GENERIC`, the console has no way to automatically create the component, so the user has to provide the proper `component-manager` configuration to first create the component for the arm.",
                        "examples": [
                            {
                                "arms":
                                [
                                    {
                                        "name": "MTML",
                                        "type": "MTM",
                                        "serial": "22723",
                                        "system": "jhu-dVRK"
                                    }
                                    ,
                                    {
                                        "name": "MTMR",
                                        "type": "MTM_GENERIC",
                                        "component": "ForceDimensionSDK",
                                        "interface": "MTMR"
                                    }
                                ]
                            }
                        ]
                    },

                    "serial": {
                        "type": "string",
                        "description": "Arm's serial number.  To verify the serial number, locate the label on the arm itself (see [dVRK wiki](https://github.com/jhu-dvrk/sawIntuitiveResearchKit/wiki/XMLConfig)).  The serial number and the arm's name are used to locate the arm configuration file assuming the arm configuration file name is `<arm_name>-<arm_serial>.json` (e.g. `MTML-22723.json`).",
                        "examples": [
                            {
                                "serial": "22723"
                            }
                        ]
                    },

                    "system": {
                        "type": "string",
                        "description": "name of your system, i.e. subdirectory under `sawIntuitiveResearchKit/share` where to locate the arm configuration files (`sawRobotIO1394*.xml`, `<arm_name>-<arm_serial>.json`, gravity compensation parameters (for MTMs)...`).   For example, setting the `system` to `jhu-dVRK` will add `sawIntuitiveResearchKit/share/jhu-dVRK` to the search path to locate the arm's configuration files.",
                        "examples": [
                            {
                                "system": "jhu-daVinci"
                            }
                        ]
                    },

                    "arm": {
                        "type": "string",
                        "description": "Arm configuration file.  Note that this is optional if the `serial` number has been provided.  If the `serial` number has been provided, the application will assume the arm file is `<name>-<serial>.json`.  For example `PSM1-22723.json`.  This attribute is useful mostly if the arm is simulated (`\"simulation\": \"KINEMATIC\"`)."
                    },

                    "simulation": {
                        "type": "string",
                        "enum": ["KINEMATIC"],
                        "description": "Use the arm in simulation mode. In this case, the console doesn't need to create an IO component and can run without the physical arms and dVRK controllers (see examples in directory `share/arm`). The only simulation currently supported is `KINEMATIC`, i.e. the PID will set the measured positions (`measured_js` and `setpoint_js`) based on the commanded positions (`servo_jp`). This allows to test the kinematic but doesn't include any dynamic nor simulation of interactions with the world like Gazebo or VREP would."
                    },

                    "base-frame": {
                        "type": "object",
                        "description": "Base frame prepended to the forward kinematics.  The base frame is also taken into account when setting cartesian position goals",
                        "examples": [
                            {
                                "base-frame": {
                                    "reference-frame": "HRSV",
                                    "transform": [[ -1.0,  0.0,          0.0,          0.180],
                                                  [  0.0,  0.866025404,  0.5,          0.400],
                                                  [  0.0,  0.5,         -0.866025404,  0.475],
                                                  [  0.0,  0.0,          0.0,          1.0]]
                                }
                            }
			    ,
                            {
                                "base-frame": {
                                    "component": "ECM",
                                    "interface": "Arm"
                                }
                            }
                        ],
                        "oneOf": [
                            { "required": ["transform", "reference-frame"] },
                            { "required": ["component", "interface"] }
                        ],
                        "additionalProperties": false,
                        "properties": {

                            "transform": {
                                "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/cisst-matrices.schema.json#/properties/matrix4x4"
                            },

                            "reference-frame": {
                                "description": "Name of the reference frame.  This is used for Qt Widget and ROS tf",
                                "type": "string"
                            },

                            "component": {
                                "description": "Name of the component that can provide the base frame at runtime.  This is used for the full patient cart where the SUJ component can compute the base frame.",
                                "type": "string"
                            },

                            "interface": {
                                "description": "Name of the required interface used to set the base frame on the arm (using function `set_base_frame`)",
                                "type": "string"
                            }

                        }
                    },

                    "period": {
                        "description": "Override the default periodicity of the arm class.  Most user should steer away from changing the default arm periodicity.  This works only for the dVRK base types ('MTM, PSM, ECM).",
                        "type": "number",
                        "exclusiveMinimum": 0.0
                    },

                    "io": {
                        "type": "string",
                        "description": "[Deprecated] Name of the XML configuration file for the low level arm's IO (from *sawRobotIO1394*).  The name of the IO configuration file is now inferred from the `serial` number attribute.  Use `serial` instead."
                    },

                    "pid": {
                        "type": "string",
                        "description": "[Deprecated] Name of the XML configuration file for the arm's PID (from *sawControllers*, `mtsPID`).  The name of the PID configuration file is now inferred from the arm's `name` attribute."
                    },

                    "kinematic": {
                        "type": "string",
                        "description": "[Deprecated] Name of the JSON configuration file for the arm's kinematic (from *cisstRobot*, `robManipulator`).  The kinematic file should now be provided in the arm configuration file.  The name of the arm configuration file can be inferred from the arm name and serial number (e.g. `PSM1-28007.json`) or provided using the `arm` attribute."
                    },

                    "component": {
                        "description": "For arm of type xxx_GENERIC only.  Name of the component for the generic arm.  For the dVRK arms, the component is named after the arm (e.g. \"MTML\").  For other devices (e.g. `sawSensablePhantom`) the component might be able to provide multiple arms so the arm name is used for the \"interface\".",
                        "type": "string"
                    },

                    "interface": {
                        "description": "For arm of type xxx_GENERIC only.  Name of the provided interface for the generic arm.  For the dVRK arms, the component is named after the arm (e.g. \"MTML\") and the interface is always \"Arm\".  For other devices (e.g. `sawSensablePhantom`) the component might be able to provide multiple arms so the arm name is used for the \"interface\".",
                        "type": "string"
                    },

                    "skip-ros-bridge": {
                        "description": "Tell the component manager to not expose the arm commands to ROS.  By default, the component manager will expose the arm to ROS using the cisst ROS CRTK bridge",
                        "type": "boolean",
                        "default": false
                    },

                    "socket-server": {
                        "description": "Only works for PSMs.  Indicates that a PSM socket server should be created.  This can be used to communicate with another dVRK console process with a PSM of type `PSM_SOCKET` and create a tele-operation between two sites.",
                        "type": "boolean",
                        "default": false
                    },

                    "remote-ip": {
                        "description": "Only works with PSM of type `PSM_SOCKET` or if \"socket-server\" is set to `true`.  Used to create a UDP socket to remotely access a PSM",
                        "type": "string"
                    },

                    "port": {
                        "description": "Only works with PSM of type `PSM_SOCKET` or if \"socket-server\" is set to `true`.  Used to create a UDP socket to remotely access a PSM",
                        "type": "number"
                    }

                }
            }
        },


        "ecm-teleop": {
            "type": "object",
            "description": "Configuration for the ECM tele-operation component",
            "required": ["mtm-left", "mtm-right", "ecm"],
            "additionalProperties": false,
            "properties": {

                "mtm-left": {
                    "type": "string",
                    "description": "Name of the MTML.  The arm must have been declared in the list of arms"
                },

                "mtm-right": {
                    "type": "string",
                    "description": "Name of the MTMR.  The arm must have been declared in the list of arms"
                },

                "ecm": {
                    "type": "string",
                    "description": "Name of the ECM.  The arm must have been declared in the list of arms"
                },

                "configure-parameter": {
                    "description": "See *cisstMultiTask* [component manager](cisst-component-manager.html)",
                    "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/dvrk-teleop-ecm.schema.json#/properties"
                },

                "period": {
                    "description": "Override the default periodicity of the ECM tele-operation class.  Most user should steer away from changing the default arm periodicity.  This works only for the dVRK base class, i.e. `\"type\": \"TELEOP_ECM\"`",
                    "type": "number",
                    "exclusiveMinimum": 0.0
                }
            }
        },

        "psm-teleops": {
            "type": "array",
            "description": "List of PSM tele-operation components.  Each PSM tele-operation component requires a mtm and a psm",
            "items": {
                "type": "object",
                "description": "Configuration for a single PSM tele-operation component",
                "required": ["mtm", "psm"],
                "additionalProperties": false,
                "properties": {

                    "mtm": {
                        "type": "string",
                        "description": "Name of the MTM.  The arm must have been declared in the list of arms"
                    },

                    "psm": {
                        "type": "string",
                        "description": "Name of the MTM.  The arm must have been declared in the list of arms"
                    },

                    "psm-base-frame": {
                        "type": "object",
                        "description": "Optional base frame.  This allows the tele-operation component to track changes of a potential base frame for the PSM.  This can be used to allow ECM motions while tele-operating.  The interface provided must have a `measured_cp` command",
                        "required": ["component", "interface"],
                        "additionalProperties": false,
                        "properties": {

                            "component": {
                                "description": "Name of the component that can provide the base frame at runtime.",
                                "type": "string"
                            },

                            "interface": {
                                "description": "Name of the provided interface used to get the base frame (using command `measured_cp`)",
                                "type": "string"
                            }
                        },
                        "examples": [
                            {
                                "mtm": "MTMR",
                                "psm": "PSM1",
                                "psm-base-frame": {
                                    "component": "ECM",
                                    "interface": "Arm"
                                }
                            }
                        ]
                    },

                    "type": {
                        "type": "string",
                        "enum": ["TELEOP_PSM", "TELEOP_PSM_DERIVED", "TELEOP_PSM_GENERIC"],
                        "default": "TELEOP_PSM",
                        "description": "Type of PSM tele-operation component.  This determines which class should be used to instantiate the tele-operation component.<ul><li>`TELEOP_PSM` corresponds to the default class provided for the dVRK arms.<li>`TELEOP_PSM_DERIVED` corresponds to a class derived from the base class `mtsTeleOperationPSM` provided in the dVRK stack.  Users can derive the base arm class to alter its behavior.  In this case, the console knows that the derived class has all the features from the base class so the connections to the MTM, PSM,  Qt widget and ROS bridge are the same as those for the base class.<li>`TELEOP_PSM_GENERIC` correspond to classes not derived from the dVRK base class.</ul>For `TELEOP_PSM_DERIVED` and `TELEOP_PSM_GENERIC`, the console has no way to automatically create the component, so the user has to provide the proper `component-manager` configuration to first create the component for the arm."
                    },

                    "configure-parameter": {
                        "description": "See *cisstMultiTask* [component manager](dvrk-teleop-psm.html)",
                        "$ref": "https://dvrk.lcsr.jhu.edu/documentation/schemas/v2.1/dvrk-teleop-psm.schema.json#/"
                    },

                    "period": {
                        "description": "Override the default periodicity of the PSM tele-operation class.  Most user should steer away from changing the default arm periodicity.  This works only for the dVRK base class, i.e. `\"type\": \"TELEOP_PSM\"`",
                        "type": "number",
                        "exclusiveMinimum": 0.0
                    }

                }
            }
        },

        "chatty": {
            "type": "boolean",
            "description": "Make the console say something useless when it starts.  It's mostly a way to test the text-to-speech feature.",
            "default": false
        }

    }
}
