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
//! [![github]](https://github.com/NotQuiteApex/picoboot-rs)   [![crates-io]](https://crates.io/crates/picoboot-rs)   [![docs-rs]](https://docs.rs/picoboot-rs)
//!
//! [github]: https://img.shields.io/badge/github-8da0cb?style=for-the-badge&labelColor=555555&logo=github
//! [crates-io]: https://img.shields.io/badge/crates.io-fc8d62?style=for-the-badge&labelColor=555555&logo=rust
//! [docs-rs]: https://img.shields.io/badge/docs.rs-66c2a5?style=for-the-badge&labelColor=555555&logo=docs.rs
//!
//! Connecting to and communicating with a Raspberry Pi microcontroller in BOOTSEL mode over USB.
//!
//! <br>
//!
//! PICOBOOT is a USB interface provided by Raspberry Pi microcontrollers when
//! in BOOTSEL mode. Normally, firmware for a Raspberry Pi microcontroller is
//! loaded over a USB Mass Storage Device interface, appearing as a 128MB flash
//! drive to the computer. The PICOBOOT interface is (usually) also active
//! during this time, and can be used for more advanced management of the
//! microcontroller device.
//!
//! # Example
//!
//! Flash a UF2 to a Pico device!
//!
//! ```rust
//! use picoboot_rs::{
//! PicobootConnection, TargetID, PICO_FLASH_START, PICO_PAGE_SIZE, PICO_SECTOR_SIZE,
//! PICO_STACK_POINTER,
//! };
//!
//! use rusb::Context;
//! use uf2_decode::convert_from_uf2;
//!
//! // creates a vector of vectors of u8's that map to flash pages sequentially
//! fn uf2_pages(bytes: Vec<u8>) -> Vec<Vec<u8>> {
//! // loads the uf2 file into a binary
//! let fw = convert_from_uf2(&bytes).expect("failed to parse uf2").0;
//!
//! let mut fw_pages: Vec<Vec<u8>> = vec![];
//! let len = fw.len();
//!
//! // splits the binary into sequential pages
//! for i in (0..len).step_by(PICO_PAGE_SIZE as usize) {
//! let size = std::cmp::min(len - i, PICO_PAGE_SIZE as usize);
//! let mut page = fw[i..i + size].to_vec();
//! page.resize(PICO_PAGE_SIZE as usize, 0);
//! fw_pages.push(page);
//! }
//!
//! fw_pages
//! }
//!
//! fn main() {
//! match Context::new() {
//! Ok(ctx) => {
//! // create connection object
//! let mut conn = PicobootConnection::new(ctx, None)
//! .expect("failed to connect to PICOBOOT interface");
//!
//! conn.reset_interface().expect("failed to reset interface");
//! conn.access_exclusive_eject().expect("failed to claim access");
//! conn.exit_xip().expect("failed to exit from xip mode");
//!
//! // firmware in a big vector of u8's
//! let fw = std::fs::read("blink.uf2").expect("failed to read firmware");
//! let fw_pages = uf2_pages(fw);
//!
//! // erase space on flash
//! for (i, _) in fw_pages.iter().enumerate() {
//! let addr = (i as u32) * PICO_PAGE_SIZE + PICO_FLASH_START;
//! if (addr % PICO_SECTOR_SIZE) == 0 {
//! conn.flash_erase(addr, PICO_SECTOR_SIZE)
//! .expect("failed to erase flash");
//! }
//! }
//!
//! for (i, page) in fw_pages.iter().enumerate() {
//! let addr = (i as u32) * PICO_PAGE_SIZE + PICO_FLASH_START;
//! let size = PICO_PAGE_SIZE as u32;
//!
//! // write page to flash
//! conn.flash_write(addr, page).expect("failed to write flash");
//!
//! // confirm flash write was successful
//! let read = conn.flash_read(addr, size).expect("failed to read flash");
//! let matching = page.iter().zip(&read).all(|(&a, &b)| a == b);
//! assert!(matching, "page does not match flash");
//! }
//!
//! // reboot device to start firmware
//! let delay = 500; // in milliseconds
//! match conn.get_device_type() {
//! TargetID::Rp2040 => {
//! conn.reboot(0x0, PICO_STACK_POINTER, delay)
//! .expect("failed to reboot device");
//! }
//! TargetID::Rp2350 => conn.reboot2_normal(delay)
//! .expect("failed to reboot device"),
//! }
//! }
//! Err(e) => panic!("Could not initialize libusb: {}", e),
//! }
//! }
//! ```
/// RP MCU flash page size (for writing)
pub const PICO_PAGE_SIZE: u32 = 0x100;
/// RP MCU flash sector size (for erasing)
pub const PICO_SECTOR_SIZE: u32 = 0x1000;
/// RP MCU memory address for the start of flash storage
pub const PICO_FLASH_START: u32 = 0x10000000;
/// RP MCU memory address for the initial stack pointer
pub const PICO_STACK_POINTER: u32 = 0x20042000; // same as SRAM_END_RP2040
/// RP USB Vendor ID
pub const PICOBOOT_VID: u16 = 0x2E8A;
/// RP2040 USB Product ID
pub const PICOBOOT_PID_RP2040: u16 = 0x0003;
/// RP2350 USB Product ID
pub const PICOBOOT_PID_RP2350: u16 = 0x000f;
/// RP MCU magic number for USB interfacing
pub const PICOBOOT_MAGIC: u32 = 0x431FD10B;
/// UF2 Family ID for RP2040
pub const UF2_RP2040_FAMILY_ID: u32 = 0xE48BFF56;
// pub const UF2_ABSOLUTE_FAMILY_ID: u32 = 0xE48BFF57;
// pub const UF2_DATA_FAMILY_ID: u32 = 0xE48BFF58;
/// UF2 Family ID for RP2350 (ARM, Secure TrustZone)
pub const UF2_RP2350_ARM_S_FAMILY_ID: u32 = 0xE48BFF59;
/// UF2 Family ID for RP2350 (RISC-V)
pub const UF2_RP2350_RISCV_FAMILY_ID: u32 = 0xE48BFF5A;
/// UF2 Family ID for RP2350 (ARM, Non-Secure TrustZone)
pub const UF2_RP2350_ARM_NS_FAMILY_ID: u32 = 0xE48BFF5B;
// pub const UF2_FAMILY_ID_MAX: u32 = 0xE48BFF5B;
/// Command Module
pub use ;
/// USB Connection Module
pub use PicobootConnection;