Skip to content

Commit 652ecb3

Browse files
committed
Add command to get firmware version
And also embed it properl in the USB descriptor's bcdDevice. Signed-off-by: Daniel Schaefer <[email protected]>
1 parent c5ce182 commit 652ecb3

File tree

8 files changed

+83
-12
lines changed

8 files changed

+83
-12
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
edition = "2021"
33
name = "lotus_inputmodules"
4-
version = "0.1.1"
4+
version = "0.1.2-pre"
55

66
[dependencies]
77
cortex-m = { version = "0.7", features = ["critical-section-single-core"]}

README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,25 @@ cargo run
121121
Or by copying the above generated UF2 file to the partition mounted when the
122122
module is in the bootloder.
123123

124+
### Check the firmware version of the device
125+
126+
###### In-band using `control.py`
127+
128+
```sh
129+
> ./control.py --version
130+
Device version: 0.1.2
131+
```
132+
133+
###### By looking at the USB descriptor
134+
135+
On Linux:
136+
137+
```sh
138+
> lsusb -d 32ac: -v 2> /dev/null | grep -P 'ID 32ac|bcdDevice'
139+
Bus 003 Device 078: ID 32ac:0021 Framework Lotus B1 Display
140+
bcdDevice 0.10
141+
```
142+
124143
## Panic
125144

126145
On panic the RP2040 resets itself into bootloader mode.

control.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,8 @@ def main():
8282
parser.add_argument("--snake", help="Snake", action="store_true")
8383
parser.add_argument(
8484
"--all-brightnesses", help="Show every pixel in a different brightness", action="store_true")
85+
parser.add_argument("-v", "--version",
86+
help="Get device version", action="store_true")
8587
parser.add_argument("--serial-dev", help="Change the serial dev. Probably /dev/ttyACM0 on Linux, COM0 on Windows",
8688
default='/dev/ttyACM0')
8789
args = parser.parse_args()
@@ -149,6 +151,9 @@ def main():
149151
show_string(args.string)
150152
elif args.symbols is not None:
151153
show_symbols(args.symbols)
154+
elif args.version:
155+
version = get_version()
156+
print(f"Device version: {version}")
152157
else:
153158
print("Provide arg")
154159

@@ -180,6 +185,21 @@ def get_brightness():
180185
return int(res[0])
181186

182187

188+
def get_version():
189+
"""Get the device's firmware version"""
190+
command = FWK_MAGIC + [0x20]
191+
res = send_command(command, with_response=True)
192+
major = res[0]
193+
minor = (res[1] & 0xF0) >> 4
194+
patch = res[1] & 0xF
195+
pre_release = res[2]
196+
197+
version = f"{major}.{minor}.{patch}"
198+
if pre_release:
199+
version += " (Pre-release)"
200+
return version
201+
202+
183203
def animate(b: bool):
184204
"""Tell the firmware to start/stop animation.
185205
Scrolls the currently saved grid vertically down."""

src/bin/b1display.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ use heapless::String;
4747

4848
use lotus_input::control::*;
4949
use lotus_input::graphics::*;
50-
use lotus_input::serialnum::get_serialnum;
50+
use lotus_input::serialnum::{device_release, get_serialnum};
5151

5252
// FRA - Framwork
5353
// KDE - Lotus C2 LED Matrix
@@ -118,7 +118,7 @@ fn main() -> ! {
118118
.product("Lotus B1 Display")
119119
.serial_number(serialnum)
120120
.max_power(500) // TODO: Check how much
121-
.device_release(0x0010) // TODO: Assign dynamically based on crate version
121+
.device_release(device_release()) // TODO: Assign dynamically based on crate version
122122
.device_class(USB_CLASS_CDC)
123123
.build();
124124

@@ -215,7 +215,10 @@ fn main() -> ! {
215215
handle_sleep(go_sleeping, &mut state, &mut delay, &mut lcd_led);
216216
} else if let SleepState::Awake = state.sleeping {
217217
// While sleeping no command is handled, except waking up
218-
handle_command(&command, &mut disp, logo_rect);
218+
//handle_command(&command, &mut disp, logo_rect);
219+
if let Some(response) = handle_command(&command, &mut disp, logo_rect) {
220+
let _ = serial.write(&response);
221+
};
219222
}
220223
}
221224
}

src/bin/ledmatrix.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ use lotus_input::control::*;
100100
use lotus_input::lotus::LotusLedMatrix;
101101
use lotus_input::matrix::*;
102102
use lotus_input::patterns::*;
103-
use lotus_input::serialnum::get_serialnum;
103+
use lotus_input::serialnum::{device_release, get_serialnum};
104104

105105
// FRA - Framwork
106106
// KDE - Lotus C2 LED Matrix
@@ -160,7 +160,7 @@ fn main() -> ! {
160160
.product("Lotus LED Matrix")
161161
.serial_number(serialnum)
162162
.max_power(200) // Device uses roughly 164mW when all LEDs are at full brightness
163-
.device_release(0x0011) // TODO: Assign dynamically based on crate version
163+
.device_release(device_release())
164164
.device_class(USB_CLASS_CDC)
165165
.build();
166166

src/control.rs

Lines changed: 22 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use heapless::String;
1717
use crate::matrix::*;
1818
#[cfg(feature = "ledmatrix")]
1919
use crate::patterns::*;
20+
use crate::serialnum::{device_release, is_pre_release};
2021

2122
pub enum _CommandVals {
2223
_Brightness = 0x00,
@@ -29,6 +30,7 @@ pub enum _CommandVals {
2930
_StageGreyCol = 0x07,
3031
_DrawGreyColBuffer = 0x08,
3132
SetText = 0x09,
33+
Version = 0x20,
3234
}
3335

3436
pub enum PatternVals {
@@ -70,6 +72,7 @@ pub enum Command {
7072
DrawGreyColBuffer,
7173
#[cfg(feature = "b1display")]
7274
SetText(String<64>),
75+
Version,
7376
_Unknown,
7477
}
7578
pub fn parse_command(count: usize, buf: &[u8]) -> Option<Command> {
@@ -94,6 +97,7 @@ pub fn parse_command(count: usize, buf: &[u8]) -> Option<Command> {
9497
Command::IsSleeping
9598
}),
9699
0x05 => Some(Command::Panic),
100+
0x20 => Some(Command::Version),
97101
_ => None, //Some(Command::Unknown),
98102
}
99103
} else {
@@ -196,17 +200,27 @@ pub fn parse_module_command(_count: usize, _buf: &[u8]) -> Option<Command> {
196200
None
197201
}
198202

199-
pub fn handle_generic_command(command: &Command) {
203+
pub fn handle_generic_command(command: &Command) -> Option<[u8; 32]> {
200204
match command {
201205
Command::BootloaderReset => {
202206
//let _ = serial.write("Bootloader Reset".as_bytes());
203207
reset_to_usb_boot(0, 0);
208+
None
204209
}
205210
Command::Sleep(_go_sleeping) => {
206211
// Handled elsewhere
212+
None
207213
}
208214
Command::Panic => panic!("Ahhh"),
209-
_ => {}
215+
Command::Version => {
216+
let mut response: [u8; 32] = [0; 32];
217+
let bcd_device = device_release().to_be_bytes();
218+
response[0] = bcd_device[0];
219+
response[1] = bcd_device[1];
220+
response[2] = is_pre_release() as u8;
221+
return Some(response);
222+
}
223+
_ => None,
210224
}
211225
}
212226

@@ -274,13 +288,13 @@ pub fn handle_command(command: &Command, state: &mut State, matrix: &mut Foo) ->
274288
return Some(response);
275289
}
276290
// TODO: Make it return something
277-
_ => handle_generic_command(command),
291+
_ => return handle_generic_command(command),
278292
}
279293
None
280294
}
281295

282296
#[cfg(feature = "b1display")]
283-
pub fn handle_command<D>(command: &Command, disp: &mut D, logo_rect: Rectangle)
297+
pub fn handle_command<D>(command: &Command, disp: &mut D, logo_rect: Rectangle) -> Option<[u8; 32]>
284298
where
285299
D: DrawTarget<Color = Rgb565>,
286300
<D as DrawTarget>::Error: Debug,
@@ -289,9 +303,11 @@ where
289303
Command::BootloaderReset => {
290304
//let _ = serial.write("Bootloader Reset".as_bytes());
291305
reset_to_usb_boot(0, 0);
306+
None
292307
}
293308
Command::Sleep(_go_sleeping) => {
294309
// Handled elsewhere
310+
None
295311
}
296312
Command::Panic => panic!("Ahhh"),
297313
Command::SetText(text) => {
@@ -307,7 +323,8 @@ where
307323
Point::new(0, LOGO_OFFSET + logo_rect.size.height as i32),
308324
)
309325
.unwrap();
326+
None
310327
}
311-
_ => handle_generic_command(command),
328+
_ => return handle_generic_command(command),
312329
}
313330
}

src/serialnum.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,15 @@ pub fn get_serialnum() -> Option<&'static str> {
1414
core::str::from_utf8(slice).ok()
1515
}
1616
}
17+
18+
/// Get the firmware version in a format for USB Device Release
19+
/// The value is in binary coded decimal with a format of 0xJJMN where JJ is the major version number, M is the minor version number and N is the sub minor version number. e.g. USB 2.0 is reported as 0x0200, USB 1.1 as 0x0110 and USB 1.0 as 0x0100.
20+
pub fn device_release() -> u16 {
21+
(env!("CARGO_PKG_VERSION_MAJOR").parse::<u16>().unwrap() << 8)
22+
+ (env!("CARGO_PKG_VERSION_MINOR").parse::<u16>().unwrap() << 4)
23+
+ env!("CARGO_PKG_VERSION_PATCH").parse::<u16>().unwrap()
24+
}
25+
26+
pub fn is_pre_release() -> bool {
27+
!env!("CARGO_PKG_VERSION_PRE").is_empty()
28+
}

0 commit comments

Comments
 (0)