From e8099fc681be18e33330af769a98719f6bfdc042 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Sun, 28 Feb 2021 12:23:30 -0800 Subject: [PATCH] Use bindgen for rust bindings --- Cargo.toml | 3 +++ build.rs | 32 ++++++++++++++++++++++++++++++++ radio.h | 2 ++ src/lib.rs | 5 +++++ src/radio.rs | 45 ++++++++++++++++++++++----------------------- 5 files changed, 64 insertions(+), 23 deletions(-) create mode 100644 build.rs diff --git a/Cargo.toml b/Cargo.toml index d809cba..5e9e1aa 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,3 +12,6 @@ crate-type = ["staticlib"] [dependencies] libc = "0.2" getopts = "0.2" + +[build-dependencies] +bindgen = "0.53.1" diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..bd0b5ba --- /dev/null +++ b/build.rs @@ -0,0 +1,32 @@ + +extern crate bindgen; + +use std::env; +use std::path::PathBuf; + +fn main() { + // Tell cargo to invalidate the built crate whenever the wrapper changes + println!("cargo:rerun-if-changed=radio.h"); + + // The bindgen::Builder is the main entry point + // to bindgen, and lets you build up options for + // the resulting bindings. + let bindings = bindgen::Builder::default() + // The input header we would like to generate + // bindings for. + .header("radio.h") + // Tell cargo to invalidate the built crate whenever any of the + // included header files changed. + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .whitelist_type("radio_device_t") + // Finish the builder and generate the bindings. + .generate() + // Unwrap the Result and panic on failure. + .expect("Unable to generate bindings for radio.h"); + + // Write the bindings to the $OUT_DIR/bindings.rs file. + let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); +} diff --git a/radio.h b/radio.h index f170a60..aea93a2 100644 --- a/radio.h +++ b/radio.h @@ -29,6 +29,8 @@ // // Check for compatible radio model. // +#include + int radio_is_compatible(const char *ident); // diff --git a/src/lib.rs b/src/lib.rs index 8f5a348..413b9bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,12 @@ +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + use libc::{c_int, c_char}; use getopts::Options; use std::process::exit; + mod radio; const COPYRIGHT: &'static str = "Copyright (C) 2018 Serge Vakulenko KK6ABQ"; diff --git a/src/radio.rs b/src/radio.rs index d49bdc0..bc06713 100644 --- a/src/radio.rs +++ b/src/radio.rs @@ -2,22 +2,21 @@ use std::ffi::CString; use libc::{c_char, c_int}; use std::os::unix::io::AsRawFd; -#[repr(C)] -pub struct RadioDeviceT { _private: [u8; 0] } +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); extern { - fn radio_connect() -> *const RadioDeviceT; + fn radio_connect() -> *const radio_device_t; - fn radio_download(device: *const RadioDeviceT); - fn radio_upload(device: *const RadioDeviceT, cont_flag: c_int); + fn radio_download(device: *const radio_device_t); + fn radio_upload(device: *const radio_device_t, cont_flag: c_int); fn radio_list_c(); - fn radio_verify_config(device: *const RadioDeviceT); - fn radio_print_version(device: *const RadioDeviceT, stdout: *const libc::FILE); - fn radio_print_config(device: *const RadioDeviceT, file: *const libc::FILE, verbose: c_int); - fn radio_read_image(filename: *const c_char) -> *const RadioDeviceT; - fn radio_save_image(device: *const RadioDeviceT, filename: *const c_char); - fn radio_parse_config(device: *const RadioDeviceT, filename: *const c_char); - fn radio_write_csv(device: *const RadioDeviceT, filename: *const c_char); + 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); fn dfu_reboot(); fn dfu_close(); @@ -27,7 +26,7 @@ extern { /// Connect to the radio via the serial port. /// Identify the type of device. -pub fn connect() -> *const RadioDeviceT { +pub fn connect() -> *const radio_device_t { unsafe { radio_connect() } @@ -47,14 +46,14 @@ pub fn disconnect() { } /// Read firmware image from the device -pub fn download(device: *const RadioDeviceT) { +pub fn download(device: *const radio_device_t) { unsafe { radio_download(device) } } /// Write firmware image to the device. -pub fn upload(device: *const RadioDeviceT, cont_flag: c_int) { +pub fn upload(device: *const radio_device_t, cont_flag: c_int) { unsafe { radio_upload(device, cont_flag) } @@ -69,14 +68,14 @@ pub fn list() { } /// Check the configuration. -pub fn verify_config(device: *const RadioDeviceT) { +pub fn verify_config(device: *const radio_device_t) { unsafe { radio_verify_config(device); } } /// Read firmware image from the binary file. -pub fn read_image(filename: &str) -> *const RadioDeviceT { +pub fn read_image(filename: &str) -> *const radio_device_t { let filename = CString::new(filename.to_string()).unwrap(); unsafe { radio_read_image(filename.as_ptr()) @@ -84,7 +83,7 @@ pub fn read_image(filename: &str) -> *const RadioDeviceT { } /// Save firmware image to the binary file. -pub fn save_image(device: *const RadioDeviceT, filename: &str) { +pub fn save_image(device: *const radio_device_t, filename: &str) { let filename = CString::new(filename.to_string()).unwrap(); unsafe { radio_save_image(device, filename.as_ptr()) @@ -92,7 +91,7 @@ pub fn save_image(device: *const RadioDeviceT, filename: &str) { } /// Read the configuration from text file, and modify the firmware. -pub fn parse_config(device: *const RadioDeviceT, filename: &str) { +pub fn parse_config(device: *const radio_device_t, filename: &str) { let filename = CString::new(filename.to_string()).unwrap(); unsafe { radio_parse_config(device, filename.as_ptr()) @@ -100,7 +99,7 @@ pub fn parse_config(device: *const RadioDeviceT, filename: &str) { } /// Print full information about the device configuration. -pub fn print_config(device: *const RadioDeviceT, filename: &str) { +pub fn print_config(device: *const radio_device_t, filename: &str) { let file = std::fs::File::create(filename).unwrap(); let fd = file.as_raw_fd(); let mode = CString::new("w").unwrap(); @@ -111,7 +110,7 @@ pub fn print_config(device: *const RadioDeviceT, filename: &str) { } } -pub fn print_config_to_stdout(device: *const RadioDeviceT) { +pub fn print_config_to_stdout(device: *const radio_device_t) { let mode = CString::new("w").unwrap(); unsafe { let stdout = libc::fdopen(libc::STDOUT_FILENO, mode.as_ptr()); @@ -125,7 +124,7 @@ pub fn print_config_to_stdout(device: *const RadioDeviceT) { } /// Print generic information about the device. -pub fn print_version(device: *const RadioDeviceT) { +pub fn print_version(device: *const radio_device_t) { let mode = CString::new("w").unwrap(); unsafe { radio_print_version(device, libc::fdopen(libc::STDOUT_FILENO, mode.as_ptr())); @@ -133,7 +132,7 @@ pub fn print_version(device: *const RadioDeviceT) { } /// Update CSV contacts database. -pub fn write_csv(device: *const RadioDeviceT, filename: &str) { +pub fn write_csv(device: *const radio_device_t, filename: &str) { let filename = CString::new(filename.to_string()).unwrap(); unsafe { radio_write_csv(device, filename.as_ptr());