Overview
this page will contain
- architecture
- class diagrams
- how to add a new controller
- how to add a new task
Relationship diagram¶
classDiagram
Controller <-- Mosca
DataHandler <-- Mosca
Spectra <-- DataHandler
Stats <-- DataHandler
Task <-- DataHandler
CircularBuffer <-- Spectra
CircularBuffer <-- Stats
CircularBuffer <-- Task
Clarifications
- these are association relationships only (e.g: Controller has no reference to Mosca and can be instanciated on its own).
- Spectra, Stats and Task each contain their own CircularBuffer.
Workflow¶
Prepare¶
Shortcut
Users can directly call start_mosca instead of calling apply_mosca, prepare, and start_acq.
sequenceDiagram
participant User
participant Mosca
participant Controller
participant Manager
participant Buffers
autonumber
User->>Mosca: acq_nb_points
User->>Mosca: ...
User->>Mosca: gate_mode
User->>Mosca: apply_mosca()
Mosca->>Controller: apply_mosca(...)
User->>Mosca: prepare()
Mosca->>Controller: prepare(...)
Mosca->>Controller: get_...
Controller-->>Mosca: channels
Controller-->>Mosca: stats_names
Controller-->>Mosca: spectrum_size
Mosca->>Manager: prepare(...)
Manager->>Buffers: prepare(...)
Buffers->>Buffers: setup, alloc, ...
buffers
In that diagram, Tasks (Rois, ...) are not shown, but their workflow is the same as the Buffers (spectra, stats).
In words:
- Steps 1, 2, 3: user sets acquisition parameters
- Steps 4, 5: parameters are applied to the controller, controller should validate the given parameters.
-
Steps 6 to 11: when prepare is called everything should be set up for the acquisition, so that Mosca can retrieve the following information from the controller:
- list of channels
- spectrum size
- statistics names (if any)
-
Steps 12, 13: Mosca sends those information to the Manager so the buffers and tasks can be prepared.
Start¶
sequenceDiagram
participant User
participant Mosca
participant Controller
participant Manager
participant Buffers
autonumber
User->>Mosca: start_acq()
Mosca->>Manager: notify_start()
Manager-->>Buffers: lock()
Manager-->>Buffers: notify_start()
Manager->>Manager: start() data thread
Mosca->>Mosca: start() polling thread
Mosca->>Controller: start_acq()
par Mosca to Controller
loop Polling thread
Mosca-->>Controller: poll_acq()
Mosca-->>Manager: add_spectra(...)
end
and Manager to Manager
loop Data thread
Manager-->>Manager: notify_newdata()
Manager-->>Manager: wait_data()
Manager-->>Buffers: add_data()
end
end
- Step 1 to 4: buffers/tasks are notified that an acquisition is about to start.
- Step 5: the data thread is started. This thread runs the tasks (Rois, Sums), and waits on the new_data queue filled by the data handler when new data arrives.
- Step 6: the polling loop thread is started. It calls the controller's poll_acq function at regular intervals.
- Step 7: controller starts acquisition
- Step 9: every time the polling loop gets some new data, it sends it to the data handler (add_spectra).
- Step 10, 11: when data is passed to it by Mosca, the data hander signals its data thread that it has received N points. The tasks, if any, are then run on those new points. The tasks results are store in their respective buffers.
Stop¶
The stop workflow is the same whether the stop was triggered by the hardware (e.g: requested number of points reached or acquisition stopped due to an error) or requested by the user. Obviously the only difference are the first two steps of the diagram.
sequenceDiagram
participant User
participant Mosca
participant Controller
participant Manager
participant Buffers
autonumber
User->>Mosca: stop_acq()
par
Mosca->>Controller: stop_acq()
loop Polling thread
Mosca-->>Controller: poll_acq()
end
end
Mosca->>Manager: notify_end()
Manager->Manager: join() data thread
Manager->>Buffers: notify_end()
Manager->>Buffers: unlock()