Difference between revisions of "Control Daemon"
BAndiT1983 (talk | contribs) |
|||
(33 intermediate revisions by 5 users not shown) | |||
Line 1: | Line 1: | ||
== | === Overview === | ||
'''>>>>TODO''' Overview text. | '''>>>>TODO''' Overview text. | ||
Line 17: | Line 16: | ||
All of those lead to a solid lockup of the Beta, because if you write to one of those memory addresses which are used for communicating with the PL, and there is no handler in the FPGA, the ARM cores lock up solid, no recovery possible they basically wait for an ACK/NACK forever. | All of those lead to a solid lockup of the Beta, because if you write to one of those memory addresses which are used for communicating with the PL, and there is no handler in the FPGA, the ARM cores lock up solid, no recovery possible they basically wait for an ACK/NACK forever. | ||
Research is taking place in the Labs [https://lab.apertus.org/T757 here]. | Research is taking place in the Labs [https://lab.apertus.org/T757 here]. Code can be found on [https://github.com/apertus-open-source-cinema/axiom-control-daemon GitHub] | ||
=== Structure === | === Structure === | ||
[[File:ABTDcd01- AXIOM Control Daemon.png | 1150px]] | |||
The control daemon project currently consists of three different modules: | |||
* '''Web UI''' - HTML5, sends requests to the backend, currently by using JQuery (still evaluating alternatives). | |||
* '''WSServer''' - receives WebSocket requests, converts them to Flatbuffers packages and sends them to the daemon, through socket. | |||
* '''Daemon''' - processes flatbuffer packages received over a UNIX domain socket and calls suitable handler. | |||
The communication with the daemon is done via a UNIX domain socket. There are two different protocols used when communicating with the daemon. A handshake protocol which tells the user what parameters and modules are available, their minimum and maximum value, as well as a description. | |||
Preliminary handshake protocol: | |||
<pre style="white-space: pre-wrap">[ | |||
{ | |||
"module": "image_sensor", | |||
"parameter": "analog_gain", | |||
"possibleValues": [ | |||
"1/3", "2/3", "1", "3/3", "4/3", "2", "3", "4" | |||
], | |||
"currentValue": "", | |||
"defaultValue": "1", | |||
"range": [], | |||
"readOnly": false | |||
}, | |||
{ | |||
"module": "image_sensor", | |||
"parameter": "digital_gain", | |||
"possibleValues": [ | |||
"1", "2", "3", "4", "6", "8", "10", "12", "14", "16" | |||
], | |||
"currentValue": "", | |||
"defaultValue": "1", | |||
"range": [], | |||
"readOnly": false | |||
} | |||
] | |||
</pre> | |||
At the moment this parameters are residing in '''description.json''', which is read by the daemon at the initialization phase. If following command is received, then the daemon fills in current values, places the data under '''value1''' and sends it back to caller: | |||
<pre style="white-space: pre-wrap"> | |||
module: general | |||
parameter: available_parameters | |||
</pre> | |||
The second protocol is used for writing and reading the different parameters. It uses [https://google.github.io/flatbuffers/ Flatbuffers]. The schema for Flatbuffers can be found [https://github.com/apertus-open-source-cinema/axiom-control-daemon/blob/master/Schema/axiom_daemon.fbs here]. | |||
Communication of the Web UI with the daemon it bridged from the UNIX domain socket and flatbuffers to websocket and JSON by the WSServer. The WSServer accepts following fields, which get translated to the Flatbuffers schema (and vice versa): | |||
{| | |||
|'''Field'''||'''Type'''||'''Example'''||'''Comment''' | |||
|- | |||
| || || || | |||
|- | |||
|sender||string||WSServer|| | |||
|- | |||
|module||string||"image_sensor"|| | |||
|- | |||
|command||string||"set" or "get"|| | |||
|- | |||
|parameter||string||"analog_gain"|| | |||
|- | |||
|value1||string||"4"|| | |||
|- | |||
|value2||string||"5.7"|| | |||
|- | |||
|status||string||"success" or "fail" ||used for reply from Daemon | |||
|- | |||
|message||string|| ||status message, to get more info when request fails | |||
|- | |||
|timestamp||string|| ||date and time of camera, when the request was send back to client | |||
|} | |||
<span style="color: red; font-weight: bold">TODO: Add JSON/REST package description from Lab (https://lab.apertus.org/T865)</span> | <span style="color: red; font-weight: bold">TODO: Add JSON/REST package description from Lab (https://lab.apertus.org/T865)</span> | ||
=== Build === | |||
'''Required packages''' (names are varying between Linux distributions): | |||
* cmake | |||
* clang | |||
* ninja | |||
* git | |||
'''Steps''': | |||
* Install required packages | |||
* Clone the [https://github.com/apertus-open-source-cinema/axiom-control-daemon repo]: <code>git clone --recursive https://github.com/apertus-open-source-cinema/axiom-control-daemon</code> | |||
* cd into cloned repo | |||
* <code>mkdir build && cd build</code> | |||
* <code>cmake -GNinja ..</code> | |||
* <code>ninja</code> | |||
=== Setup daemon === | === Setup daemon === | ||
Line 42: | Line 120: | ||
=== Setup WebUI === | === Setup WebUI === | ||
===Image Sensor Register Information=== | |||
<br> | |||
<p><span class = "typ"> Note : </span> <span style="color:blue">Register_num[ x : y ]</span> means we want to access the <span style="color:blue">y+1 th</span> to <span style="color:blue">x+1 th</span> bits of <span style="color:blue">Register_num</span> . So Register <span style="color:blue">71[15 : 0]</span> means that we want to access the <span style="color:blue">1st </span> to <span style="color:blue">16th</span> bit of the register number <span style="color:blue">71</span>. </p> | |||
<p>[https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=61 Register Overview]</p> | |||
{| class="wikitable" | |||
|- | |||
! Register Name | |||
! Register Address | |||
! Default Value | |||
! Description | |||
|- | |||
| Image_flipping | |||
| 69[1:0] | |||
| 0 | |||
| <poem>The image coming out of the image sensor, can be flipped in X and/or Y direction. When flipping in Y is enable, the | |||
bottom left pixel (0, 3071) is read out first instead of the top left one (0, 0). When flipping in X is enabled only the | |||
pixels within a channel are flipped on the X-axis, not the channels themselves. Flipping in X is only supported when | |||
using 32 channels per side .<br> | |||
0: No image flipping | |||
1: Image flipping in X | |||
2: Image flipping in Y | |||
3: Image flipping in X and Y</poem> | |||
|- | |||
| Exp_ext | |||
| 70[0] | |||
| 0 | |||
| <poem>The exposure time can be programmed in two ways, externally or internally. Externally, the exposure time is defined | |||
as the time between the rising edge of [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=14 T_EXP1] and the rising edge of [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=14 FRAME_REQ] .Internally, the exposure time is set by uploading the desired value to the corresponding sequencer register.<br> | |||
0: Exposure time is defined by the value uploaded in the | |||
sequencer register (71-72) | |||
1: Exposure time is defined by the pulses applied to the | |||
T_EXP1 and FRAME_REQ pins</poem> | |||
|- | |||
| Exp_time | |||
| 71-72[7:0] | |||
<poem><br>(<br><span style="white-space: nowrap;">Exp_time[15:0] = Reg 71[15:0]</span> | |||
<span style="white-space: nowrap;">Exp_time[23:16] = Reg 72[7:0]</span> <br>)</poem> | |||
| 1536 | |||
| <poem>When the Exp_ext register is set to ‘0’, the value in this | |||
register defines the exposure time according to the [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=33 formula] </poem> | |||
|- | |||
| Offset_bot | |||
| 87[11:0] | |||
| 780 | |||
| <poem>A digital offset can be applied to the output signal. The value in this register defines the dark level offset | |||
applied to the bottom(OUT1_N/P to OUT32_N/P) output signal (min = 0, max = 4095) [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=67 More Info] </poem> | |||
|- | |||
| Offset_top | |||
| 88[11:0] | |||
| 780 | |||
| <poem>A digital offset can be applied to the output signal. The value in this register defines the dark level offset | |||
applied to the top(OUT33_P/N to OUT64_P/N) output signal (min = 0, max = 4095) [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=67 More Info]</poem> | |||
|- | |||
| Number_lines_tot | |||
| 1 | |||
| 3072 | |||
| <poem>The value in this register defines the number of lines read | |||
out by the sensor (min=1, max=3072)</poem> | |||
|- | |||
| PGA_gain | |||
| 115[2:0] | |||
| 0 | |||
| <poem>0: unity gain | |||
1: x2 gain | |||
3: x3 gain | |||
7: x4 gain</poem> | |||
|- | |||
| PGA_div | |||
| 115[3] | |||
| 0 | |||
| <poem>1: divide the output signal by 3</poem> | |||
|- | |||
| ADC_range | |||
| 116[7:0] | |||
| 127 | |||
| <poem>Change the slope and the input range of the ramp used by the ADC [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=53 More Info] </poem> | |||
|- | |||
| ADC_range_mult | |||
| 116[9:8] | |||
| 1 | |||
| <poem>Change the slope and the input range of the ramp used by the ADC [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=53 More Info]<br> | |||
0: 8 bit (x1) | |||
1: 10bit (x2) | |||
3: 12bit (x4) | |||
</poem> | |||
|- | |||
|- | |||
| ADC_range_mult2 | |||
| 100[1:0] | |||
| 0 | |||
| <poem>Extends the ADC range for slow input clock speeds. `ADC_range_mult` | |||
has to be set to 3 for all bit modes when using this. [https://kiquance21.github.io/ApertusTest/pdf/datasheet_cmv12000_v2.11.pdf#page=53 More Info]<br> | |||
0: x4 | |||
1: x8 | |||
3: x16 | |||
</poem> | |||
|- | |||
|} | |||
===DaemonCLI=== | |||
To set/get parameters from command line, '''DaemonCLI''' can be used: | |||
'''Syntax''': DaemonCLI <module> set/get <parameter> <value> | |||
====Predefined Commands==== | |||
Specific commands are available which allow making abstracted parameter changes. The Control Daemon will automatically set all the underlying image sensor register values. | |||
'''Examples''': | |||
<br><br> | |||
Analog Gain ( [https://wiki.apertus.org/index.php/Sandbox#Image_Sensor_Register_Information Register Info] ) | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor set analog_gain 2 // Set the image sensor analog gain to value "2"</pre> | |||
This command is equivalent to : | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor set config_register 115 1 // Setting Gain (x2) | |||
DaemonCLI image_sensor set config_register 116 0x3d5 // ADC_range fine-tuned for gain value | |||
DaemonCLI image_sensor set config_register 100 1 //ADC_range_mult2 | |||
DaemonCLI image_sensor set config_register 87 2000 //Bottom channel output offset | |||
DaemonCLI image_sensor set config_register 88 2000 //Top channel output offset | |||
</pre> | |||
====Setting and Getting Parameters Explicitly==== | |||
<p>With these commands we can set or get value of each register individually </p> | |||
'''Examples''': | |||
<br><br> | |||
Number of Lines to be read ( [https://wiki.apertus.org/index.php/Sandbox#Image_Sensor_Register_Information Register Info] ) | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor get config_register 1 // get number of lines to be read</pre> | |||
Image Flipping ( [https://wiki.apertus.org/index.php/Sandbox#Image_Sensor_Register_Information Register Info] ) | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor set config_register 69 2 //Flip image in Y direction</pre> | |||
Setting Exposure Time ( [https://wiki.apertus.org/index.php/Sandbox#Image_Sensor_Register_Information Register Info] ) | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor set config_register 70 0 // Setting register to use internal exposure mode | |||
DaemonCLI image_sensor set config_register 71 1536 | |||
DaemonCLI image_sensor set config_register 72 0 </pre> | |||
Digital Offset Bottom ( [https://wiki.apertus.org/index.php/Sandbox#Image_Sensor_Register_Information Register Info] ) | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor set config_register 87 1824</pre> | |||
Digital Offset Top ( [https://wiki.apertus.org/index.php/Sandbox#Image_Sensor_Register_Information Register Info] ) | |||
<pre style="white-space: pre-wrap">DaemonCLI image_sensor set config_register 88 1824</pre> | |||
====Available modules==== | |||
{| | |||
|general||General methods, like getting available parameters through get_available_methods | |||
|- | |||
|image_sensor||CMV12000 (currently) | |||
|} | |||
==== Available parameters (per module)==== | |||
'''image_sensor''' | |||
{| | |||
|digital_gain||Digital gain | |||
|- | |||
|analog_gain||Analog gain | |||
|- | |||
|config_register||read/write arbitrary sensor config register (further parameters are index and value) | |||
|} | |||
===Development notes=== | |||
'''CMV12000Adapter''' will be used as example. Please look at the class for examples of implementation. | |||
====Add new parameters==== | |||
Before registering new parameters, two methods should be added: a setter and a getter. | |||
Declaration syntax: | |||
bool <setter_name>(std::string value1, std::string value2, std::string& message)<br/> | |||
bool <getter_name>(std::string& value, std::string& message) | |||
Note the ampersand ('''&''') after the type, it is very '''important''' for returning multiple values. As methods can return only one value, '''bool''' in this case, variables can be passed by reference ('''&''') to be able to set their values inside methods. Values can be modified as usual and the value will be passed back to the caller (see '''IDaemonModule.h''' and '''MessageHandler.cpp''' for examples). | |||
Setter receives two values, in case just one is required '''value2''' will be 0 (zero). | |||
After the setter and getter are implemented, it's time to attach them to a parameter name. Here they are registered to '''gain''' parameter: | |||
void CMV12000Adapter::RegisterAvailableMethods()<br/> | |||
{<br/> | |||
AddParameterHandler("analog_gain", GETTER_FUNC(&CMV12000Adapter::GetAnalogGain), SETTER_FUNC(&CMV12000Adapter::SetAnalogGain));<br/> | |||
AddParameterHandler("digital_gain", GETTER_FUNC(&CMV12000Adapter::GetDigitalGain), SETTER_FUNC(&CMV12000Adapter::SetDigitalGain));<br/> | |||
} | |||
This code will attach methods like '''SetAnalogGain()''' and '''GetAnalogGain()''' to the corresponding parameter "analog_gain". | |||
=== Unit tests === | === Unit tests === |
Latest revision as of 21:31, 3 July 2019
1 Overview
>>>>TODO Overview text.
Currently, booting up the camera is as follows:
- A systemd service is activated which runs a shell script.
- This script then loads a bitstream into the FPGA and uses other scripts and C programs to train LVDS channels and set up the HDMI output
When the service is disabled, the user can run this script manually, which:
- Does not keep the user from running if it has already been activated by systemd.
- And on the other hand, simple scripts which query the registers (e.g. to get the temperature of the sensor) can be activated even if the FPGA bitstream didn't load.
All of those lead to a solid lockup of the Beta, because if you write to one of those memory addresses which are used for communicating with the PL, and there is no handler in the FPGA, the ARM cores lock up solid, no recovery possible they basically wait for an ACK/NACK forever.
Research is taking place in the Labs here. Code can be found on GitHub
2 Structure
The control daemon project currently consists of three different modules:
- Web UI - HTML5, sends requests to the backend, currently by using JQuery (still evaluating alternatives).
- WSServer - receives WebSocket requests, converts them to Flatbuffers packages and sends them to the daemon, through socket.
- Daemon - processes flatbuffer packages received over a UNIX domain socket and calls suitable handler.
The communication with the daemon is done via a UNIX domain socket. There are two different protocols used when communicating with the daemon. A handshake protocol which tells the user what parameters and modules are available, their minimum and maximum value, as well as a description.
Preliminary handshake protocol:
[ { "module": "image_sensor", "parameter": "analog_gain", "possibleValues": [ "1/3", "2/3", "1", "3/3", "4/3", "2", "3", "4" ], "currentValue": "", "defaultValue": "1", "range": [], "readOnly": false }, { "module": "image_sensor", "parameter": "digital_gain", "possibleValues": [ "1", "2", "3", "4", "6", "8", "10", "12", "14", "16" ], "currentValue": "", "defaultValue": "1", "range": [], "readOnly": false } ]
At the moment this parameters are residing in description.json, which is read by the daemon at the initialization phase. If following command is received, then the daemon fills in current values, places the data under value1 and sends it back to caller:
module: general parameter: available_parameters
The second protocol is used for writing and reading the different parameters. It uses Flatbuffers. The schema for Flatbuffers can be found here.
Communication of the Web UI with the daemon it bridged from the UNIX domain socket and flatbuffers to websocket and JSON by the WSServer. The WSServer accepts following fields, which get translated to the Flatbuffers schema (and vice versa):
Field | Type | Example | Comment |
sender | string | WSServer | |
module | string | "image_sensor" | |
command | string | "set" or "get" | |
parameter | string | "analog_gain" | |
value1 | string | "4" | |
value2 | string | "5.7" | |
status | string | "success" or "fail" | used for reply from Daemon |
message | string | status message, to get more info when request fails | |
timestamp | string | date and time of camera, when the request was send back to client |
TODO: Add JSON/REST package description from Lab (https://lab.apertus.org/T865)
3 Build
Required packages (names are varying between Linux distributions):
- cmake
- clang
- ninja
- git
Steps:
- Install required packages
- Clone the repo:
git clone --recursive https://github.com/apertus-open-source-cinema/axiom-control-daemon
- cd into cloned repo
mkdir build && cd build
cmake -GNinja ..
ninja
4 Setup daemon
5 Setup WebUI
6 Image Sensor Register Information
Note : Register_num[ x : y ] means we want to access the y+1 th to x+1 th bits of Register_num . So Register 71[15 : 0] means that we want to access the 1st to 16th bit of the register number 71.
Register Name | Register Address | Default Value | Description |
---|---|---|---|
Image_flipping | 69[1:0] | 0 | The image coming out of the image sensor, can be flipped in X and/or Y direction. When flipping in Y is enable, the |
Exp_ext | 70[0] | 0 | The exposure time can be programmed in two ways, externally or internally. Externally, the exposure time is defined |
Exp_time | 71-72[7:0]
|
1536 | When the Exp_ext register is set to ‘0’, the value in this |
Offset_bot | 87[11:0] | 780 | A digital offset can be applied to the output signal. The value in this register defines the dark level offset |
Offset_top | 88[11:0] | 780 | A digital offset can be applied to the output signal. The value in this register defines the dark level offset |
Number_lines_tot | 1 | 3072 | The value in this register defines the number of lines read |
PGA_gain | 115[2:0] | 0 | 0: unity gain |
PGA_div | 115[3] | 0 | 1: divide the output signal by 3 |
ADC_range | 116[7:0] | 127 | Change the slope and the input range of the ramp used by the ADC More Info |
ADC_range_mult | 116[9:8] | 1 | Change the slope and the input range of the ramp used by the ADC More Info |
ADC_range_mult2 | 100[1:0] | 0 | Extends the ADC range for slow input clock speeds. `ADC_range_mult` |
7 DaemonCLI
To set/get parameters from command line, DaemonCLI can be used:
Syntax: DaemonCLI <module> set/get <parameter> <value>
7.1 Predefined Commands
Specific commands are available which allow making abstracted parameter changes. The Control Daemon will automatically set all the underlying image sensor register values.
Examples:
Analog Gain ( Register Info )
DaemonCLI image_sensor set analog_gain 2 // Set the image sensor analog gain to value "2"
This command is equivalent to :
DaemonCLI image_sensor set config_register 115 1 // Setting Gain (x2) DaemonCLI image_sensor set config_register 116 0x3d5 // ADC_range fine-tuned for gain value DaemonCLI image_sensor set config_register 100 1 //ADC_range_mult2 DaemonCLI image_sensor set config_register 87 2000 //Bottom channel output offset DaemonCLI image_sensor set config_register 88 2000 //Top channel output offset
7.2 Setting and Getting Parameters Explicitly
With these commands we can set or get value of each register individually
Examples:
Number of Lines to be read ( Register Info )
DaemonCLI image_sensor get config_register 1 // get number of lines to be read
Image Flipping ( Register Info )
DaemonCLI image_sensor set config_register 69 2 //Flip image in Y direction
Setting Exposure Time ( Register Info )
DaemonCLI image_sensor set config_register 70 0 // Setting register to use internal exposure mode DaemonCLI image_sensor set config_register 71 1536 DaemonCLI image_sensor set config_register 72 0
Digital Offset Bottom ( Register Info )
DaemonCLI image_sensor set config_register 87 1824
Digital Offset Top ( Register Info )
DaemonCLI image_sensor set config_register 88 1824
7.3 Available modules
general | General methods, like getting available parameters through get_available_methods |
image_sensor | CMV12000 (currently) |
7.4 Available parameters (per module)
image_sensor
digital_gain | Digital gain |
analog_gain | Analog gain |
config_register | read/write arbitrary sensor config register (further parameters are index and value) |
8 Development notes
CMV12000Adapter will be used as example. Please look at the class for examples of implementation.
8.1 Add new parameters
Before registering new parameters, two methods should be added: a setter and a getter.
Declaration syntax:
bool <setter_name>(std::string value1, std::string value2, std::string& message)
bool <getter_name>(std::string& value, std::string& message)
Note the ampersand (&) after the type, it is very important for returning multiple values. As methods can return only one value, bool in this case, variables can be passed by reference (&) to be able to set their values inside methods. Values can be modified as usual and the value will be passed back to the caller (see IDaemonModule.h and MessageHandler.cpp for examples).
Setter receives two values, in case just one is required value2 will be 0 (zero).
After the setter and getter are implemented, it's time to attach them to a parameter name. Here they are registered to gain parameter:
void CMV12000Adapter::RegisterAvailableMethods()
{
AddParameterHandler("analog_gain", GETTER_FUNC(&CMV12000Adapter::GetAnalogGain), SETTER_FUNC(&CMV12000Adapter::SetAnalogGain));
AddParameterHandler("digital_gain", GETTER_FUNC(&CMV12000Adapter::GetDigitalGain), SETTER_FUNC(&CMV12000Adapter::SetDigitalGain));
}
This code will attach methods like SetAnalogGain() and GetAnalogGain() to the corresponding parameter "analog_gain".
9 Unit tests
Unit tests have been added to the project to verify correct functionality. Catch2 framework is used because it's single-header only and utilizes the C++11 way of doing things.
Note: (for development on PC) - RAM access of the camera is different from x86/x64 CPUs, modified classes have to be used to bypass this, otherwise SEGFAULT would be the result.
In the CMake scripts a switch called ENABLE_MOCK was added so that users can disable any code which won't work on a regular PC (see CMV12000AdapterTests.cpp for an example). While running the build on camera cmake ..
is sufficient, but for development one should use:
$ cmake -DENABLE_MOCK=ON ..