1pub mod err;
77
78#[cfg(unix)]
79#[allow(non_camel_case_types)]
80pub type wchar = u32;
81#[cfg(windows)]
82#[allow(non_camel_case_types)]
83pub type wchar = u16;
84
85#[repr(C)]
86pub struct DisplayCallbacks {
87 pub init_progress_bar: extern "C" fn(),
88 pub log_message: extern "C" fn(msg_type: std::os::raw::c_int, msg: *const std::os::raw::c_int),
89 pub load_bar: extern "C" fn(current: std::os::raw::c_int, total: std::os::raw::c_int),
90}
91
92extern "C" fn init_progress_bar() {}
93
94extern "C" fn log_message(_msg_type: std::os::raw::c_int, _msg: *const std::os::raw::c_int) {}
95
96extern "C" fn load_bar(_current: std::os::raw::c_int, _total: std::os::raw::c_int) {}
97
98#[repr(C)]
99#[derive(Debug, Copy, Clone)]
100pub enum Verbosity {
101 Level0 = 0,
102 Level1 = 1,
103 Level2 = 2,
104 Level3 = 3,
105}
106
107#[repr(C)]
108#[derive(Debug, Copy, Clone)]
109pub enum DebugPort {
110 Jtag = 0,
111 Swd = 1,
112}
113
114#[repr(C)]
115#[derive(Debug, Copy, Clone)]
116pub enum DebugConnectMode {
117 Normal = 0,
118 HotPlug = 1,
119 UnderReset = 2,
120 PowerDown = 3,
121 PreReset = 4,
122}
123
124#[repr(C)]
125#[derive(Debug, Copy, Clone)]
126pub enum DebugResetMode {
127 SoftwareReset = 0,
128 HardwareReset = 1,
129 CoreReset = 2,
130}
131
132#[repr(C)]
133#[derive(Debug, Copy, Clone)]
134pub struct Frequencies {
135 pub jtag_freq: [std::os::raw::c_uint; 12usize],
136 pub jtag_freq_count: std::os::raw::c_uint,
137 pub swd_freq: [std::os::raw::c_uint; 12usize],
138 pub swd_freq_count: std::os::raw::c_uint,
139}
140
141impl Frequencies {
142 pub fn jtag_frequencies(&self) -> Vec<u32> {
143 let size = std::convert::TryInto::try_into(self.jtag_freq_count).unwrap_or_default();
144 self.jtag_freq.to_vec()[0..size].to_vec()
145 }
146
147 pub fn swd_frequencies(&self) -> Vec<u32> {
148 let size = std::convert::TryInto::try_into(self.swd_freq_count).unwrap_or_default();
149 self.swd_freq.to_vec()[0..size].to_vec()
150 }
151}
152
153impl std::fmt::Display for Frequencies {
154 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
155 write!(
156 f,
157 "\
158JTAG Frequencies Available: {:?},
159SWD Frequencies Available: {:?}",
160 self.jtag_frequencies(),
161 self.swd_frequencies(),
162 )
163 }
164}
165
166#[repr(C)]
167#[derive(Debug, Copy, Clone)]
168pub struct DeviceGeneralInfo {
169 pub device_id: ::std::os::raw::c_ushort,
170 pub flash_size: ::std::os::raw::c_int,
171 pub bootloader_version: ::std::os::raw::c_int,
172 pub category: [::std::os::raw::c_char; 4usize],
173 pub cpu: [::std::os::raw::c_char; 20usize],
174 pub name: [::std::os::raw::c_char; 100usize],
175 pub series: [::std::os::raw::c_char; 100usize],
176 pub description: [::std::os::raw::c_char; 150usize],
177 pub revision_id: [::std::os::raw::c_char; 8usize],
178 pub board: [::std::os::raw::c_char; 100usize],
179}
180
181#[repr(C)]
182#[derive(Debug, Copy, Clone)]
183pub struct DebugConnectParameters {
184 pub debug_port: DebugPort,
185 pub index: std::os::raw::c_int,
186 pub serial_number: [std::os::raw::c_char; 33usize],
187 pub firmware_version: [std::os::raw::c_char; 20usize],
188 pub target_voltage: [std::os::raw::c_char; 5usize],
189 pub access_port_count: std::os::raw::c_int,
190 pub access_port: std::os::raw::c_int,
191 pub connection_mode: DebugConnectMode,
192 pub reset_mode: DebugResetMode,
193 pub old_firmware: std::os::raw::c_int,
194 pub frequencies: Frequencies,
195 pub frequency: std::os::raw::c_int,
196 pub bridge: std::os::raw::c_int,
197 pub shared: std::os::raw::c_int,
198 pub board: [std::os::raw::c_char; 100usize],
199 pub debug_sleep: std::os::raw::c_int,
200 pub speed: std::os::raw::c_int,
201}
202
203type SetLoaderPath = unsafe extern "C" fn(path: *const std::os::raw::c_char);
204type SetDisplayCallbacks = unsafe extern "C" fn(c: DisplayCallbacks);
205type SetVerbosityLevel = unsafe extern "C" fn(level: Verbosity);
206type GetStLinkList = unsafe extern "C" fn(
207 debug_connect_parameters: *mut *mut DebugConnectParameters,
208 shared: std::os::raw::c_int,
209) -> std::os::raw::c_int;
210type ConnectStLink =
211 unsafe extern "C" fn(debug_connect_parameters: DebugConnectParameters) -> std::os::raw::c_int;
212type Disconnect = unsafe extern "C" fn();
213type Reset = unsafe extern "C" fn(reset_mode: DebugResetMode) -> std::os::raw::c_int;
214type MassErase = unsafe extern "C" fn() -> std::os::raw::c_int;
215type DownloadFile = unsafe extern "C" fn(
216 file_path: *const wchar,
217 address: std::os::raw::c_uint,
218 skip_erase: std::os::raw::c_uint,
219 verify: std::os::raw::c_uint,
220 path: *const wchar,
221) -> std::os::raw::c_int;
222type GetDeviceGeneralInfo = unsafe extern "C" fn() -> *mut DeviceGeneralInfo;
223type ReadMemory = unsafe extern "C" fn(
224 address: ::std::os::raw::c_uint,
225 data: *mut *mut ::std::os::raw::c_uchar,
226 size: ::std::os::raw::c_uint,
227) -> ::std::os::raw::c_int;
228type WriteMemory = unsafe extern "C" fn(
229 address: ::std::os::raw::c_uint,
230 data: *mut ::std::os::raw::c_uchar,
231 size: ::std::os::raw::c_uint,
232) -> ::std::os::raw::c_int;
233type ReadCoreRegister = unsafe extern "C" fn(
234 register: std::os::raw::c_uint,
235 data: *mut std::os::raw::c_uint,
236) -> ::std::os::raw::c_int;
237type WriteCoreRegister = unsafe extern "C" fn(
238 register: std::os::raw::c_uint,
239 data: std::os::raw::c_uint,
240) -> ::std::os::raw::c_int;
241
242#[cfg(unix)]
243pub struct VTable {
244 set_loaders_path: libloading::os::unix::Symbol<SetLoaderPath>,
245 set_display_callbacks: libloading::os::unix::Symbol<SetDisplayCallbacks>,
246 set_verbosity_level: libloading::os::unix::Symbol<SetVerbosityLevel>,
247 get_stlink_list: libloading::os::unix::Symbol<GetStLinkList>,
248 connect_stlink: libloading::os::unix::Symbol<ConnectStLink>,
249 disconnect: libloading::os::unix::Symbol<Disconnect>,
250 reset: libloading::os::unix::Symbol<Reset>,
251 mass_erase: libloading::os::unix::Symbol<MassErase>,
252 download_file: libloading::os::unix::Symbol<DownloadFile>,
253 get_device_general_info: libloading::os::unix::Symbol<GetDeviceGeneralInfo>,
254 read_memory: libloading::os::unix::Symbol<ReadMemory>,
255 write_memory: libloading::os::unix::Symbol<WriteMemory>,
256 read_core_register: libloading::os::unix::Symbol<ReadCoreRegister>,
257 write_core_register: libloading::os::unix::Symbol<WriteCoreRegister>,
258}
259
260#[cfg(windows)]
261pub struct VTable {
262 set_loaders_path: libloading::os::windows::Symbol<SetLoaderPath>,
263 set_display_callbacks: libloading::os::windows::Symbol<SetDisplayCallbacks>,
264 set_verbosity_level: libloading::os::windows::Symbol<SetVerbosityLevel>,
265 get_stlink_list: libloading::os::windows::Symbol<GetStLinkList>,
266 connect_stlink: libloading::os::windows::Symbol<ConnectStLink>,
267 disconnect: libloading::os::windows::Symbol<Disconnect>,
268 reset: libloading::os::windows::Symbol<Reset>,
269 mass_erase: libloading::os::windows::Symbol<MassErase>,
270 download_file: libloading::os::windows::Symbol<DownloadFile>,
271 get_device_general_info: libloading::os::windows::Symbol<GetDeviceGeneralInfo>,
272 read_memory: libloading::os::windows::Symbol<ReadMemory>,
273 write_memory: libloading::os::windows::Symbol<WriteMemory>,
274 read_core_register: libloading::os::windows::Symbol<ReadCoreRegister>,
275 write_core_register: libloading::os::windows::Symbol<WriteCoreRegister>,
276}
277
278impl VTable {
279 fn new(library: &libloading::Library) -> Result<Self, err::Error> {
280 let set_loaders_path: libloading::Symbol<SetLoaderPath> =
281 unsafe { library.get(b"setLoadersPath\0")? };
282 let set_loaders_path = unsafe { set_loaders_path.into_raw() };
283 let set_display_callbacks: libloading::Symbol<SetDisplayCallbacks> =
284 unsafe { library.get(b"setDisplayCallbacks\0")? };
285 let set_display_callbacks = unsafe { set_display_callbacks.into_raw() };
286 let set_verbosity_level: libloading::Symbol<SetVerbosityLevel> =
287 unsafe { library.get(b"setVerbosityLevel\0")? };
288 let set_verbosity_level = unsafe { set_verbosity_level.into_raw() };
289 let get_stlink_list: libloading::Symbol<GetStLinkList> =
290 unsafe { library.get(b"getStLinkList\0")? };
291 let get_stlink_list = unsafe { get_stlink_list.into_raw() };
292 let connect_stlink: libloading::Symbol<ConnectStLink> =
293 unsafe { library.get(b"connectStLink\0")? };
294 let connect_stlink = unsafe { connect_stlink.into_raw() };
295 let disconnect: libloading::Symbol<Disconnect> = unsafe { library.get(b"disconnect\0")? };
296 let disconnect = unsafe { disconnect.into_raw() };
297 let reset: libloading::Symbol<Reset> = unsafe { library.get(b"reset\0")? };
298 let reset = unsafe { reset.into_raw() };
299 let mass_erase: libloading::Symbol<MassErase> = unsafe { library.get(b"massErase\0")? };
300 let mass_erase = unsafe { mass_erase.into_raw() };
301 let download_file: libloading::Symbol<DownloadFile> =
302 unsafe { library.get(b"downloadFile\0")? };
303 let download_file = unsafe { download_file.into_raw() };
304 let get_device_general_info: libloading::Symbol<GetDeviceGeneralInfo> =
305 unsafe { library.get(b"getDeviceGeneralInf\0")? };
306 let get_device_general_info = unsafe { get_device_general_info.into_raw() };
307 let read_memory: libloading::Symbol<ReadMemory> = unsafe { library.get(b"readMemory\0")? };
308 let read_memory = unsafe { read_memory.into_raw() };
309 let write_memory: libloading::Symbol<WriteMemory> =
310 unsafe { library.get(b"writeMemory\0")? };
311 let write_memory = unsafe { write_memory.into_raw() };
312 let read_core_register: libloading::Symbol<ReadCoreRegister> =
313 unsafe { library.get(b"readCortexReg\0")? };
314 let read_core_register = unsafe { read_core_register.into_raw() };
315 let write_core_register: libloading::Symbol<WriteCoreRegister> =
316 unsafe { library.get(b"writeCortexRegistres\0")? };
317 let write_core_register = unsafe { write_core_register.into_raw() };
318
319 Ok(VTable {
320 set_loaders_path,
321 set_display_callbacks,
322 set_verbosity_level,
323 get_stlink_list,
324 connect_stlink,
325 disconnect,
326 reset,
327 mass_erase,
328 download_file,
329 get_device_general_info,
330 read_memory,
331 write_memory,
332 read_core_register,
333 write_core_register,
334 })
335 }
336}
337
338#[derive(Debug, Clone)]
339pub struct STLink {
340 debug_connect_parameters: DebugConnectParameters,
341}
342
343impl STLink {
344 pub fn frequencies(&self) -> Frequencies {
345 self.debug_connect_parameters.frequencies
346 }
347
348 pub fn debug_port(&self) -> DebugPort {
349 self.debug_connect_parameters.debug_port
350 }
351
352 pub fn index(&self) -> i32 {
353 self.debug_connect_parameters.index
354 }
355
356 pub fn access_port_count(&self) -> i32 {
357 self.debug_connect_parameters.access_port_count
358 }
359
360 pub fn access_port(&self) -> i32 {
361 self.debug_connect_parameters.access_port
362 }
363
364 pub fn connection_mode(&self) -> DebugConnectMode {
365 self.debug_connect_parameters.connection_mode
366 }
367
368 pub fn reset_mode(&self) -> DebugResetMode {
369 self.debug_connect_parameters.reset_mode
370 }
371
372 pub fn old_firmware(&self) -> bool {
373 self.debug_connect_parameters.old_firmware == 1
374 }
375
376 pub fn frequency(&self) -> i32 {
377 self.debug_connect_parameters.frequency
378 }
379
380 pub fn bridge(&self) -> bool {
381 self.debug_connect_parameters.bridge == 1
382 }
383
384 pub fn shared(&self) -> bool {
385 self.debug_connect_parameters.shared == 1
386 }
387
388 pub fn debug_sleep(&self) -> bool {
389 self.debug_connect_parameters.debug_sleep == 1
390 }
391
392 pub fn speed(&self) -> i32 {
393 self.debug_connect_parameters.speed
394 }
395
396 pub fn target_voltage(&self) -> Result<f32, err::Error> {
397 Ok(String::from_utf8(
398 self.debug_connect_parameters
399 .target_voltage
400 .iter()
401 .map(|&c| c as u8)
402 .collect(),
403 )?.trim_matches(char::from(0)).parse()?)
404 }
405
406 pub fn serial_number(&self) -> Result<String, err::Error> {
407 Ok(String::from_utf8(
408 self.debug_connect_parameters
409 .serial_number
410 .iter()
411 .map(|&c| c as u8)
412 .collect(),
413 )?.trim_matches(char::from(0)).to_owned())
414 }
415
416 pub fn firmware_version(&self) -> Result<String, err::Error> {
417 Ok(String::from_utf8(
418 self.debug_connect_parameters
419 .firmware_version
420 .iter()
421 .map(|&c| c as u8)
422 .collect(),
423 )?.trim_matches(char::from(0)).to_owned())
424 }
425
426 pub fn board(&self) -> Result<String, err::Error> {
427 Ok(String::from_utf8(
428 self.debug_connect_parameters
429 .board
430 .iter()
431 .map(|&c| c as u8)
432 .collect(),
433 )?.trim_matches(char::from(0)).to_owned())
434 }
435
436 pub fn set_access_port(&mut self, access_port: i32) {
437 self.debug_connect_parameters.access_port = access_port;
438 }
439
440 pub fn set_frequency(&mut self, frequency: i32) {
441 self.debug_connect_parameters.frequency = frequency;
442 }
443
444 pub fn set_reset_mode(&mut self, reset_mode: DebugResetMode) {
445 self.debug_connect_parameters.reset_mode = reset_mode;
446 }
447
448 pub fn set_connection_mode(&mut self, connection_mode: DebugConnectMode) {
449 self.debug_connect_parameters.connection_mode = connection_mode
450 }
451}
452
453impl std::fmt::Display for STLink {
454 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
455 write!(
456 f,
457 "\
458Board: {},
459Serial Number: {},
460Firmware Version: {},
461Index: {},
462Connection Mode: {:?},
463Reset Mode: {:?},
464Access Port Count: {},
465Access Port: {},
466Debug Port: {:?},
467Old Firmware: {},
468{},
469Frequency: {},
470Bridge: {},
471Shared: {},
472Debug Sleep: {},
473Speed: {},
474Target Voltage: {}",
475 self.board().unwrap_or("undefined".into()),
476 self.serial_number().unwrap_or("undefined".into()),
477 self.firmware_version().unwrap_or("undefined".into()),
478 self.index(),
479 self.connection_mode(),
480 self.reset_mode(),
481 self.access_port_count(),
482 self.access_port(),
483 self.debug_port(),
484 self.old_firmware(),
485 self.frequencies(),
486 self.frequency(),
487 self.bridge(),
488 self.shared(),
489 self.debug_sleep(),
490 self.speed(),
491 self.target_voltage().unwrap_or(0.0)
492 )
493 }
494}
495
496#[derive(Debug, Clone)]
497pub struct DeviceInfo {
498 device_general_info: DeviceGeneralInfo,
499}
500
501impl DeviceInfo {
502 pub fn category(&self) -> Result<String, err::Error> {
503 Ok(String::from_utf8(
504 self.device_general_info
505 .category
506 .iter()
507 .map(|&c| c as u8)
508 .collect(),
509 )?.trim_matches(char::from(0)).to_owned())
510 }
511
512 pub fn cpu(&self) -> Result<String, err::Error> {
513 Ok(String::from_utf8(
514 self.device_general_info
515 .cpu
516 .iter()
517 .map(|&c| c as u8)
518 .collect(),
519 )?.trim_matches(char::from(0)).to_owned())
520 }
521
522 pub fn name(&self) -> Result<String, err::Error> {
523 Ok(String::from_utf8(
524 self.device_general_info
525 .name
526 .iter()
527 .map(|&c| c as u8)
528 .collect(),
529 )?.trim_matches(char::from(0)).to_owned())
530 }
531
532 pub fn series(&self) -> Result<String, err::Error> {
533 Ok(String::from_utf8(
534 self.device_general_info
535 .series
536 .iter()
537 .map(|&c| c as u8)
538 .collect(),
539 )?.trim_matches(char::from(0)).to_owned())
540 }
541
542 pub fn description(&self) -> Result<String, err::Error> {
543 Ok(String::from_utf8(
544 self.device_general_info
545 .description
546 .iter()
547 .map(|&c| c as u8)
548 .collect(),
549 )?.trim_matches(char::from(0)).to_owned())
550 }
551
552 pub fn revision_id(&self) -> Result<String, err::Error> {
553 Ok(String::from_utf8(
554 self.device_general_info
555 .revision_id
556 .iter()
557 .map(|&c| c as u8)
558 .collect(),
559 )?.trim_matches(char::from(0)).to_owned())
560 }
561
562 pub fn board(&self) -> Result<String, err::Error> {
563 Ok(String::from_utf8(
564 self.device_general_info
565 .board
566 .iter()
567 .map(|&c| c as u8)
568 .collect(),
569 )?.trim_matches(char::from(0)).to_owned())
570 }
571
572 pub fn device_id(&self) -> i32 {
573 self.device_general_info.device_id.into()
574 }
575
576 pub fn flash_size(&self) -> i32 {
577 self.device_general_info.flash_size
578 }
579
580 pub fn bootloader_version(&self) -> i32 {
581 self.device_general_info.bootloader_version
582 }
583}
584
585impl std::fmt::Display for DeviceInfo {
586 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
587 write!(
588 f,
589 "\
590Category: {},
591Cpu: {},
592Name: {},
593Series: {},
594Description: {},
595Revision Id: {},
596Board: {},
597Device Id: 0x{:X},
598Flash Size: 0x{:X},
599Bootloader Version: 0x{:X}",
600 self.category().unwrap_or("undefined".into()),
601 self.cpu().unwrap_or("undefined".into()),
602 self.name().unwrap_or("undefined".into()),
603 self.series().unwrap_or("undefined".into()),
604 self.description().unwrap_or("undefined".into()),
605 self.revision_id().unwrap_or("undefined".into()),
606 self.board().unwrap_or("undefined".into()),
607 self.device_id(),
608 self.flash_size(),
609 self.bootloader_version()
610 )
611 }
612}
613
614pub enum Register {
615 R0,
616 R1,
617 R2,
618 R3,
619 R4,
620 R5,
621 R6,
622 R7,
623 R8,
624 R9,
625 R10,
626 R11,
627 R12,
628 SP,
629 LR,
630 PC,
631}
632
633impl From<Register> for u32 {
634 fn from(register: Register) -> Self {
635 match register {
636 Register::R0 => 0,
637 Register::R1 => 1,
638 Register::R2 => 2,
639 Register::R3 => 3,
640 Register::R4 => 4,
641 Register::R5 => 5,
642 Register::R6 => 6,
643 Register::R7 => 7,
644 Register::R8 => 8,
645 Register::R9 => 9,
646 Register::R10 => 10,
647 Register::R11 => 11,
648 Register::R12 => 12,
649 Register::SP => 13,
650 Register::LR => 14,
651 Register::PC => 15,
652 }
653 }
654}
655
656pub struct STM32CubeProg {
657 #[allow(dead_code)]
658 library: libloading::Library,
659 vtable: VTable,
660}
661
662impl STM32CubeProg {
663 #[cfg(unix)]
664 fn library_path(path: &std::path::Path) -> std::path::PathBuf {
665 path.join("lib/libCubeProgrammer_API.so")
666 }
667
668 #[cfg(windows)]
669 fn library_path(path: &std::path::Path) -> std::path::PathBuf {
670 path.join("api\\lib\\CubeProgrammer_API.dll")
671 }
672
673 #[cfg(unix)]
674 fn flashloader_path(path: &std::path::Path) -> std::path::PathBuf {
675 path.join("bin")
676 }
677
678 #[cfg(windows)]
679 fn flashloader_path(path: &std::path::Path) -> std::path::PathBuf {
680 path.join("bin")
681 }
682
683 #[cfg(unix)]
684 fn load_library(path: &std::path::Path) -> Result<libloading::Library, err::Error> {
685 let library: libloading::Library =
686 unsafe { libloading::os::unix::Library::new(path)?.into() };
687 Ok(library)
688 }
689
690 #[cfg(windows)]
691 fn load_library(path: &std::path::Path) -> Result<libloading::Library, err::Error> {
692 let library: libloading::Library = unsafe {
693 libloading::os::windows::Library::load_with_flags(
694 path,
695 libloading::os::windows::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR
696 | libloading::os::windows::LOAD_LIBRARY_SEARCH_SYSTEM32
697 | libloading::os::windows::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS,
698 )?
699 .into()
700 };
701 Ok(library)
702 }
703
704 pub fn new<P: AsRef<std::path::Path>>(path: P) -> Result<Self, err::Error> {
705 let library_path = Self::library_path(path.as_ref());
706 let library = Self::load_library(library_path.as_ref())?;
707 let vtable = VTable::new(&library)?;
708
709 unsafe {
710 (vtable.set_loaders_path)(
711 Self::flashloader_path(path.as_ref())
712 .as_os_str()
713 .as_encoded_bytes()
714 .as_ptr() as *const i8,
715 )
716 };
717
718 let cb: DisplayCallbacks = DisplayCallbacks {
719 init_progress_bar: init_progress_bar,
720 log_message: log_message,
721 load_bar: load_bar,
722 };
723
724 unsafe { (vtable.set_display_callbacks)(cb) };
725
726 unsafe { (vtable.set_verbosity_level)(Verbosity::Level0) };
727
728 Ok(STM32CubeProg { library, vtable })
729 }
730
731 pub fn discover(&self) -> Result<Vec<STLink>, err::Error> {
732 let mut debug_connect_parameters = std::ptr::null_mut();
733 let stlink_count =
734 unsafe { (self.vtable.get_stlink_list)(&mut debug_connect_parameters, 0) };
735
736 let params_slice =
737 unsafe { std::slice::from_raw_parts(debug_connect_parameters, stlink_count as usize) };
738
739 params_slice
740 .iter()
741 .map(|param| -> Result<STLink, err::Error> {
742 let debug_connect_parameters = param.clone();
743 Ok(STLink {
744 debug_connect_parameters,
745 })
746 })
747 .collect::<Result<Vec<STLink>, err::Error>>()
748 }
749
750 pub fn connect(&self, stlink: &STLink) -> Result<(), err::Error> {
751 let error = unsafe { (self.vtable.connect_stlink)(stlink.debug_connect_parameters) };
752 if error == 0 {
753 Ok(())
754 } else {
755 Err(err::CubeProgrammerError::from(error).into())
756 }
757 }
758
759 pub fn disconnect(&self) {
760 unsafe { (self.vtable.disconnect)() };
761 }
762
763 pub fn reset(&self, stlink: &STLink) -> Result<(), err::Error> {
764 let error = unsafe { (self.vtable.reset)(stlink.debug_connect_parameters.reset_mode) };
765 if error == 0 {
766 Ok(())
767 } else {
768 Err(err::CubeProgrammerError::from(error).into())
769 }
770 }
771
772 pub fn mass_erase(&self) -> Result<(), err::Error> {
773 let error = unsafe { (self.vtable.mass_erase)() };
774 if error == 0 {
775 Ok(())
776 } else {
777 Err(err::CubeProgrammerError::from(error).into())
778 }
779 }
780
781 pub fn download<P: AsRef<std::path::Path>>(
782 &self,
783 path: P,
784 address: Option<u32>,
785 skip_erase: Option<bool>,
786 verify: Option<bool>,
787 ) -> Result<(), err::Error> {
788 let c_path = widestring::WideCString::from_os_str(
789 std::fs::canonicalize(path.as_ref())?.as_os_str(),
790 )?;
791
792 let error = unsafe {
793 (self.vtable.download_file)(
794 c_path.as_ptr(),
795 address.unwrap_or(0),
796 skip_erase.unwrap_or(true).into(),
797 verify.unwrap_or(true).into(),
798 std::ptr::null(),
799 )
800 };
801 if error == 0 {
802 Ok(())
803 } else {
804 Err(err::CubeProgrammerError::from(error).into())
805 }
806 }
807
808 pub fn device_info(&self) -> Result<DeviceInfo, err::Error> {
809 let device_general_info = unsafe { (self.vtable.get_device_general_info)().as_ref() };
810
811 match device_general_info {
812 Some(value) => Ok(DeviceInfo {
813 device_general_info: value.clone(),
814 }),
815 None => Err(err::CubeProgrammerError::NoDeviceFound.into()),
816 }
817 }
818
819 pub fn read_core_register(&self, register: Register) -> Result<u32, err::Error> {
820 let mut data = 0;
821 let error = unsafe { (self.vtable.read_core_register)(register.into(), &mut data) };
822 if error == 0 {
823 Ok(data)
824 } else {
825 Err(err::CubeProgrammerError::from(error).into())
826 }
827 }
828
829 pub fn write_core_register(&self, register: Register, data: u32) -> Result<(), err::Error> {
830 let error = unsafe { (self.vtable.write_core_register)(register.into(), data) };
831 if error == 0 {
832 Ok(())
833 } else {
834 Err(err::CubeProgrammerError::from(error).into())
835 }
836 }
837
838 pub fn read_memory8(&self, address: u32, size: u32) -> Result<Vec<u8>, err::Error> {
839 let mut data = std::ptr::null_mut();
840 let error = unsafe { (self.vtable.read_memory)(address, &mut data, size) };
841 if error == 0 {
842 let data: &mut [u8] = unsafe { core::slice::from_raw_parts_mut(data, size as usize) };
843 Ok(data.to_vec())
844 } else {
845 Err(err::CubeProgrammerError::from(error).into())
846 }
847 }
848
849 pub fn read_memory32(&self, address: u32, size: u32) -> Result<Vec<u32>, err::Error> {
850 let mut data = std::ptr::null_mut();
851 let error = unsafe { (self.vtable.read_memory)(address, &mut data, size * 4) };
852 if error == 0 {
853 let data: &mut [u8] =
854 unsafe { core::slice::from_raw_parts_mut(data, (size * 4) as usize) };
855 data.chunks(4)
856 .map(|chunk| -> Result<u32, err::Error> {
857 let chunk = std::convert::TryInto::try_into(chunk)?;
858 Ok(u32::from_le_bytes(chunk))
859 })
860 .collect::<Result<Vec<u32>, err::Error>>()
861 } else {
862 Err(err::CubeProgrammerError::from(error).into())
863 }
864 }
865
866 pub fn write_memory8(&self, address: u32, data: Vec<u8>) -> Result<(), err::Error> {
867 let size: u32 = std::convert::TryInto::try_into(data.len())?;
868
869 let error = unsafe { (self.vtable.write_memory)(address, data.clone().as_mut_ptr(), size) };
870 if error == 0 {
871 Ok(())
872 } else {
873 Err(err::CubeProgrammerError::from(error).into())
874 }
875 }
876
877 pub fn write_memory32(&self, address: u32, data_u32: Vec<u32>) -> Result<(), err::Error> {
878 let size: u32 = std::convert::TryInto::try_into(data_u32.len())?;
879 let mut data_u8: Vec<u8> = Vec::new();
880 for &num in &data_u32 {
881 data_u8.extend_from_slice(&num.to_le_bytes());
882 }
883
884 let error = unsafe { (self.vtable.write_memory)(address, data_u8.as_mut_ptr(), size * 4) };
885 if error == 0 {
886 Ok(())
887 } else {
888 Err(err::CubeProgrammerError::from(error).into())
889 }
890 }
891}