1#![no_std]
2
3extern crate alloc;
4
5struct Ev3Allocator {}
6#[global_allocator]
7static GLOBAL_ALLOCATOR: Ev3Allocator = Ev3Allocator {};
8
9unsafe impl GlobalAlloc for Ev3Allocator {
10 unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
11 ev3_malloc(layout.size())
12 .cast::<u8>()
13 .as_mut()
14 .expect("ev3_malloc failed")
15 }
16
17 unsafe fn dealloc(&self, ptr: *mut u8, _layout: core::alloc::Layout) {
18 ev3_free(ptr.cast::<core::ffi::c_void>())
19 }
20}
21
22pub fn reset(is_panic: bool) {
23 motor_stop(MotorPort::A, false);
24 motor_stop(MotorPort::B, false);
25 motor_stop(MotorPort::C, false);
26 motor_stop(MotorPort::D, false);
27 sensor_config(SensorPort::S1, SensorType::NONE);
28 sensor_config(SensorPort::S2, SensorType::NONE);
29 sensor_config(SensorPort::S3, SensorType::NONE);
30 sensor_config(SensorPort::S4, SensorType::NONE);
31 led_set_color(LedColor::OFF);
32 if is_panic {
33 lcd_apply(|fb| {
34 for (index, row) in fb.chunks_exact_mut(LCD_FRAMEBUFFER_ROW_BYTES).enumerate() {
35 if index % 2 == 0 {
36 row.fill(0b10101010);
37 } else {
38 row.fill(0b01010101);
39 }
40 }
41 });
42 for _ in 0..4 {
43 flash_led(LedColor::RED);
44 }
45 } else {
46 lcd_clear();
47 }
48}
49
50#[no_mangle]
51pub extern "C" fn abort() -> ! {
52 unsafe { ev3_exit_task() }
53 #[warn(clippy::empty_loop)]
54 loop {}
55}
56
57const PANIC_DATA_SIZE: usize = 512;
58const PANIC_FILE: &str = "PANIC.txt";
59struct PanicData {
60 data: [u8; PANIC_DATA_SIZE],
61 offset: usize,
62}
63
64impl PanicData {
65 pub fn new() -> Self {
66 PanicData {
67 data: [0; PANIC_DATA_SIZE],
68 offset: 0,
69 }
70 }
71
72 pub fn close(&mut self) {
73 if self.offset >= PANIC_DATA_SIZE {
74 self.offset = PANIC_DATA_SIZE - 1;
75 }
76 self.data[self.offset] = '\n' as u8;
77 self.offset = PANIC_DATA_SIZE;
78 }
79
80 pub fn save(&self) {
81 let mut file = MemFile::new();
82 file.load(PANIC_FILE);
83 if let Some(buffer) = file.buffer() {
84 let data = buffer.data_mut();
85 if data.len() == PANIC_DATA_SIZE {
86 data.copy_from_slice(&self.data);
87 buffer.write(PANIC_FILE);
88 }
89 }
90 file.free();
91 }
92}
93
94pub fn reset_ev3_panic_file() {
95 let mut data = PanicData::new();
96 data.write_str("panic data ready").ok();
97 data.close();
98 data.save();
99}
100
101impl Write for PanicData {
102 fn write_str(&mut self, s: &str) -> core::fmt::Result {
103 for c in s.bytes() {
104 if self.offset < PANIC_DATA_SIZE {
105 self.data[self.offset] = c;
106 self.offset += 1;
107 }
108 }
109 core::fmt::Result::Ok(())
110 }
111}
112
113fn flash_led(color: LedColor) {
114 led_set_color(color);
115 msleep(500);
116 led_set_color(LedColor::OFF);
117 msleep(500);
118}
119
120use core::{alloc::GlobalAlloc, fmt::Write};
121#[cfg(not(test))]
122#[panic_handler]
123fn panic(info: &core::panic::PanicInfo) -> ! {
124 reset(true);
125 let mut data = PanicData::new();
126 if let Some(location) = info.location() {
127 writeln!(
128 &mut data,
129 "panic at {}:{}",
130 "FILE",
132 location.line()
133 )
134 .ok();
135 } else {
136 writeln!(&mut data, "panic at unknown location").ok();
137 }
138 writeln!(&mut data, "message: {}", info.message()).ok();
139 data.close();
140 data.save();
141 abort();
142}
143
144#[repr(i32)]
145#[derive(Clone, Copy, PartialEq)]
146pub enum ER {
147 OK = 0,
148 SYS = -5,
149 NOSPT = -9,
150 RSFN = -10,
151 RSATR = -11,
152 PAR = -17,
153 ID = -18,
154 CTX = -25,
155 MACV = -26,
156 OACV = -27,
157 ILUSE = -28,
158 NOMEM = -33,
159 NOID = -34,
160 NORES = -35,
161 OBJ = -41,
162 NOEXS = -42,
163 QOVR = -43,
164 RLWAI = -49,
165 TMOUT = -50,
166 DLT = -51,
167 CLS = -52,
168 WBLK = -57,
169 BOVR = -58,
170}
171pub type ErUint = i32;
172
173#[repr(i32)]
174#[derive(Clone, Copy, PartialEq)]
175pub enum LedColor {
176 OFF = 0,
177 RED = 1,
178 GREEN = 2,
179 ORANGE = 3,
180}
181
182#[repr(i32)]
183#[derive(Clone, Copy, PartialEq)]
184pub enum Button {
185 LEFT = 0,
186 RIGHT = 1,
187 UP = 2,
188 DOWN = 3,
189 ENTER = 4,
190 BACK = 5,
191}
192
193#[repr(i32)]
194#[derive(Clone, Copy, PartialEq)]
195pub enum SerialPort {
196 DEFAULT = 0,
197 UART = 1,
198 BLUETOOTH = 2,
199}
200
201#[repr(i32)]
202#[derive(Clone, Copy, PartialEq)]
203pub enum LcdFont {
204 SMALL = 0,
205 MEDIUM = 1,
206}
207
208#[repr(i32)]
209#[derive(Clone, Copy, PartialEq)]
210pub enum LcdColor {
211 WHITE = 0,
212 BLACK = 1,
213}
214
215pub const LCD_WIDTH: i32 = 178;
216pub const LCD_HEIGHT: i32 = 128;
217pub const LCD_FRAMEBUFFER_ROW_BYTES: usize = 60;
218pub const LCD_FRAMEBUFFER_ROWS: usize = 128;
219pub const LCD_FRAMEBUFFER_SIZE: usize = LCD_FRAMEBUFFER_ROW_BYTES * LCD_FRAMEBUFFER_ROWS;
220
221#[repr(i32)]
222#[derive(Clone, Copy, PartialEq)]
223pub enum MotorPort {
224 A = 0,
225 B = 1,
226 C = 2,
227 D = 3,
228}
229
230#[repr(i32)]
231#[derive(Clone, Copy, PartialEq)]
232pub enum MotorType {
233 NONE = 0,
234 MEDIUM = 1,
235 LARGE = 2,
236 UNDEGULATED = 3,
237}
238impl From<i32> for MotorType {
239 fn from(t: i32) -> MotorType {
240 match t {
241 1 => MotorType::MEDIUM,
242 2 => MotorType::LARGE,
243 3 => MotorType::UNDEGULATED,
244 _ => MotorType::NONE,
245 }
246 }
247}
248
249#[repr(i32)]
250#[derive(Clone, Copy, PartialEq)]
251pub enum SensorPort {
252 S1 = 0,
253 S2 = 1,
254 S3 = 2,
255 S4 = 3,
256}
257
258#[repr(i32)]
259#[derive(Clone, Copy, PartialEq)]
260pub enum SensorType {
261 NONE = 0,
262 ULTRASONIC = 1,
263 GYRO = 2,
264 TOUCH = 3,
265 COLOR = 4,
266 INFRARED = 5,
267 HtNxtACCEL = 6,
268 HtNxtCOLOR = 7,
269 NxtULTRASONIC = 8,
270 NxtTEMP = 9,
271}
272impl From<i32> for SensorType {
273 fn from(t: i32) -> SensorType {
274 match t {
275 1 => SensorType::ULTRASONIC,
276 2 => SensorType::GYRO,
277 3 => SensorType::TOUCH,
278 4 => SensorType::COLOR,
279 5 => SensorType::INFRARED,
280 6 => SensorType::HtNxtACCEL,
281 7 => SensorType::HtNxtCOLOR,
282 8 => SensorType::NxtULTRASONIC,
283 9 => SensorType::NxtTEMP,
284 _ => SensorType::NONE,
285 }
286 }
287}
288
289#[repr(i32)]
290pub enum SensorColorCode {
291 NONE = 0,
292 BLACK = 1,
293 BLUE = 2,
294 GREEN = 3,
295 YELLOW = 4,
296 RED = 5,
297 WHITE = 6,
298 BROWN = 7,
299}
300
301#[repr(C)]
302#[derive(Debug, Copy, Clone)]
303pub struct RgbRaw {
304 pub r: u16,
306 pub g: u16,
308 pub b: u16,
310}
311
312#[repr(C)]
313#[derive(Debug, Copy, Clone)]
314pub struct IrSeek {
315 pub heading: [i8; 4usize],
317 pub distance: [i8; 4usize],
319}
320
321#[repr(C)]
322#[derive(Debug, Copy, Clone)]
323pub struct IrRemote {
324 pub channel: [u8; 4usize],
326}
327
328#[repr(C)]
329#[derive(Debug, Copy, Clone)]
330pub struct MemFile {
331 buffer: *const u8,
332 filesz: u32,
333 buffersz: u32,
334}
335
336impl MemFile {
337 pub fn new() -> Self {
338 MemFile {
339 buffer: core::ptr::null(),
340 filesz: 0,
341 buffersz: 0,
342 }
343 }
344
345 pub fn load(&mut self, path: &str) -> ER {
346 memfile_load(path, self)
347 }
348
349 pub fn data(&self) -> Option<&[u8]> {
350 if self.buffer.is_null() {
351 None
352 } else {
353 Some(unsafe { core::slice::from_raw_parts(self.buffer, self.filesz as usize) })
354 }
355 }
356
357 pub fn buffer(self) -> Option<MemFileBuffer> {
358 let mut memfile = self;
359 if memfile.buffer.is_null() {
360 memfile_free(&mut memfile);
361 None
362 } else {
363 Some(MemFileBuffer {
364 buffer: memfile.buffer as *mut u8,
365 filesz: memfile.filesz,
366 buffersz: memfile.buffersz,
367 })
368 }
369 }
370
371 pub fn free(self) {
372 let mut memfile = self;
373 memfile_free(&mut memfile);
374 }
375}
376
377#[repr(C)]
378#[derive(Debug, Copy, Clone)]
379pub struct MemFileBuffer {
380 buffer: *mut u8,
381 filesz: u32,
382 buffersz: u32,
383}
384
385impl MemFileBuffer {
386 pub fn data(&self) -> &[u8] {
387 unsafe { core::slice::from_raw_parts(self.buffer, self.filesz as usize) }
388 }
389
390 pub fn data_mut(&self) -> &mut [u8] {
391 unsafe { core::slice::from_raw_parts_mut(self.buffer, self.filesz as usize) }
392 }
393
394 pub fn write(&self, path: &str) -> ER {
395 file_write(path, self.data())
396 }
397
398 pub fn memfile(self) -> MemFile {
399 MemFile {
400 buffer: self.buffer,
401 filesz: self.filesz,
402 buffersz: self.buffersz,
403 }
404 }
405
406 pub fn free(self) {
407 let mut memfile = self.memfile();
408 memfile_free(&mut memfile);
409 }
410}
411
412pub type TMO = i32;
418pub type RELTIM = u32;
419pub type HRTCNT = u32;
420pub type SYSTIM = i64;
421pub type SYSUTM = u64;
422pub type BoolT = i8;
423
424extern "C" {
425 fn ev3_malloc(size: usize) -> *mut core::ffi::c_void;
426 fn ev3_free(ptr: *mut core::ffi::c_void) -> ();
427
428 fn ev3_exit_task() -> ();
429 fn ev3_get_utm(p_sysutm: &mut SYSUTM) -> ER;
430 fn ev3_sleep(ticks: i32) -> ER;
431
432 fn ev3_bluetooth_agent_set_period_ms(ms: u32);
433 fn ev3_bluetooth_agent_set_master(is_master: BoolT);
434 fn ev3_check_bluetooth_is_connected() -> BoolT;
435 fn ev3_schedule_bluetooth_agent_task() -> BoolT;
436 fn ev3_bt_write_value(value: u32) -> BoolT;
437 fn ev3_connect_to_bluetooth_device(addr: *const u8, pin: *const u8) -> ER;
438 fn ev3_bluetooth_agent_values_read_ptr() -> *mut u32;
439 fn ev3_bluetooth_agent_value_read_ptr() -> *mut u32;
440
441 fn ev3_battery_current_mA() -> i32;
442 fn ev3_battery_voltage_mV() -> i32;
443 fn ev3_button_is_pressed(button: Button) -> BoolT;
444
445 fn ev3_lcd_set_font(font: LcdFont) -> ER;
446 fn ev3_font_get_size(font: LcdFont, width: *mut i32, height: *mut i32) -> ER;
447 fn ev3_lcd_draw_string(str: *const u8, x: i32, y: i32) -> ER;
448 fn ev3_lcd_draw_line(x0: i32, y0: i32, x1: i32, y1: i32) -> ER;
449 fn ev3_lcd_pixels() -> *mut u8;
450 fn ev3_lcd_fill_rect(x: i32, y: i32, w: i32, h: i32, color: LcdColor) -> ER;
451 fn ev3_motor_config(port: MotorPort, mt: MotorType) -> ER;
452 fn ev3_motor_get_type(port: MotorPort) -> ErUint;
453 fn ev3_motor_get_counts(port: MotorPort) -> i32;
454 fn ev3_motor_get_ticks(port: MotorPort) -> u32;
455 fn ev3_motor_reset_counts(port: MotorPort) -> ER;
456 fn ev3_motor_set_power(port: MotorPort, power: i32) -> ER;
457 fn ev3_motor_get_power(port: MotorPort) -> i32;
458 fn ev3_motor_stop(port: MotorPort, brake: BoolT) -> ER;
459
460 fn ev3_sensor_config(port: SensorPort, st: SensorType) -> ER;
461 fn ev3_sensor_get_type(port: SensorPort) -> ErUint;
462 fn ev3_color_sensor_get_color(port: SensorPort) -> SensorColorCode;
463 fn ev3_color_sensor_get_reflect(port: SensorPort) -> u8;
464 fn ev3_color_sensor_get_ambient(port: SensorPort) -> u8;
465 fn ev3_color_sensor_get_rgb_raw(port: SensorPort, val: *mut RgbRaw);
466 fn ev3_gyro_sensor_get_angle(port: SensorPort) -> i16;
467 fn ev3_gyro_sensor_get_rate(port: SensorPort) -> i16;
468 fn ev3_gyro_sensor_reset(port: SensorPort) -> ER;
469 fn ev3_ultrasonic_sensor_get_distance(port: SensorPort) -> i16;
470 fn ev3_infrared_sensor_get_distance(port: SensorPort) -> u8;
473 fn ev3_touch_sensor_is_pressed(port: SensorPort) -> BoolT;
476 fn ev3_touch_sensor_analog_read_pin1(port: SensorPort) -> i16;
477 fn nxt_ultrasonic_sensor_get_last_reading(port: SensorPort) -> i16;
482 fn nxt_ultrasonic_sensor_did_reset(port: SensorPort) -> BoolT;
483 fn nxt_ultrasonic_sensor_request_read(port: SensorPort) -> BoolT;
484 fn nxt_ultrasonic_sensor_request_reset(port: SensorPort) -> BoolT;
485 fn nxt_ultrasonic_sensor_get_distance(port: SensorPort, distance: *mut i16) -> BoolT;
486
487 fn ev3_memfile_load(path: *const u8, memfile: *mut MemFile) -> ER;
492 fn ev3_memfile_free(memfile: *mut MemFile) -> ER;
493 fn ev3_file_write(path: *const u8, data: *const u8, size: u32) -> ER;
494
495 fn ev3_led_set_color(color: LedColor) -> ER;
496}
497
498pub fn get_utm(p_sysutm: &mut SYSUTM) -> ER {
499 unsafe { ev3_get_utm(p_sysutm) }
500}
501
502pub fn get_utime() -> SYSUTM {
503 let mut res: SYSUTM = 0;
504 match get_utm(&mut res) {
505 ER::OK => res,
506 _ => {
507 panic!("get_utime failed");
508 }
509 }
510}
511
512pub fn msleep(ms: i32) -> ER {
513 unsafe { ev3_sleep(ms) }
514}
515
516#[derive(Clone, Copy, PartialEq, Eq)]
517pub struct BtValue {
518 value: u32,
519}
520
521impl BtValue {
522 pub fn new(value: u32) -> Self {
523 BtValue { value }
524 }
525}
526
527impl From<BtValue> for u32 {
528 fn from(v: BtValue) -> u32 {
529 v.value
530 }
531}
532impl From<u32> for BtValue {
533 fn from(v: u32) -> BtValue {
534 BtValue { value: v }
535 }
536}
537
538impl From<BtValue> for i32 {
539 fn from(v: BtValue) -> i32 {
540 v.value as i32
541 }
542}
543impl From<i32> for BtValue {
544 fn from(v: i32) -> BtValue {
545 BtValue { value: v as u32 }
546 }
547}
548
549impl From<(u16, u16)> for BtValue {
550 fn from(v: (u16, u16)) -> BtValue {
551 BtValue {
552 value: (v.0 as u32) << 16 | v.1 as u32,
553 }
554 }
555}
556impl From<BtValue> for (u16, u16) {
557 fn from(v: BtValue) -> (u16, u16) {
558 ((v.value >> 16) as u16, v.value as u16)
559 }
560}
561
562impl From<(u8, u8, u8, u8)> for BtValue {
563 fn from(v: (u8, u8, u8, u8)) -> BtValue {
564 BtValue {
565 value: (v.0 as u32) << 24 | (v.1 as u32) << 16 | (v.2 as u32) << 8 | v.3 as u32,
566 }
567 }
568}
569impl From<BtValue> for (u8, u8, u8, u8) {
570 fn from(v: BtValue) -> (u8, u8, u8, u8) {
571 (
572 (v.value >> 24) as u8,
573 (v.value >> 16) as u8,
574 (v.value >> 8) as u8,
575 v.value as u8,
576 )
577 }
578}
579
580impl From<(i8, i8, i8, i8)> for BtValue {
581 fn from(v: (i8, i8, i8, i8)) -> BtValue {
582 BtValue {
583 value: ((v.0 as i32 & 0xff) << 24
584 | (v.1 as i32 & 0xff) << 16
585 | (v.2 as i32 & 0xff) << 8
586 | (v.3 as i32 & 0xff)) as u32,
587 }
588 }
589}
590impl From<BtValue> for (i8, i8, i8, i8) {
591 fn from(v: BtValue) -> (i8, i8, i8, i8) {
592 (
593 (v.value >> 24) as i8,
594 (v.value >> 16) as i8,
595 (v.value >> 8) as i8,
596 v.value as i8,
597 )
598 }
599}
600
601#[derive(Clone, Copy)]
602pub struct BT {
603 value: *mut u32,
604 counter: *mut u32,
605}
606
607impl BT {
608 pub fn new_master(slave: &[u8; 6], pin: &[u8; 4], read_period_ms: u32) -> Option<Self> {
609 bluetooth_agent_set_master(true);
610
611 let connected = unsafe {
612 let er = ev3_connect_to_bluetooth_device(slave.as_ptr(), pin.as_ptr());
613 er == ER::OK
614 };
615 if !connected {
616 return None;
617 }
618
619 if !schedule_bluetooth_agent_task() {
620 return None;
621 }
622
623 if !bluetooth_is_connected() {
624 return None;
625 }
626
627 bluetooth_agent_set_period_ms(read_period_ms);
628
629 Some(BT {
630 value: unsafe { ev3_bluetooth_agent_value_read_ptr() },
631 counter: unsafe { ev3_bluetooth_agent_values_read_ptr() },
632 })
633 }
634
635 pub fn new_slave(read_period_ms: u32) -> Option<Self> {
636 bluetooth_agent_set_master(false);
637
638 if !schedule_bluetooth_agent_task() {
639 return None;
640 }
641
642 if !bluetooth_is_connected() {
643 return None;
644 }
645
646 bluetooth_agent_set_period_ms(read_period_ms);
647
648 Some(BT {
649 value: unsafe { ev3_bluetooth_agent_value_read_ptr() },
650 counter: unsafe { ev3_bluetooth_agent_values_read_ptr() },
651 })
652 }
653
654 pub fn write(&self, value: BtValue) -> bool {
655 unsafe { ev3_bt_write_value(value.into()) != 0 }
656 }
657
658 pub fn read(&self) -> BtValue {
659 unsafe { *self.value }.into()
660 }
661
662 pub fn read_count(&self) -> usize {
663 (unsafe { *self.counter }) as usize
664 }
665
666 pub fn is_connected(&self) -> bool {
667 bluetooth_is_connected()
668 }
669
670 pub fn set_read_period(&self, ms: u32) {
671 bluetooth_agent_set_period_ms(ms);
672 }
673}
674
675pub fn bluetooth_agent_set_period_ms(ms: u32) {
676 unsafe {
677 ev3_bluetooth_agent_set_period_ms(ms);
678 }
679}
680
681pub fn bluetooth_agent_set_master(is_master: bool) {
682 unsafe {
683 ev3_bluetooth_agent_set_master(if is_master { 1 } else { 0 });
684 }
685}
686
687pub fn bluetooth_is_connected() -> bool {
688 unsafe { ev3_check_bluetooth_is_connected() != 0 }
689}
690
691pub fn schedule_bluetooth_agent_task() -> bool {
692 unsafe { ev3_schedule_bluetooth_agent_task() != 0 }
693}
694
695pub fn battery_current_ma() -> i32 {
696 unsafe { ev3_battery_current_mA() }
697}
698pub fn battery_voltage_mv() -> i32 {
699 unsafe { ev3_battery_voltage_mV() }
700}
701
702pub fn button_is_pressed(button: Button) -> bool {
703 unsafe { ev3_button_is_pressed(button) != 0 }
704}
705
706pub fn any_button_is_pressed() -> bool {
707 button_is_pressed(Button::BACK)
708 || button_is_pressed(Button::ENTER)
709 || button_is_pressed(Button::UP)
710 || button_is_pressed(Button::DOWN)
711 || button_is_pressed(Button::LEFT)
712 || button_is_pressed(Button::RIGHT)
713}
714
715pub fn wait_for_buttons_released() {
716 while any_button_is_pressed() {}
717}
718
719pub fn lcd_set_font(font: LcdFont) -> ER {
720 unsafe { ev3_lcd_set_font(font) }
721}
722
723pub fn font_get_size(font: LcdFont) -> (i32, i32) {
724 let mut w: i32 = 0;
725 let mut h: i32 = 0;
726 unsafe {
727 let er = ev3_font_get_size(font, &mut w, &mut h);
728 if let ER::OK = er {
729 (w, h)
730 } else {
731 (0, 0)
732 }
733 }
734}
735
736pub fn lcd_draw_string(s: &str, x: i32, y: i32) -> ER {
742 const MAX: usize = 32;
743 const BYTES: usize = MAX + 1;
744 let mut chars: [u8; BYTES] = [0; BYTES];
745 for (i, c) in s.bytes().enumerate() {
746 if i >= MAX {
747 break;
748 }
749 chars[i] = c;
750 chars[i + 1] = 0;
751 }
752 unsafe { ev3_lcd_draw_string(&(chars[0]), x, y) }
753}
754
755pub fn lcd_draw_line(x0: i32, y0: i32, x1: i32, y1: i32) -> ER {
756 unsafe { ev3_lcd_draw_line(x0, y0, x1, y1) }
757}
758
759pub fn lcd_fill_rect(x: i32, y: i32, w: i32, h: i32, color: LcdColor) -> ER {
760 unsafe { ev3_lcd_fill_rect(x, y, w, h, color) }
761}
762
763pub fn lcd_apply(f: impl Fn(&mut [u8; LCD_FRAMEBUFFER_SIZE])) {
764 unsafe {
765 let pixels = ev3_lcd_pixels().cast::<[u8; LCD_FRAMEBUFFER_SIZE]>();
766 let framebuffer = &mut *pixels;
767 f(framebuffer);
768 }
769}
770
771pub fn lcd_clear() {
772 lcd_apply(|fb| fb.fill(0x00));
773}
774
775pub fn motor_config(port: MotorPort, mt: MotorType) -> ER {
776 unsafe { ev3_motor_config(port, mt) }
777}
778
779pub fn motor_get_type(port: MotorPort) -> MotorType {
780 unsafe {
781 let t = ev3_motor_get_type(port);
782 MotorType::from(t)
783 }
784}
785
786pub fn motor_get_counts(port: MotorPort) -> i32 {
787 unsafe { ev3_motor_get_counts(port) }
788}
789
790pub fn motor_get_ticks(port: MotorPort) -> u32 {
791 unsafe { ev3_motor_get_ticks(port) }
792}
793
794pub fn motor_reset_counts(port: MotorPort) -> ER {
795 unsafe { ev3_motor_reset_counts(port) }
796}
797
798pub fn motor_set_power(port: MotorPort, power: i32) -> ER {
799 unsafe { ev3_motor_set_power(port, power) }
800}
801
802pub fn motor_get_power(port: MotorPort) -> i32 {
803 unsafe { ev3_motor_get_power(port) }
804}
805
806pub fn motor_stop(port: MotorPort, brake: bool) -> ER {
807 unsafe { ev3_motor_stop(port, if brake { 1 } else { 0 }) }
808}
809
810pub fn sensor_config(port: SensorPort, st: SensorType) -> ER {
811 unsafe { ev3_sensor_config(port, st) }
812}
813
814pub fn sensor_get_type(port: SensorPort) -> SensorType {
815 unsafe {
816 let t = ev3_sensor_get_type(port);
817 SensorType::from(t)
818 }
819}
820
821pub fn touch_sensor_is_pressed(port: SensorPort) -> bool {
822 unsafe { ev3_touch_sensor_is_pressed(port) != 0 }
823}
824
825pub fn analog_sensor_read(port: SensorPort) -> i16 {
826 unsafe { ev3_touch_sensor_analog_read_pin1(port) }
827}
828
829pub fn color_sensor_get_color(port: SensorPort) -> SensorColorCode {
830 unsafe { ev3_color_sensor_get_color(port) }
831}
832
833pub fn color_sensor_get_reflect(port: SensorPort) -> u8 {
834 unsafe { ev3_color_sensor_get_reflect(port) }
835}
836
837pub fn color_sensor_get_ambient(port: SensorPort) -> u8 {
838 unsafe { ev3_color_sensor_get_ambient(port) }
839}
840
841pub fn color_sensor_get_rgb(port: SensorPort) -> RgbRaw {
842 let mut r = RgbRaw { r: 0, g: 0, b: 0 };
843 unsafe {
844 ev3_color_sensor_get_rgb_raw(port, &mut r);
845 }
846 r
847}
848
849pub fn gyro_sensor_get_angle(port: SensorPort) -> i16 {
850 unsafe { ev3_gyro_sensor_get_angle(port) }
851}
852
853pub fn gyro_sensor_get_rate(port: SensorPort) -> i16 {
854 unsafe { ev3_gyro_sensor_get_rate(port) }
855}
856
857pub fn gyro_sensor_reset(port: SensorPort) -> ER {
858 unsafe { ev3_gyro_sensor_reset(port) }
859}
860
861pub fn ultrasonic_sensor_get_distance(port: SensorPort) -> i16 {
862 unsafe { ev3_ultrasonic_sensor_get_distance(port) }
863}
864
865pub fn infrared_sensor_get_distance(port: SensorPort) -> u8 {
868 unsafe { ev3_infrared_sensor_get_distance(port) }
869}
870
871pub fn ultrasonic_sensor_get_last_reading_nxt(port: SensorPort) -> i16 {
880 unsafe { nxt_ultrasonic_sensor_get_last_reading(port) }
881}
882
883pub fn ultrasonic_sensor_did_reset_nxt(port: SensorPort) -> bool {
884 unsafe { nxt_ultrasonic_sensor_did_reset(port) != 0 }
885}
886
887pub fn ultrasonic_sensor_request_read_nxt(port: SensorPort) -> bool {
888 unsafe { nxt_ultrasonic_sensor_request_read(port) != 0 }
889}
890
891pub fn ultrasonic_sensor_request_reset_nxt(port: SensorPort) -> bool {
892 unsafe { nxt_ultrasonic_sensor_request_reset(port) != 0 }
893}
894
895pub fn ultrasonic_sensor_get_distance_nxt(port: SensorPort) -> i16 {
896 let mut d = 0;
897 unsafe {
898 nxt_ultrasonic_sensor_get_distance(port, &mut d);
899 }
900 d
901}
902
903const MAX_PATH_LEN: usize = 32;
908fn str2path(s: &str) -> [u8; MAX_PATH_LEN] {
909 let mut c_path = [0u8; MAX_PATH_LEN];
910 for (i, c) in s.bytes().take(MAX_PATH_LEN - 1).enumerate() {
911 c_path[i] = c;
912 }
913 c_path
914}
915
916pub fn memfile_load(path: &str, memfile: &mut MemFile) -> ER {
917 let path = str2path(path);
918 unsafe { ev3_memfile_load(path.as_ptr(), memfile) }
919}
920pub fn memfile_free(memfile: &mut MemFile) -> ER {
921 unsafe { ev3_memfile_free(memfile) }
922}
923pub fn file_write(path: &str, data: &[u8]) -> ER {
924 let path = str2path(path);
925 unsafe { ev3_file_write(path.as_ptr(), data.as_ptr(), data.len() as u32) }
926}
927
928pub fn led_set_color(color: LedColor) -> ER {
929 unsafe { ev3_led_set_color(color) }
930}