Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New QMI driver for Thorlabs MPC320 #62

Closed
rbudhrani opened this issue Jan 8, 2024 · 3 comments · Fixed by #73
Closed

New QMI driver for Thorlabs MPC320 #62

rbudhrani opened this issue Jan 8, 2024 · 3 comments · Fixed by #73
Labels
QMI driver Addition or modification on a QMI driver

Comments

@rbudhrani
Copy link
Collaborator

rbudhrani commented Jan 8, 2024

Description

The Thorlabs USB device(s) use(s) FTDI peripehral chips for PC communication. For these, there are (USB-to-serial) drivers available for Windows and Linux from FTDI. "Before any PC USB communication can be established with an
Thorlabs controller, the client program is required to set up the necessary FTDI chip serial
port settings used to communicate to the Thorlabs controller embedded system. Within the
Thorlabs software itself the following FTDI library calls are made to set up the USB chip serial
port for each Thorlabs USB device enumerated on the bus." Example:

// Set baud rate to 115200.
ftStatus = FT_SetBaudRate(m_hFTDevice, (ULONG)uBaudRate);
// 8 data bits, 1 stop bit, no parity
ftStatus = FT_SetDataCharacteristics(m_hFTDevice, FT_BITS_8, FT_STOP_BITS_1, 
FT_PARITY_NONE);
// Pre purge dwell 50ms.
Sleep(uPrePurgeDwell);
// Purge the device.
ftStatus = FT_Purge(m_hFTDevice, FT_PURGE_RX | FT_PURGE_TX);
// Post purge dwell 50ms.
Sleep(uPostPurgeDwell);
// Reset device.
ftStatus = FT_ResetDevice(m_hFTDevice);
// Set flow control to RTS/CTS.
ftStatus = FT_SetFlowControl(m_hFTDevice, FT_FLOW_RTS_CTS, 0, 0);
// Set RTS.
ftStatus = FT_SetRts(m_hFTDevice);

So with a USB-to-serial driver, we set up the comms with baud rate of 115200 and the rest are default (also RTS/CTS Handshake).

USB Device Enumeration

The USB devices connected to the PC are enumerated, and serial numbers are read from the devices. For MPC320 the
serial number appears to start with "38", as seen on hardware manual p5. The number "38" is followed by six digits, which are the actual serial number. "38" is the harwadre type indicator.

APT Communication protocol

The protocol communicates through messages, which have a structure that always starts with a fixed length, 6-byte message header which, in some cases, is followed by a variable length data packet.
The header part of the message always contains information that indicates whether a data
packet follows the header and if so, the number of bytes that the data packet contains.
Values that are longer than a byte follow the Intel little-endian format.

Bytes 0 & 1 are the message ID, describing the action the message requests.
Bytes 2 & 3 give the data packet length if data packet follows or
Byte 2 gives param1 and Byte 3 gives param2. If no parameters are required, these are 0.
Byte 4 gives the destination module, or destination module | 0x80 for data packet. This
gives indication if a data packet follows or not. If the MSB of byte 4 is set, then the message will be followed by a data packet.
Byte 5 gives the source of the message.

As we have a system with 3 sub-modules (paddles), we probably have a communication system that goes through the devices motherboard to these sub-modules. The source bytes therefore likely will be

0x01 Host controller (i.e., control PC)
0x11 Rack controller, motherboard in a card slot system or comms router board
0x21 Bay 0 in a card slot system (paddle 1)
0x22 Bay 1 in a card slot system (paddle 2)
0x23 etc (paddle 3)

"The host sends a message to the motherboard that the sub-modules are plugged into, with the destination field of each message indicating which slot the message must be routed to... In slot-type systems the host can also send messages to the motherboard that the sub-modules are plugged into (destination byte = 0x11). In fact, as a very first step in the communications process, the host must send a message to the motherboard to find out which slots are used in the system... Sub-modules never send SET and REQUEST messages to the host and GET messages are always sent to the host as a destination."

Format Specifiers

  • word: Unsigned 16- bit integer (2 bytes) in the Intel (little-endian) format.
    For example, decimal 12345 (3039H) is encoded as the byte sequence 39, 30.
  • short: Signed 16-bit integer (2 bytes) in 2’s compliment format.
    For example, decimal -1 is encoded as the byte sequence FF, FF.
  • dword: Unsigned 32-bit integer (4 bytes) in the Intel (little-endian) format.
    For example, decimal 123456789 (75BCD15H) is encoded as the byte sequence 15, CD, 5B, 07
  • long:
    • Signed 32-bit integer (4 bytes) in 2’s compliment format.
      For example, decimal -1 is encoded as the byte sequence FF, FF.
    • 4 bytes in the Intel (little-endian) format.
      For example, decimal -123456789 (FFFFFFFFF8A432EBH) is encoded as the byte sequence EB, 32, A4, F8,.
  • char: 1 byte (2 digits).
  • char[N]: string of N characters.

Messages Applicable to MPC220 and MPC320

Inputs:
chanID should be possible to give two channels as input 0x01 or 0x02. But MPC320 probably has only one "channel", 0x01. Not fully clear.
destID is 0x11 for controller and 0x21-0x23 for paddles 1, 2, 3, respectively. Also called as "bays" in documentation.
hostID byte 5 is "always" 0x01, the Host Controller.
de0x80 like destID but inputted with the logical OR 0x80.
ho0x80 like hostID but inputted with the logical OR 0x80.
enabSt Enable states, 0x01 for enable, 0x02 for disable
dir The direction to Jog. 0x01 to jog forward, or 0x02 to jog in the reverse direction.
StopMd 0x01 to stop immediately, or 0x02 to stop in a controller (profiled) manner.
reqbuf A 'ctypes.int' (or so) modifiable buffer value that will be changed during command. Usually the single-byte "get" response.
data bits if the inputted command expects input value(s) more than 1 byte. This will be appended to the command header as data bits (no buffer!).

Returns:
data bits if the inputted command expects a response. This will be appended to the command (6 bits) as a buffer that the device response will fill.
The format on the table is ": <start_byte-end_byte description>, <start_byte2-end_byte2 description2>, ..."
returns is what the Python implementation should return

Command name hex ID byte 0 byte 1 byte 2 byte 3 byte 4 byte 5 data bits returns
MGMSG_MOD_IDENTIFY 0x0223 0x23 0x02 0x00 0x00 destID hostID No None (flashes LED of controller)
MGMSG_MOD_SET_CHANENABLESTATE 0x0210 0x10 0x02 chanID EnabSt destID hostID No None
MGMSG_MOD_REQ_CHANENABLESTATE 0x0211 0x10 0x02 chanID 0x00 destID hostID No N/A
MGMSG_MOD_GET_CHANENABLESTATE 0x0212 0x10 0x02 chanID reqbuf destID hostID No int (bool)
MGMSG_HW_DISCONNECT 0x0002 0x02 0x00 0x00 0x00 destID hostID No None
MGMSG_HW_START_UPDATEMSGS 0x0011 0x11 0x00 0x00 0x00 destID hostID No None
MGMSG_HW_STOP_UPDATEMSGS 0x0012 0x12 0x00 0x00 0x00 destID hostID No None
MGMSG_HW_REQ_INFO 0x0005 0x05 0x00 0x00 0x00 hostID destID No N/A
MGMSG_HW_GET_INFO 0x0006 0x06 0x00 0x54 0x00 ho0x80 hostID 84: 6-9 SN#, 10-17 model#, 18-19 type, 20-23 FW ver, 24-83 N/A, 84-85 HW ver, 86-87 Mod state, 88-89 end chars QMI_InstrumentIdentification
MGMSG_MOT_MOVE_HOME 0x0443 0x43 0x04 chanID 0x00 destID hostID No None
MGMSG_MOT_MOVE_HOMED 0x0444 0x44 0x04 chanID 0x00 hostID destID No N/A (used in combination with 0x0443 only)
MGMSG_MOT_MOVE_COMPLETED 0x0464 0x64 0x04 0x0E 0x00 ho0x80 destID 14: ??? N/A (used in combination with move commands)
MGMSG_MOT_MOVE_ABSOLUTE 0x0453 0x53 0x04 0x06 0x00 destID hostID 6: 6-7 chanID, 8-11 abs_dist None
MGMSG_MOT_MOVE_JOG 0x046A 0x6A 0x04 chanID dir destID hostID No None
MGMSG_MOT_MOVE_STOP 0x0465 0x65 0x04 chanID StopMd destID hostID No None
MGMSG_MOT_MOVE_STOPPED 0x0466 0x66 0x04 0x0E 0x00 ho0x80 destID 14: ??? N/A (used in combination with 0x0465 only)
MGMSG_MOT_SET_EEPROMPARAMS 0x04B9 0xB9 0x04 0x04 0x00 de0x80 hostID 4: 6-7 chanID, 8-9 message ID None
MGMSG_MOT_GET_UCSTATUSUPDATE 0x0491 0x91 0x04 0x0E 0x00 de0x80 hostID 14: 6-7 chanID, 8-11 position, 12-13 velocity, 14-15 motor curr, 16-19 status bits Tuple[float, float, float, int]
MGMSG_MOT_REQ_UCSTATUSUPDATE 0x0490 0x90 0x04 chanID 0x00 destID hostID No N/A
MGMSG_POL_SET_PARAMS 0x0530 0x30 0x05 0x0A 0x00 de0x80 hostID 12: 6-7 N/A, 8-9 velocity, 10-11 homepos, 12-13 jogstep1, 14-15 jogstep2, 16-17 jogstep3 None
MGMSG_POL_REQ_PARAMS 0x0531 0x31 0x05 0x00 0x00 destID hostID No N/A
MGMSG_POL_GET_PARAMS 0x0532 0x32 0x05 0x0A 0x00 ho0x80 destID 12: 6-7 N/A, 8-9 velocity, 10-11 homepos, 12-13 jogstep1, 14-15 jogstep2, 16-17 jogstep3 Tuple[float, float, List[int]]

Note that we do not suggest yet specific names for the Python functions. Also note that query functions can be combinations of two or more commands. E.g.
get_idn() -> QMI_InstrumentIdentification needs to first send the request (0x0005) and the obtain the respose with another command (0x0006).
Note also that the data bits can have specific format specifiers per byte range. Check the manual for those specifiers.

Figure out motor type and which conversions might be needed. As Thorlabs parameters are integer values, the Thorlabs values calculated from the conversion equations need to be rounded to the nearest integer. This is mostly done already in a scientist-made driver for the device, see instruments.thorlabs.mpc320 in 169-ltfiber-experiments-towards-transmission-dip branch in Diamondos.

As the motor types are different and the driver could be applied also to other hardware of Thorlabs, it could be beneficial to directly make the driver the same way as the Newport single_axis_motion_controller.py where the actuators (motors) are defined in actuators.py,
where we would now define the conversion constants as part of the actuator (motor) class. Also we can directly implement two classes, the linear and the rotational one.

Modules to be created

  • qmi.instruments.thorlabs.apt_packets.py
  • qmi.instruments.thorlabs.apt_protocol.py
  • qmi.instruments.thorlabs.mpc320.py

Modules to be modified

  • qmi.instruments.thorlabs.__init__.py

Unit-tests to be created or modified

  • tests.instruments.thorlabs.test_apt_protocol.py
  • tests.instruments.thorlabs.test_mpc320.py

Documentation to be updated

  • CHANGELOG.md
  • Confluence

Hardware

Thorlabs MPC320 (this will need to be added to the dialout group if using on Linux)

@rbudhrani rbudhrani self-assigned this Jan 8, 2024
@heevasti heevasti added the QMI driver Addition or modification on a QMI driver label Jan 12, 2024
@rbudhrani
Copy link
Collaborator Author

MGMSG_RESTOREFACTORYSETTINGS is listed under commands for the MPC320 but in the description of the command in the APT protocol manual it is only applicable to the following:

  • Benchtop Piezo Controllers (BPC301 and BPC303)
  • K-CUBE NanoTrak (KNA101-IR)
  • K-Cube Laser Source (KLS1550 and KLS635)
  • K-Cube Laser Diode Driver (KLD101) UNITS
    Seems like Thorlabs is also susceptible to copy pasta

@rbudhrani
Copy link
Collaborator Author

rbudhrani commented Feb 2, 2024

MGMSG_RESTOREFACTORYSETTINGS is listed under commands for the MPC320 but in the description of the command (page 60) in the APT protocol manual it is only applicable to the following:

  • Benchtop Piezo Controllers (BPC301 and BPC303)
  • K-CUBE NanoTrak (KNA101-IR)
  • K-Cube Laser Source (KLS1550 and KLS635)
  • K-Cube Laser Diode Driver (KLD101) UNITS
    Seems like Thorlabs is also susceptible to copy pasta

The motor control messages (page 61) also fail to mention the MPC320, so now I'm thinking that the MPC320 is a new device and only the contents page of the manual was updated without updating the commands. I'll check with Thorlabs

@heevasti heevasti added the blocked An issue is blocked by another issue label Feb 13, 2024
@rbudhrani
Copy link
Collaborator Author

Will remain blocked until reply from Thorlabs regarding certain commands

@heevasti heevasti removed the blocked An issue is blocked by another issue label Mar 11, 2024
@rbudhrani rbudhrani linked a pull request Mar 15, 2024 that will close this issue
@rbudhrani rbudhrani added the blocked An issue is blocked by another issue label Apr 2, 2024
@heevasti heevasti removed the blocked An issue is blocked by another issue label Apr 30, 2024
@rbudhrani rbudhrani removed their assignment Jul 16, 2024
@rbudhrani rbudhrani reopened this Jul 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
QMI driver Addition or modification on a QMI driver
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants