diff --git a/serial.c b/serial.c index ad06d0e..66926e1 100644 --- a/serial.c +++ b/serial.c @@ -703,7 +703,7 @@ again: return (char*)&reply[1]; } -void serial_read_region(int addr, unsigned char *data, int nbytes) +void c_serial_read_region(int addr, unsigned char *data, int nbytes) { static const int DATASZ = 64; unsigned char cmd[6], reply[8 + DATASZ]; @@ -741,7 +741,7 @@ again: } } -void serial_write_region(int addr, unsigned char *data, int nbytes) +void c_serial_write_region(int addr, unsigned char *data, int nbytes) { //static const int DATASZ = 64; static const int DATASZ = 16; diff --git a/src/radio.rs b/src/radio.rs index 62786ae..147607b 100644 --- a/src/radio.rs +++ b/src/radio.rs @@ -77,6 +77,10 @@ pub fn connect() -> Radio { let trace_flag = false; //TODO fix if let Some(device_path) = crate::serial::serial_init(0x28e9, 0x018a, trace_flag) { if let Some(identifier) = crate::serial::identify(&device_path) { + unsafe { + crate::serial::device_path = Some(device_path); + } + return identifier; } } diff --git a/src/serial.rs b/src/serial.rs index de9f2c8..b93f253 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -1,8 +1,11 @@ use std::ffi::{CStr}; -use libc::{c_char}; +use libc::{c_char, c_int, c_uchar, c_void}; use std::process::exit; use std::time::Duration; +//hack to handle the serial device path state +pub static mut device_path: Option = None; + extern { fn find_path(vid: libc::c_int, pid: libc::c_int) -> *const c_char; fn serial_identify(s: *const c_char) -> *const c_char; @@ -61,6 +64,151 @@ fn send_receive(port: &mut dyn serial::SerialPort, command: &[u8], reply_len: us buf } +#[no_mangle] +pub extern "C" fn serial_read_region(addr: c_int, data: *mut c_uchar, nbytes: c_int) { + use serial::prelude::*; + + let dev_path = unsafe { + match device_path { + Some(ref s) => s.clone(), + None => { + eprintln!("No serial device path set, exiting"); + exit(-1); + } + } + }; + + let mut port = match serial::open(&dev_path) { + Ok(port) => port, + Err(err) => { + println!("{}", err); + exit(-1); + } + }; + + port.reconfigure(&|settings: &mut dyn SerialPortSettings| { + settings.set_baud_rate(serial::BaudRate::Baud115200)?; + settings.set_char_size(serial::CharSize::Bits8); + Ok(()) + }).unwrap(); + port.set_timeout(Duration::new(1,0)).unwrap(); + + const DATA_SIZE: usize = 64; + let num_bytes = nbytes as usize; + let addr = addr as usize; + + let mut output_data = vec![]; + + let mut n = 0; + while n < num_bytes { + // Serial read command: 'R' aa aa aa aa 0x10 + let cmd: [u8; 6] = [ + 0x52, // ASCII 'R' + ((addr + n) >> 24) as u8, + ((addr + n) >> 16) as u8, + ((addr + n) >> 8) as u8, + (addr + n) as u8, + 64, + ]; + let reply_len = 8 + DATA_SIZE; + eprintln!("Here in serial_read_region"); + let reply = send_receive(&mut port, &cmd, reply_len, true); + if reply[0] != b'W' || reply[7+DATA_SIZE] != 0x6 { + eprintln!("serial_read_region: wrong read reply: {:?} shit: {}", reply, reply[7+DATA_SIZE]); + exit(-1); + } + + //Compute checksum + let mut checksum: u8 = reply[1]; + for idx in 2..6+DATA_SIZE { + checksum = checksum.overflowing_add(reply[idx]).0; + } + let expected_checksum = reply[6+DATA_SIZE]; + if checksum != expected_checksum { + eprintln!("serial_read_region: wrong read checksum {}, expected {}", checksum, expected_checksum); + exit(-1); + } + + output_data.extend(reply.into_iter()); + n += DATA_SIZE; + } + + let n = output_data.len(); + let ptr = output_data.as_ptr() as *const c_void; + unsafe { + libc::memcpy(data as *mut c_void, ptr, n); + } +} + +#[no_mangle] +pub extern "C" fn serial_write_region(addr: c_int, data: *mut c_uchar, nbytes: c_int) { + use serial::prelude::*; + + let dev_path = unsafe { + match device_path { + Some(ref s) => s.clone(), + None => { + eprintln!("No serial device path set, exiting"); + exit(-1); + } + } + }; + + let mut port = match serial::open(&dev_path) { + Ok(port) => port, + Err(err) => { + println!("{}", err); + exit(-1); + } + }; + + port.reconfigure(&|settings: &mut dyn SerialPortSettings| { + settings.set_baud_rate(serial::BaudRate::Baud115200)?; + settings.set_char_size(serial::CharSize::Bits8); + Ok(()) + }).unwrap(); + port.set_timeout(Duration::new(1,0)).unwrap(); + + const DATA_SIZE: usize = 16; + + let num_bytes = nbytes as usize; + let addr = addr as usize; + + let mut n = 0; + while n < num_bytes { + let mut cmd: [u8; 8 + DATA_SIZE] = [0; 8 + DATA_SIZE]; + cmd[0] = 0x57; // ASCII 'W' + cmd[1] = ((addr + n) >> 24) as u8; + cmd[2] = ((addr + n) >> 16) as u8; + cmd[3] = ((addr + n) >> 8) as u8; + cmd[4] = (addr + n) as u8; + cmd[5] = DATA_SIZE as u8; + + let ptr = unsafe { + cmd.as_mut_ptr().offset(6) as *mut c_void + }; + unsafe { + libc::memcpy(ptr, data.offset(n as isize) as *const c_void, DATA_SIZE); + } + + //Compute checksum + let mut checksum: u8 = cmd[1]; + for idx in 2..(6+DATA_SIZE) { + checksum = checksum.overflowing_add(cmd[idx]).0; + } + cmd[DATA_SIZE+6] = checksum; + cmd[DATA_SIZE+7] = b'\x06'; // CMD_ACK byte + let reply = send_receive(&mut port, &cmd, 1, true); + if reply[0] != b'\x06' { + eprintln!("serial_write_region: wrong acknowledge {:?}, expected: {:?}", reply, b'\x06'); + exit(-1); + } + + n += DATA_SIZE as usize; + } +} + + /// Query and return the device identification string. /// On error, return None. pub fn identify(dev_path: &str) -> Option {