1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use std::sync::mpsc::{Receiver, Sender};
use hidapi::HidDevice;
use log::{error, trace};
use crate::PowerStatus;
use crate::scope::{commands, StatusResponseLegacy};
use crate::scope::commands::Command;
impl crate::Nlab {
pub(crate) fn run_v1(
hid_device: HidDevice,
command_tx: Sender<Command>,
command_rx: Receiver<Command>,
fw_version: Arc<RwLock<Option<u16>>>,
power_status: Arc<RwLock<PowerStatus>>,
) {
let mut active_requests_map: HashMap<u8, Command> = HashMap::new();
let mut active_data_request: Option<u8> = None;
let mut incoming_usb_buffer: [u8; 64] = [0u8; 64];
let mut outgoing_usb_buffer: [u8; 65] = [0u8; 65];
let mut request_id: u8 = 0;
'communication: loop {
// Check first to see if we have a cancelled active request
if let Some(id) = &active_data_request {
// We have an active request id
if let Command::RequestData(rq) = active_requests_map.get(id).unwrap() {
// we get the active request
if let Ok(()) = rq.stop_recv.try_recv() {
// We have received a stop signal
command_tx.send(Command::StopData).unwrap();
}
}
}
// check for an incoming command from the user
// Do one of the following:
// 1. Write a request to do the command
// 2. Write a null packet to request an update on the power status
if let Ok(mut command) = command_rx.try_recv() {
if let Command::Quit = &command {
break 'communication;
}
// Process the command
// 1. fill the outgoing USB buffer
outgoing_usb_buffer.fill(0);
let result = command.fill_tx_buffer_legacy(&mut outgoing_usb_buffer);
if result.is_ok() {
// If we can successfully create a request packet, then
// 2. increment the request id
// 3. send the request packet
{
//TODO: make this block more concise
request_id = request_id.wrapping_add(1);
if request_id == 0 {
request_id += 1
}
outgoing_usb_buffer[2] = request_id;
}
if hid_device.write(&outgoing_usb_buffer).is_err() {
eprintln!("USB write error, ending nLab connection");
break 'communication;
}
if let Command::RequestData(_) = &command {
active_data_request = Some(request_id);
}
active_requests_map.insert(request_id, command);
trace!("Sent request {request_id}");
} else {
// If we cannot successfully create a request packet, then
// 1. Print the error
// 2. send a null request for status
eprintln!("{result:?}");
if hid_device.write(&commands::NULL_REQ).is_err() {
eprintln!("USB write error, ending nLab connection");
break 'communication;
}
}
} else if hid_device.write(&commands::NULL_REQ).is_err() {
eprintln!("USB write error, ending nLab connection");
break 'communication;
}
// Read the incoming command and process it
if hid_device.read(&mut incoming_usb_buffer).is_err() {
eprintln!("USB read error, ending nLab connection");
break 'communication;
}
let response = StatusResponseLegacy::new(&incoming_usb_buffer);
let version = response.fw_version as u16;
*fw_version.write().unwrap() = Some(version);
power_status.write().unwrap().state = response.power_state;
power_status.write().unwrap().usage = response.power_usage as f64 * 5.0 / 255.0;
// close out request if it's open
if response.request_id > 0 {
// If we have an active request with this ID
if let Some(command) = active_requests_map.get(&response.request_id)
{
// Handle the incoming usb packet
command.handle_rx_legacy(&incoming_usb_buffer);
// If the command has finished its work
if command.is_finished() {
// Set the active data request as none if we just finished it
active_data_request = active_data_request.filter(|&id| id != response.request_id);
// Remove this request from the active map
if let Some(Command::StopData) = active_requests_map.remove(&response.request_id) {
// If we received the ACK on a stop command, check if we have an active id
if let Some(active_id) = &active_data_request {
// Look up that ID, remove the command from the active map
if let Some(Command::RequestData(rq)) = active_requests_map.remove(active_id) {
// If that command is a request data command
*rq.remaining_samples.write().unwrap() = 0;
}
active_data_request = None;
}
}
trace!("Finished request ID: {}, ADRQ: {active_data_request:?}", response.request_id);
} else {
trace!("Received request ID: {}, ADRQ: {active_data_request:?}", response.request_id);
}
} else {
error!("Received response for request {}, but cannot find a record of that request", response.request_id);
}
}
}
}
}