dmrconfig/src/radio.rs

225 lines
5.8 KiB
Rust
Raw Normal View History

2021-02-28 19:41:21 -08:00
use std::ffi::{CStr, CString};
2021-02-28 20:14:21 -08:00
use libc::{c_char, c_int, c_uint};
2021-02-28 01:19:31 -08:00
use std::os::unix::io::AsRawFd;
2021-03-01 00:11:41 -08:00
use std::process::exit;
2021-02-28 01:19:31 -08:00
2021-02-28 12:23:30 -08:00
include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
2021-02-28 19:41:21 -08:00
#[repr(C)]
pub struct radio_tab_t {
ident: *const c_char,
device: *const radio_device_t,
}
2021-02-27 23:16:01 -08:00
extern {
2021-02-28 19:41:21 -08:00
2021-03-01 00:11:41 -08:00
fn set_active_device(device: *const radio_device_t);
//fn radio_connect() -> *const radio_device_t;
2021-02-28 11:33:05 -08:00
2021-02-28 12:23:30 -08:00
fn radio_download(device: *const radio_device_t);
fn radio_upload(device: *const radio_device_t, cont_flag: c_int);
fn radio_verify_config(device: *const radio_device_t);
fn radio_print_version(device: *const radio_device_t, stdout: *const libc::FILE);
fn radio_print_config(device: *const radio_device_t, file: *const libc::FILE, verbose: c_int);
fn radio_read_image(filename: *const c_char) -> *const radio_device_t;
fn radio_save_image(device: *const radio_device_t, filename: *const c_char);
fn radio_parse_config(device: *const radio_device_t, filename: *const c_char);
fn radio_write_csv(device: *const radio_device_t, filename: *const c_char);
2021-02-28 11:33:05 -08:00
2021-02-28 20:14:21 -08:00
fn dfu_init(vid: c_uint, pid: c_uint) -> *const c_char;
2021-02-28 11:33:05 -08:00
fn dfu_reboot();
fn dfu_close();
2021-02-28 20:14:21 -08:00
fn hid_init(vid: c_int, pid: c_int) -> c_int;
fn hid_identify() -> *const c_char;
2021-02-28 11:33:05 -08:00
fn hid_close();
2021-02-28 20:14:21 -08:00
fn serial_init(vid: c_int, pid: c_int) -> c_int;
fn serial_identify() -> *const c_char;
2021-02-28 11:33:05 -08:00
fn serial_close();
2021-02-28 19:41:21 -08:00
fn get_radio_tab() -> *const radio_tab_t;
2021-02-27 23:16:01 -08:00
}
/// Connect to the radio via the serial port.
2021-02-28 20:14:21 -08:00
/// and identify the type of device.
2021-02-28 12:23:30 -08:00
pub fn connect() -> *const radio_device_t {
2021-02-28 01:31:29 -08:00
unsafe {
2021-03-01 00:11:41 -08:00
let mut ident: *const c_char;
2021-02-28 20:14:21 -08:00
// Try TYT MD family.
ident = dfu_init(0x0483, 0xdf11);
if ident.is_null() {
// Try RD-5R, DM-1801 and GD-77.
2021-03-01 00:11:41 -08:00
if hid_init(0x15a2, 0x0073) >= 0 {
2021-02-28 20:14:21 -08:00
ident = hid_identify();
2021-03-01 00:11:41 -08:00
}
2021-02-28 20:14:21 -08:00
}
if ident.is_null() {
// Try AT-D868UV.
2021-03-01 00:11:41 -08:00
if serial_init(0x28e9, 0x018a) >= 0 {
2021-02-28 20:14:21 -08:00
ident = serial_identify();
2021-03-01 00:11:41 -08:00
}
2021-02-28 20:14:21 -08:00
}
if ident.is_null() {
eprintln!("No radio detected.");
eprintln!("Check your USB cable!");
exit(-1);
}
let ident_str = CStr::from_ptr(ident).to_str().unwrap();
2021-03-01 00:11:41 -08:00
let mut device: *const radio_device_t = std::ptr::null();
let mut radio_tab_ptr = get_radio_tab();
2021-02-28 20:14:21 -08:00
loop {
2021-03-01 00:11:41 -08:00
let ident_ptr = (*radio_tab_ptr).ident;
2021-02-28 20:14:21 -08:00
if ident_ptr.is_null() {
break;
}
2021-03-01 00:11:41 -08:00
let table_ident = CStr::from_ptr(ident_ptr).to_str().unwrap();
if ident_str.eq_ignore_ascii_case(table_ident) {
device = (*radio_tab_ptr).device;
2021-02-28 20:14:21 -08:00
break;
}
2021-03-01 00:11:41 -08:00
radio_tab_ptr = radio_tab_ptr.offset(1);
2021-02-28 20:14:21 -08:00
}
2021-03-01 00:11:41 -08:00
2021-02-28 20:14:21 -08:00
if device.is_null() {
eprintln!("Unrecognized radio '{}'.", ident_str);
exit(-1);
}
2021-03-01 00:11:41 -08:00
let name_ptr = (*device).name;
let name = CStr::from_ptr(name_ptr).to_str().unwrap();
println!("Connect to {}", name);
2021-02-28 20:14:21 -08:00
2021-03-01 00:11:41 -08:00
set_active_device(device);
return device;
2021-02-28 01:31:29 -08:00
}
}
/// Close the serial port.
2021-02-28 01:31:29 -08:00
pub fn disconnect() {
2021-02-28 11:33:05 -08:00
eprintln!("Close device.");
2021-02-28 01:31:29 -08:00
unsafe {
2021-02-28 11:33:05 -08:00
// Restore the normal radio mode.
dfu_reboot();
dfu_close();
hid_close();
serial_close();
2021-02-28 01:31:29 -08:00
}
}
/// Read firmware image from the device
2021-02-28 12:23:30 -08:00
pub fn download(device: *const radio_device_t) {
2021-02-28 01:31:29 -08:00
unsafe {
radio_download(device)
2021-02-28 01:31:29 -08:00
}
}
/// Write firmware image to the device.
2021-02-28 12:23:30 -08:00
pub fn upload(device: *const radio_device_t, cont_flag: c_int) {
2021-02-28 02:38:07 -08:00
unsafe {
radio_upload(device, cont_flag)
2021-02-28 02:38:07 -08:00
}
}
/// List all supported radios.
2021-02-27 23:37:41 -08:00
pub fn list() {
2021-02-28 19:41:21 -08:00
println!("Supported radios:");
2021-02-27 23:16:01 -08:00
unsafe {
2021-02-28 19:41:21 -08:00
let mut ptr = get_radio_tab();
loop {
let ident_ptr = (*ptr).ident;
if ident_ptr.is_null() {
break;
}
let name_ptr = (*(*ptr).device).name;
let name = CStr::from_ptr(name_ptr).to_str().unwrap().to_string();
println!(" {}", name);
ptr = ptr.offset(1);
}
2021-02-27 23:16:01 -08:00
}
}
2021-02-28 01:19:31 -08:00
/// Check the configuration.
2021-02-28 12:23:30 -08:00
pub fn verify_config(device: *const radio_device_t) {
2021-02-28 01:31:29 -08:00
unsafe {
radio_verify_config(device);
2021-02-28 01:31:29 -08:00
}
}
/// Read firmware image from the binary file.
2021-02-28 12:23:30 -08:00
pub fn read_image(filename: &str) -> *const radio_device_t {
2021-02-28 01:19:31 -08:00
let filename = CString::new(filename.to_string()).unwrap();
unsafe {
radio_read_image(filename.as_ptr())
2021-02-28 01:19:31 -08:00
}
}
/// Save firmware image to the binary file.
2021-02-28 12:23:30 -08:00
pub fn save_image(device: *const radio_device_t, filename: &str) {
2021-02-28 01:19:31 -08:00
let filename = CString::new(filename.to_string()).unwrap();
unsafe {
radio_save_image(device, filename.as_ptr())
2021-02-28 01:19:31 -08:00
}
}
/// Read the configuration from text file, and modify the firmware.
2021-02-28 12:23:30 -08:00
pub fn parse_config(device: *const radio_device_t, filename: &str) {
2021-02-28 01:19:31 -08:00
let filename = CString::new(filename.to_string()).unwrap();
unsafe {
radio_parse_config(device, filename.as_ptr())
2021-02-28 01:19:31 -08:00
}
}
/// Print full information about the device configuration.
2021-02-28 12:23:30 -08:00
pub fn print_config(device: *const radio_device_t, filename: &str) {
2021-02-28 01:19:31 -08:00
let file = std::fs::File::create(filename).unwrap();
let fd = file.as_raw_fd();
let mode = CString::new("w").unwrap();
unsafe {
let file =libc::fdopen(fd, mode.as_ptr());
radio_print_config(device, file, 1);
2021-02-28 01:19:31 -08:00
libc::fclose(file);
}
}
2021-02-28 12:23:30 -08:00
pub fn print_config_to_stdout(device: *const radio_device_t) {
2021-02-28 01:19:31 -08:00
let mode = CString::new("w").unwrap();
unsafe {
let stdout = libc::fdopen(libc::STDOUT_FILENO, mode.as_ptr());
let verbosity = if libc::isatty(libc::STDOUT_FILENO) == 1 {
0
} else {
1
};
radio_print_config(device, stdout, verbosity);
2021-02-28 01:19:31 -08:00
}
}
/// Print generic information about the device.
2021-02-28 12:23:30 -08:00
pub fn print_version(device: *const radio_device_t) {
2021-02-28 01:19:31 -08:00
let mode = CString::new("w").unwrap();
unsafe {
radio_print_version(device, libc::fdopen(libc::STDOUT_FILENO, mode.as_ptr()));
2021-02-28 01:19:31 -08:00
}
}
/// Update CSV contacts database.
2021-02-28 12:23:30 -08:00
pub fn write_csv(device: *const radio_device_t, filename: &str) {
2021-02-28 01:19:31 -08:00
let filename = CString::new(filename.to_string()).unwrap();
unsafe {
radio_write_csv(device, filename.as_ptr());
2021-02-28 01:19:31 -08:00
}
}