Differences
This shows you the differences between two versions of the page.
Both sides previous revisionPrevious revisionNext revision | Previous revisionLast revisionBoth sides next revision | ||
projects:acb8300 [2016/01/02 22:56] – Andreas Böhler | projects:acb8300 [2016/01/25 23:19] – Andreas Böhler | ||
---|---|---|---|
Line 6: | Line 6: | ||
This page describes the USB protocol as well as the work towards integrating it into Argyll CMS. | This page describes the USB protocol as well as the work towards integrating it into Argyll CMS. | ||
+ | |||
+ | ===== First steps with the calibrator ===== | ||
+ | |||
+ | At first, I poked around the installation directory of True Color Pro and - to my surprise - found a DLL called LG_ACB8300.dll. This sounds interesting. I fired up Dependency Walker to get the exported functions: | ||
+ | |||
+ | * LG_Calibrator_CloseWaitButton | ||
+ | * LG_Calibrator_DeviceCheck_Signage | ||
+ | * LG_Calibrator_DeviceClose | ||
+ | * LG_Calibrator_DeviceClose_Signage | ||
+ | * LG_Calibrator_DeviceNumberRead | ||
+ | * LG_Calibrator_DeviceNumberWrite | ||
+ | * LG_Calibrator_DeviceOpen | ||
+ | * LG_Calibrator_DeviceOpen_Signage | ||
+ | * LG_Calibrator_GetADC | ||
+ | * LG_Calibrator_GetAPIVersion | ||
+ | * LG_Calibrator_GetFWVersion | ||
+ | * LG_Calibrator_GetXYZ | ||
+ | * LG_Calibrator_GetXYZ_Signage | ||
+ | * LG_Calibrator_SetMonitorType | ||
+ | * LG_Calibrator_StartWaitButton | ||
+ | |||
+ | I don't know what " | ||
+ | |||
+ | Thanks to his work, I could code a simple Python wrapper and later a simple C wrapper in order to debug the DLL. | ||
===== Debugging the LG_ACB8300.dll ===== | ===== Debugging the LG_ACB8300.dll ===== | ||
- | I traced parts of the LG_ACB8300.dll with OllyDBG. I built a small C wrapper around the library in order to have access to the funtions and their parameters. The wrapper simply loads the DLL entry points and calls DeviceOpen, Get_ADC, Get_XYZ, etc. in order to reverse engineer the functionality. | + | I traced parts of the LG_ACB8300.dll with OllyDBG. I built a Python and a small C wrapper around the library in order to have access to the funtions and their parameters. The wrapper simply loads the DLL entry points and calls DeviceOpen, Get_ADC, Get_XYZ, etc. in order to reverse engineer the functionality. |
Inside the Get_XYZ function, a lot of floating point magic is going on. After reversing all the floating point assembly, it turns out that the conversion from ADC to XYZ is performing as follows: | Inside the Get_XYZ function, a lot of floating point magic is going on. After reversing all the floating point assembly, it turns out that the conversion from ADC to XYZ is performing as follows: | ||
- Read ADC value from device | - Read ADC value from device | ||
- | - Do an offset correction (can be read from calibration) | + | - Do an offset correction (can be read from calibration, **subract** A from the USB protocol) |
- | - Apply a correction matrix (can be read from calibration) | + | - Apply a correction matrix (can be read from calibration, **multiply** by M from the USB protocol) |
- | - Do an offset correction (can be read from calibration) | + | - Do an offset correction (can be read from calibration, **add** X from the USB protocol) |
- | - Apply a monitor correction matrix | + | - Apply a monitor correction matrix |
The monitor correction matrix is hardcoded in the DLL. The SetMonitorType() function simply loads a different matrix into memory. | The monitor correction matrix is hardcoded in the DLL. The SetMonitorType() function simply loads a different matrix into memory. | ||
Line 38: | Line 62: | ||
===== Hacking the USB protocol ===== | ===== Hacking the USB protocol ===== | ||
- | The USB protocol consists of input reports and output reports, with a fixed length of 43 bytes. The host speaks first, the device responds (most of the time). | + | The USB protocol consists of input reports and output reports, with a fixed length of 43 bytes. The host speaks first, the device responds (most of the time). |
+ | |||
+ | They seem to not clear the send buffer before responding to a command. Thus, you always get the remaining bytes of the previous commands as well! | ||
==== Initialisation ==== | ==== Initialisation ==== | ||
Send: '' | Send: '' | ||
- | Response: '' | + | Response: '' |
+ | |||
+ | This seems to initialise the device. The bytes in the response are yet unknown. | ||
==== Read Calibration ==== | ==== Read Calibration ==== | ||
+ | |||
+ | Get the different calibration matrices and offset values from the device. M is a 3x3 matrix for the ADC to XYZ conversion, A is the first ADC offset, X is the second XYZ offset (both being a vector of length 3). | ||
Send: '' | Send: '' | ||
Response: '' | Response: '' | ||
+ | |||
+ | ^ Bytes ^ Format ^ Description ^ | ||
+ | | 0-7 | double | M[0][0] | | ||
+ | | 8-15 | double | M[0][1] | | ||
+ | | 16-23 | double | M[0][2] | | ||
+ | | 24-31 | double | M[1][0] | | ||
+ | | 32-39 | double | M[1][1] | | ||
+ | |||
Send: '' | Send: '' | ||
Response: '' | Response: '' | ||
+ | |||
+ | ^ Bytes ^ Format ^ Description ^ | ||
+ | | 0-7 | double | M[1][2] | | ||
+ | | 8-15 | double | M[2][0] | | ||
+ | | 16-23 | double | M[2][1] | | ||
+ | | 24-31 | double | M[2][2] | | ||
Send: '' | Send: '' | ||
Response: '' | Response: '' | ||
+ | |||
+ | ^ Bytes ^ Format ^ Description ^ | ||
+ | | 0-7 | double | A[0] | | ||
+ | | 8-15 | double | A[1] | | ||
+ | | 16-23 | double | A[2] | | ||
+ | | 24-31 | double | X[0] | | ||
+ | | 32-39 | double | X[1] | | ||
Send: '' | Send: '' | ||
- | Response: '' | + | Response: '' |
+ | |||
+ | ^ Bytes ^ Format ^ Description ^ | ||
+ | | 0-7 | double | X[2] | | ||
==== Read ADC values ==== | ==== Read ADC values ==== | ||
+ | |||
+ | Read ADC values from the device. | ||
Send: '' | Send: '' | ||
Response: '' | Response: '' | ||
+ | |||
+ | ^ Bytes ^ Format ^ Description ^ | ||
+ | | 1-2 | int | unknown | | ||
+ | | 3-4 | int | Z value | | ||
+ | | 5-6 | int | Y value | | ||
+ | | 7-8 | int | X value | | ||
==== Read Firmware version ==== | ==== Read Firmware version ==== | ||
Line 68: | Line 130: | ||
Send: '' | Send: '' | ||
Response: '' | Response: '' | ||
+ | |||
+ | ^ Bytes ^ Format ^ Description ^ | ||
+ | | 1 | int | Firmare Version | | ||
+ | |||
+ | In order to derive the firmware version, divide the value by 100. My device reports '' | ||
==== Wait for button inpurt ==== | ==== Wait for button inpurt ==== | ||
Line 75: | Line 142: | ||
Whenever the button is pressed, the device sends '' | Whenever the button is pressed, the device sends '' | ||
+ | |||
+ | ===== ArgyllCMS support ===== | ||
+ | |||
+ | Although the device will probably be never officially supported by ArgyllCMS, I developed an initial driver for the device. You can find the patch for Argyll 1.8.3 {{: |