syntax="proto3";

import "minknow/rpc/rpc_options.proto";
import "google/protobuf/wrappers.proto";

package ont.rpc.device;

service DeviceService {
    // Get information about the device this MinKNOW instance was started for.
    //
    // In normal circumstances (ie: when using the manager service), a new MinKNOW instance
    // is started for each available device. This call provides information about this device.
    //
    // The information returned by this call will not change (providing the MinKNOW instance
    // was started by the manager service).
    rpc get_device_info (GetDeviceInfoRequest) returns (GetDeviceInfoResponse) {}

    // Get information about the current device state.
    //
    // Information in this call may change as the device is used with MinKNOW, for example,
    // by unplugging or plugging in the device.
    // Since 1.12
    rpc get_device_state (GetDeviceStateRequest) returns (GetDeviceStateResponse) {}

    // Streaming version of get_device_state
    //
    // Since 1.13
    rpc stream_device_state (StreamDeviceStateRequest) returns (stream GetDeviceStateResponse) {}

    // Get information about the flow cell (if any).
    //
    // This provides information about the flow_cell attached to the device (described by
    // get_device_info()), if any.
    rpc get_flow_cell_info (GetFlowCellInfoRequest) returns (GetFlowCellInfoResponse) {}

    // Streaming version of get_flow_cell_info
    //
    // Since 1.13
    rpc stream_flow_cell_info (StreamFlowCellInfoRequest) returns (stream GetFlowCellInfoResponse) {}

    // Set the user specified flow cell id.
    //
    // This changes the user specified flow cell id.
    // MinKNOW will use this id in place of the id read from the eeprom, if no eeprom data
    // is available.
    //
    // This data is reset when the flow cell is disconnected.
    //
    // Since 1.12
    rpc set_user_specified_flow_cell_id (SetUserSpecifiedFlowCellIdRequest) returns (SetUserSpecifiedFlowCellIdResponse) {}

    // Set the user specified product code.
    //
    // This changes the user specified product code.
    //
    // MinKNOW does not use the product code, it is intended for use in MinKNOW's clients.
    //
    // This data is reset when the flow cell is disconnected.
    //
    // Since 1.12
    rpc set_user_specified_product_code (SetUserSpecifiedProductCodeRequest) returns (SetUserSpecifiedProductCodeResponse) {}

    // Get information about the channel layout
    //
    // Since 1.14
    rpc get_channels_layout (GetChannelsLayoutRequest) returns (GetChannelsLayoutResponse) {}

}

// Describes the configuration of a channel on the device.
//
// Note that this is a lossy representation. The device-specific APIs provide more precise
// information. This only describes common configurations, and omits anything that doesn't impact
// the received signal.
message ChannelConfiguration {
    // The currently-connected well.
    //
    // Wells are counted from 1. 0 indicates that no well is connected. 5 indicates some non-generic configuration
    // such as ground for a minion or connecting all wells on promethion
    //
    // Note that MinKNOW can return channel configurations where the well number is larger than the
    // ``max_well_count`` value returned by :meth:`DeviceService.get_device_info`. This indicates
    // that some other connection has been made (for example, PromethIONs can simultaneously
    // connect all wells, and MinIONs can connect to ground).
    uint32 well = 1;

    // Whether the test current is connected to the integrator (measurement circuit).
    //
    // The signal will be a steady test current produced on the device. This can be used for
    // calibration or to test the device integration circuits.
    bool test_current = 2;

	// Please DO NOT USE - does not have a practical use, will be removed in later versions.
    // Whether the regeneration current is connected to the integrator (measurement circuit).
    //
    // This is similar to unblock, but uses a different circuit. It is not available on MinION or
    // GridION devices.
    bool regeneration = 3;

    // Whether the unblock voltage is connected to the integrator (measurement circuit).
    //
    // Provides a reverse potential across the connected well. This can be used to drive molecules
    // back out of the well.
    bool unblock = 4;
}

message GetDeviceInfoRequest {}

message GetDeviceInfoResponse {
    enum DeviceType {
        MINION = 0;
        PROMETHION = 1; // Deprecated - will never be returned by minknow
        GRIDION = 2;
        PROMETHION_BETA = 3;
        MINION_MK1C = 4;
    }

    // A unique identifier for the device.
    //
    // This is the identifier of the device MinKNOW was started for. It will only communicate
    // with this device.
    //
    // Note that simulated device IDs are only unique for this host, not globally.
    //
    // This value will be set even if the device is not currently connected (assuming MinKNOW
    // was started by the manager service).
    string device_id = 1;

    // The type of the device.
    DeviceType device_type = 2;

    // Whether the device is simulated.
    //
    // If this is true, there is no physical device - MinKNOW is simluating it. If it is false,
    // MinKNOW will be acquiring data from a real device.
    bool is_simulated = 3;

    // The maximum number of channels supported by the device.
    //
    // Each channel provides a signal from the device. For example, a MinION supports up to 512
    // channels, and so can provide 512 simultaneous streams of data.
    //
    // This value is fixed for a given device type. Note, however, that a flow cell might be attached
    // that has a smaller number of channels.
    uint32 max_channel_count = 4;

    // The maximum number of wells connected to each channel.
    //
    // A well is a discrete location on the device where sensing can take place. Normally, each well
    // should have a single nanopore in it.
    //
    // For example, a MinION supports up to 4 wells per channel, allowing for 2048 wells in total.
    // So the value of this for a MinION will be 4.
    //
    // This value is fixed for a given device type. Note, however, that a flow cell might be attached
    // that has a smaller number of wells on each channel.
    uint32 max_wells_per_channel = 5;

    // Whether the set_temperature() method can be expected to work.
    //
    // On some systems, not all connected devices have the ability to control their own temperature,
    // as temperature controls are managed in groups. If this field is true, this device can control
    // its own temperature. If it it false, it cannot, and the temperature will be maintained at a
    // pre-determined temperature.
    bool can_set_temperature = 6;

    // The range of uncalibrated data values.
    //
    // This is the number of distinct signal values that can be produced by the device's analog to
    // digital converter (ADC).
    uint32 digitisation = 7;

    // If this is true then the physical location of the device is described by the location_index
    // field below. Examples of hardware that will know their physical locations are the devices in
    // GridIONs and PromethIONs. This is false for MinIONs as these devices are not constrained
    // to physical location.
    bool location_defined = 8;

    // An index that describes the position of the device in a linear order of devices (from
    // 0 onwards.)
    uint32 location_index = 9;

    // Firmware versions of components associated with this device
    //
    // Depending on the hardware, there may be several components associated with
    // this device, each with their own firmware version.
    message ComponentVersion {
        // Description of the component that has firmware
        string component = 1;

        // The firmware version, if this cannot be determined for a component where
        // the firmware version would usually be available, this will contain
        // "Unknown"
        string version = 2;
    }
    repeated ComponentVersion firmware_version = 10;
}

message GetDeviceStateRequest {}

message GetDeviceStateResponse {
    enum DeviceState {
        DEVICE_DISCONNECTED = 0;
        DEVICE_READY = 1;
    }

    DeviceState device_state = 1;
}

message StreamDeviceStateRequest {}

message GetFlowCellInfoRequest {}

message GetFlowCellInfoResponse {
    // Whether there is a flow cell present.
    //
    // If both this and has_adapter are false, none of the other fields will contain useful
    // information.
    bool has_flow_cell = 1;

    // The number of channels currently supported by the device.
    //
    // This may be smaller than the ``max_channel_count`` value returned by get_device_info(),
    // depending on the attached flow cell.
    uint32 channel_count = 2;

    // The number of wells currently supported by the device.
    //
    // This may be smaller than the ``max_wells_per_channel`` value returned by get_device_info(),
    // depending on the attached flow cell.
    uint32 wells_per_channel = 3;

    // The unique identifier for the flow cell.
    //
    // This should be same as the value printed onto the flow cell casing. Not all flow cells will
    // have the flow cell ID recorded in a way that MinKNOW can read. In those cases, this will be an
    // empty string, even though the user may be able to see a printed identifier on the flow cell.
    string flow_cell_id = 4;

    // The unique identifier for the ASIC.
    //
    // Note: This member is deprecated in favour of asic_id_str - it does not work for PromethION
    //       asics, and will be removed in future.
    //
    // This is a numerical value uniquely identifying the ASIC embedded in the flow cell. It will
    // always be set when a flow cell is present.
    //
    // The intended use for this is to track whether the flow cell has been replaced between calls to
    // get_flow_cell_info(). Any other use is unsupported (see the caveats below).
    //
    // Caveats:
    //
    // * This value will not mean anything to an end-user.
    // * There is no guarantee that this field will contain the same numerical identifier across
    //   MinKNOW versions, even with the same flow cell.
    // * An ASIC can be recycled into a new flow cell, so this identifier may be re-used in the
    //   future (although it can be considered unique for the duration of a protocol run).
    uint32 asic_id = 5;

    // The unique identifier for the ASIC (formatted as string).
    //
    // This is a value uniquely identifying the ASIC embedded in the flow cell. It will
    // always be set when a flow cell is present.
    //
    // The intended use for this is to track the identity of the asic in the flow cell, eg. for
    // displaying to users during production of chips.
    //
    // Caveats:
    //
    // * This value will not mean anything to a customer.
    // * There is no guarantee that this field will contain the same identifier across
    //   MinKNOW versions, even with the same flow cell.
    // * An ASIC can be recycled into a new flow cell, so this identifier may be re-used in the
    //   future (although it can be considered unique for the duration of a protocol run).
    string asic_id_str = 13;

    // The product code for the flow cell.
    //
    // This should be the code displayed in the shop where the flow cell was bought. Not all
    // flow cells will have the product code recorded in a way that MinKNOW can read. In those cases,
    // this will be an empty string.
    string product_code = 6;

    // A unique identifier for the flow cell, which the user can specify.
    //
    // In the event a flow cell does not have an eeprom, this field contains data input by the user
    // using set_flow_cell_info to record required data.
    //
    // Since 1.12
    string user_specified_flow_cell_id = 7;

    // A product code for the flow cell, which the user can specify.
    //
    // This should be the code displayed in the shop where the flow cell was bought. Not all
    // flow cells have an eeprom, in the event they don't, the user can specify using this id using
    // set_flow_cell_info.
    //
    // Since 1.12
    string user_specified_product_code = 8;

    // Whether there is a flongle adapter.
    //
    // If this is true, the adapter_id, channel_count and wells_per_channel fields should all
    // provide useful information, even if has_flow_cell is false.
    bool has_adapter = 9;

    // The unique identifier of an attached flongle adatper.
    //
    // This should be same as the value printed onto the adapter casing.
    string adapter_id = 10;

    // Used to make the field nullable, since the null value is not protobuf's default.
    oneof temperature_offset_nullable {

        // The temperature offset for the flow cell, returned as an offset in degrees Celsius.
    	//
        // This offset specifies a correction to be applied to ASIC temperature.
        // If multiple ASIC temperatures are available from the device, applies to the mean temperature.
        //
    	// Since 1.14
        float temperature_offset = 11;
    }

    // The version of the ASIC contained in the flowcell (if specified by the hardware).
    //
    // This can be used to determine if the hardware should support certain features
    // added to only newer ASICs.
    //
    // Possible values include: "IA02C", "IA02D", or if the value is not readable on the
    // current hardware an empty string is returned.
    //
    // Since 1.14
    string asic_version = 12;
}

message StreamFlowCellInfoRequest {}

message SetUserSpecifiedFlowCellIdRequest {
    // A unique identifier for the flow cell, which the user can specify.
    //
    // In the event a flow cell does not have an eeprom, this field can be used by the user
    // to record their flow_cell_id.
    //
    // Since 1.12
    string id = 1 [(rpc_required) = true];
}

message SetUserSpecifiedFlowCellIdResponse {}


message SetUserSpecifiedProductCodeRequest {

    // A product code for the flow cell, which the user can specify.
    //
    // In the event a flow cell does not have an eeprom, the user can specify product code here.
    //
    // Since 1.12
    string code = 1 [(rpc_required) = true];
}

message SetUserSpecifiedProductCodeResponse {}

message GetChannelsLayoutRequest {
}

message GetChannelsLayoutResponse
{
    repeated ChannelRecord channel_records = 1;
}

message ChannelRecord
{
    message MuxRecord
    {
        uint32 id = 1;
        uint32 phys_x = 2;
        uint32 phys_y = 3;
    }
    uint32 id = 1;
    string name = 2;
    repeated MuxRecord mux_records = 3;
}

