1use std::collections::BTreeMap;
4
5use strum::{Display, EnumString};
6use uuid::{uuid, Uuid};
7
8use crate::Filters;
9
10use super::transport;
11
12#[derive(Clone, PartialEq, Debug)]
14pub struct LedgerInfo {
15 pub model: Model,
17
18 pub conn: ConnInfo,
20}
21
22impl std::fmt::Display for LedgerInfo {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(f, "{} ({})", self.model, self.conn)
25 }
26}
27
28impl LedgerInfo {
29 pub fn kind(&self) -> ConnType {
31 match &self.conn {
32 #[cfg(feature = "transport_usb")]
33 ConnInfo::Usb(_) => ConnType::Usb,
34 #[cfg(feature = "transport_tcp")]
35 ConnInfo::Tcp(_) => ConnType::Tcp,
36 #[cfg(feature = "transport_ble")]
37 ConnInfo::Ble(_) => ConnType::Ble,
38 }
39 }
40}
41
42#[derive(Copy, Clone, PartialEq, Debug, Display, EnumString)]
44pub enum Model {
45 NanoS,
47 NanoSPlus,
49 NanoX,
51 Stax,
53 Flex,
55 NanoGen5,
57 Unknown { usb_pid: Option<u16> },
59}
60
61impl Model {
62 pub fn from_usb_pid(usb_pid: u16) -> Model {
64 INTERNAL_DEVICE_INFOS
65 .iter()
66 .find_map(|device_info| {
67 device_info
68 .matches_usb_pid(usb_pid)
69 .then_some(device_info.model)
70 })
71 .unwrap_or(Model::Unknown {
72 usb_pid: Some(usb_pid),
73 })
74 }
75}
76
77#[derive(Clone, PartialEq, Debug)]
78pub struct BleSpec {
79 pub service_uuid: Uuid,
80 pub notify_uuid: Uuid,
81 pub write_uuid: Uuid,
82 pub write_cmd_uuid: Uuid,
83}
84
85struct InternalDeviceInfo {
86 model: Model,
87 legacy_usb_product_id: u16,
88 product_id_mm: u16,
89 ble_specs: Vec<BleSpec>,
90}
91
92impl InternalDeviceInfo {
93 fn matches_usb_pid(&self, usb_pid: u16) -> bool {
94 usb_pid == self.legacy_usb_product_id || usb_pid >> 8 == self.product_id_mm
100 }
101}
102
103lazy_static::lazy_static! {
106 static ref INTERNAL_DEVICE_INFOS: Vec<InternalDeviceInfo> = {
107 vec![
108 InternalDeviceInfo {
109 model: Model::NanoS,
110 legacy_usb_product_id: 0x0001,
111 product_id_mm: 0x10,
112 ble_specs: vec![],
113 },
114 InternalDeviceInfo {
115 model: Model::NanoX,
116 legacy_usb_product_id: 0x0004,
117 product_id_mm: 0x40,
118 ble_specs: vec![
119 BleSpec {
120 service_uuid: uuid!("13d63400-2c97-0004-0000-4c6564676572"),
121 notify_uuid: uuid!("13d63400-2c97-0004-0001-4c6564676572"),
122 write_uuid: uuid!("13d63400-2c97-0004-0002-4c6564676572"),
123 write_cmd_uuid: uuid!("13d63400-2c97-0004-0003-4c6564676572"),
124 },
125 ],
126 },
127 InternalDeviceInfo {
128 model: Model::NanoSPlus,
129 legacy_usb_product_id: 0x0005,
130 product_id_mm: 0x50,
131 ble_specs: vec![],
132 },
133 InternalDeviceInfo {
134 model: Model::Stax,
135 legacy_usb_product_id: 0x0006,
136 product_id_mm: 0x60,
137 ble_specs: vec![
138 BleSpec {
139 service_uuid: uuid!("13d63400-2c97-6004-0000-4c6564676572"),
140 notify_uuid: uuid!("13d63400-2c97-6004-0001-4c6564676572"),
141 write_uuid: uuid!("13d63400-2c97-6004-0002-4c6564676572"),
142 write_cmd_uuid: uuid!("13d63400-2c97-6004-0003-4c6564676572"),
143 },
144 ],
145 },
146 InternalDeviceInfo {
147 model: Model::Flex,
148 legacy_usb_product_id: 0x0007,
149 product_id_mm: 0x70,
150 ble_specs: vec![
151 BleSpec {
152 service_uuid: uuid!("13d63400-2c97-3004-0000-4c6564676572"),
153 notify_uuid: uuid!("13d63400-2c97-3004-0001-4c6564676572"),
154 write_uuid: uuid!("13d63400-2c97-3004-0002-4c6564676572"),
155 write_cmd_uuid: uuid!("13d63400-2c97-3004-0003-4c6564676572"),
156 },
157 ],
158 },
159 InternalDeviceInfo {
160 model: Model::NanoGen5,
161 legacy_usb_product_id: 0x0008,
162 product_id_mm: 0x80,
163 ble_specs: vec![
164 BleSpec {
165 service_uuid: uuid!("13d63400-2c97-8004-0000-4c6564676572"),
166 notify_uuid: uuid!("13d63400-2c97-8004-0001-4c6564676572"),
167 write_uuid: uuid!("13d63400-2c97-8004-0002-4c6564676572"),
168 write_cmd_uuid: uuid!("13d63400-2c97-8004-0003-4c6564676572"),
169 },
170 ],
171 },
172 ]
173 };
174
175 static ref BLE_SPECS_BY_SERVICE_UUID: BTreeMap<Uuid, &'static BleSpec> = {
176 INTERNAL_DEVICE_INFOS
177 .iter()
178 .flat_map(|dev_info| dev_info.ble_specs.iter())
179 .map(|ble_spec| (ble_spec.service_uuid, ble_spec))
180 .collect()
181 };
182
183 static ref INTERNAL_DEVICE_INFOS_BY_BLE_SERVICE_UUID: BTreeMap<Uuid, &'static InternalDeviceInfo> = {
184 INTERNAL_DEVICE_INFOS
185 .iter()
186 .flat_map(|dev_info| {
187 dev_info.ble_specs.iter().map(move |ble_spec| (ble_spec.service_uuid, dev_info))
188 })
189 .collect()
190 };
191}
192
193pub fn model_by_ble_service_uuid(service_uuid: &Uuid) -> Option<Model> {
194 INTERNAL_DEVICE_INFOS_BY_BLE_SERVICE_UUID
195 .get(service_uuid)
196 .map(|dev_info| dev_info.model)
197}
198
199pub fn ble_spec_by_service_uuid(service_uuid: &Uuid) -> Option<&'static BleSpec> {
200 BLE_SPECS_BY_SERVICE_UUID.get(service_uuid).copied()
201}
202
203#[derive(Clone, PartialEq, Debug)]
205pub enum ConnInfo {
206 #[cfg(feature = "transport_usb")]
207 Usb(transport::UsbInfo),
208 #[cfg(feature = "transport_tcp")]
209 Tcp(transport::TcpInfo),
210 #[cfg(feature = "transport_ble")]
211 Ble(transport::BleInfo),
212}
213
214#[derive(Copy, Clone, PartialEq, Debug)]
216pub enum ConnType {
217 Usb,
218 Tcp,
219 Ble,
220}
221
222impl From<ConnType> for Filters {
223 fn from(value: ConnType) -> Self {
225 match value {
226 ConnType::Usb => Filters::Hid,
227 ConnType::Tcp => Filters::Tcp,
228 ConnType::Ble => Filters::Ble,
229 }
230 }
231}
232
233impl std::fmt::Display for ConnInfo {
234 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
235 match self {
236 #[cfg(feature = "transport_usb")]
237 Self::Usb(i) => write!(f, "HID {}", i),
238 #[cfg(feature = "transport_tcp")]
239 Self::Tcp(i) => write!(f, "TCP {}", i),
240 #[cfg(feature = "transport_ble")]
241 Self::Ble(i) => write!(f, "BLE {}", i),
242 }
243 }
244}
245
246#[cfg(feature = "transport_usb")]
247impl From<transport::UsbInfo> for ConnInfo {
248 fn from(value: transport::UsbInfo) -> Self {
249 Self::Usb(value)
250 }
251}
252
253#[cfg(feature = "transport_tcp")]
254impl From<transport::TcpInfo> for ConnInfo {
255 fn from(value: transport::TcpInfo) -> Self {
256 Self::Tcp(value)
257 }
258}
259
260#[cfg(feature = "transport_ble")]
261impl From<transport::BleInfo> for ConnInfo {
262 fn from(value: transport::BleInfo) -> Self {
263 Self::Ble(value)
264 }
265}
266
267#[derive(Debug, Clone, PartialEq)]
269pub struct AppInfo {
270 pub name: String,
271 pub version: String,
272 pub flags: ledger_proto::apdus::AppFlags,
273}
274
275#[derive(Debug, Clone, PartialEq)]
277pub struct DeviceInfo {
278 pub target_id: [u8; 4],
279 pub se_version: String,
280 pub mcu_version: String,
281 pub flags: Vec<u8>,
282}