blackmagic_sys/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6
7use std::error::Error;
8use std::ffi::{CStr, CString};
9use std::fmt;
10use std::ptr;
11
12// use {bmda_cli_mode_BMP_MODE_DEBUG, bmda_cli_options, bmp_scan_mode_BMP_SCAN_SWD, serial_open};
13
14// Define your custom error type (Err)
15#[derive(Debug)]
16pub struct BlackMagicProbeError {
17    message: String,
18}
19
20pub const VENDOR_ID: u16 = VENDOR_ID_BMP as u16;
21pub const PRODUCT_IDS: [u16; 2] = [PRODUCT_ID_BMP_BL as u16, PRODUCT_ID_BMP as u16];
22
23impl fmt::Display for BlackMagicProbeError {
24    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25        write!(f, "{}", self.message)
26    }
27}
28
29impl Error for BlackMagicProbeError {}
30/// A result type with the error hardwired to [`BmpError`].
31pub type Result<T> = std::result::Result<T, BlackMagicProbeError>;
32
33#[derive(Debug)]
34pub struct Probe {
35    // The serial number of the probe
36    serial: String,
37}
38
39const MAX_SPEED: u32 = 4_000_000;
40
41impl Probe {
42    // Opens the device handle for the specified serial number of the Black Magic Probe
43    pub fn open_by_serial(serial: &str) -> Result<Self> {
44        // Set the probe type to BMDA, this normally gets set during platform_init which we do not want to call
45        unsafe { bmda_probe_info.type_ = probe_type_PROBE_TYPE_BMP }
46        let input = CString::new(serial).expect("CString conversion failed");
47        // todo: replace with global opts struct used by bmp
48        let options = bmda_cli_options {
49            opt_target_dev: 1,
50            opt_flash_size: 0xffffffff,
51            opt_flash_start: 0xffffffff,
52            opt_max_swj_frequency: MAX_SPEED,
53            opt_scanmode: bmp_scan_mode_BMP_SCAN_SWD,
54            opt_mode: bmda_cli_mode_BMP_MODE_DEBUG,
55
56            opt_tpwr: false,
57            opt_list_only: false,
58            opt_connect_under_reset: false,
59            external_resistor_swd: false,
60            fast_poll: false,
61            opt_no_hl: false,
62            opt_flash_file: ptr::null_mut(),
63            opt_device: ptr::null_mut(),
64            opt_serial: ptr::null_mut(),
65            opt_targetid: 0,
66            opt_ident_string: ptr::null_mut(),
67            opt_position: 0,
68            opt_cable: ptr::null_mut(),
69            opt_monitor: ptr::null_mut(),
70        };
71        let result = unsafe { serial_open(&options, input.as_ptr()) };
72        if result == false {
73            return Err(BlackMagicProbeError {
74                message: "Could not open serial device".to_string(),
75            });
76        }
77        let bmp = Probe {
78            serial: serial.to_string(),
79        };
80
81        let result = unsafe { remote_init(true) };
82        if result == false {
83            return Err(BlackMagicProbeError {
84                message: "Could not initialize device".to_string(),
85            });
86        }
87
88        let ret: Result<Probe> = Ok(bmp);
89        return ret;
90    }
91
92    pub fn close() {
93        unsafe { serial_close() }
94    }
95
96    // Asserts the nrst line when input is true
97    // Returns true or exits in case the call failed
98    pub fn nrst_set(&self, assert: bool) -> Result<bool> {
99        unsafe { remote_nrst_set_val(assert) }
100        Ok(true)
101    }
102
103    // Returns wether nrst is asserted (true) or not
104    pub fn nrst_get(&self) -> bool {
105        unsafe { remote_nrst_get_val() }
106    }
107
108    // Get the maximum speed of the probe
109    pub fn max_speed_get(&self) -> u32 {
110        unsafe { platform_max_frequency_get() }
111    }
112
113    // Sets the maximum speed of the probe
114    pub fn max_speed_set(&self, speed: u32) {
115        unsafe { platform_max_frequency_set(speed) }
116    }
117
118    pub fn set_power(&self, enable: bool) -> Result<bool> {
119        if unsafe { platform_target_set_power(enable) } {
120            return Ok(enable);
121        }
122        Err(BlackMagicProbeError {
123            message: "Could not set target power".to_string(),
124        })
125    }
126
127    // Gets the target voltage
128    pub fn target_voltage(&self) -> Result<f32> {
129        let cstr = unsafe { platform_target_voltage() };
130        let c_str = unsafe { CStr::from_ptr(cstr) };
131
132        // Attempt to convert the CStr to a &str (Rust string slice)
133        match c_str.to_str() {
134            Ok(rust_str) => {
135                // The conversion succeeded
136                // Remove non-numeric characters (e.g., "V")
137                let numeric_str: String = rust_str
138                    .chars()
139                    .filter(|c| c.is_digit(10) || *c == '.')
140                    .collect();
141
142                // Parse the resulting numeric string to a float
143                if let Ok(float_value) = numeric_str.parse::<f32>() {
144                    return Ok(float_value);
145                } else {
146                    return Err(BlackMagicProbeError {
147                        message: "Failed to parse the string as a float.".to_string(),
148                    });
149                }
150            }
151            Err(_) => {
152                return Err(BlackMagicProbeError {
153                    message: "Invalid UTF-8 data in C string".to_string(),
154                });
155            }
156        }
157    }
158}
159
160#[cfg(test)]
161mod tests {
162    // Import necessary modules and functions
163    #[test]
164    fn test_remote_hex_string_to_num() {
165        use super::remote_hex_string_to_num;
166        use std::ffi::CString; // Adjust the import path as needed
167        let input = CString::new("").expect("CString conversion failed");
168        let result = unsafe { remote_hex_string_to_num(0, input.as_ptr()) };
169        assert_eq!(result, 0);
170        let input = CString::new("1").expect("CString conversion failed");
171        let result = unsafe { remote_hex_string_to_num(1, input.as_ptr()) };
172        assert_eq!(result, 1);
173        let input = CString::new("123456789ABCDEF").expect("CString conversion failed");
174        let result = unsafe { remote_hex_string_to_num(15, input.as_ptr()) };
175        assert_eq!(result, 0x123456789ABCDEF);
176    }
177
178    #[test]
179    #[ignore]
180    // These tests are to be run with a bmp connected with the serial provided
181    // In addition, a target needs to be connected with the specified supply voltage
182    // A bmp connected to an nrf DK or thingy would be a proper set-up for
183    // having the tests pass
184    fn test_bmp_hil() {
185        use std::thread::sleep;
186        use std::time::Duration;
187        let duration = Duration::from_millis(10);
188        let serial = "98B72495";
189        let target_voltage: f32 = 1.8;
190
191        // This test only works when a bmp is connect with the serial number specified in the variable below
192        let bmp = super::Probe::open_by_serial(serial).unwrap();
193
194        // Target voltage should be ON after initializing
195        sleep(duration);
196        assert_eq!(bmp.target_voltage().unwrap(), target_voltage);
197
198        // We should be able to set the speed to a lower value of the max
199        let speed1 = bmp.max_speed_get();
200        assert!(speed1 > 0);
201        bmp.max_speed_set(speed1 / 2);
202        let speed2 = bmp.max_speed_get();
203        assert!(speed2 < speed1);
204
205        // We should be able to assert and de-assert the reset-line
206        assert!(bmp.nrst_set(true).unwrap());
207        assert!(bmp.nrst_get());
208        assert!(bmp.nrst_set(false).unwrap());
209        assert!(!bmp.nrst_get());
210
211        // We should be able to turn off power
212        // let duration = Duration::from_secs(1);
213        // sleep(duration);
214        // assert!(bmp.set_power(false).unwrap());
215
216        // // Target voltage should be OFF after setting power
217        // assert_eq!(bmp.target_voltage(), "0.0V");
218    }
219}
220// bool platform_buffer_write(const void *data, size_t size);
221// int platform_buffer_read(void *data, size_t size);
222
223// bool remote_swd_init(void);
224// bool remote_jtag_init(void);
225// bool remote_target_get_power(void);
226// const char *remote_target_voltage(void);
227// bool remote_target_set_power(bool power);
228// void remote_nrst_set_val(bool assert);
229// bool remote_nrst_get_val(void);
230// void remote_max_frequency_set(uint32_t freq);
231// uint32_t remote_max_frequency_get(void);
232// void remote_target_clk_output_enable(bool enable);
233
234// void remote_adiv5_dp_init(adiv5_debug_port_s *dp);
235// void remote_add_jtag_dev(uint32_t dev_index, const jtag_dev_s *jtag_dev);
236
237// uint64_t remote_decode_response(const char *response, size_t digits);