From 3f4b18368bbde44c6028abf45141e6fdba526c48 Mon Sep 17 00:00:00 2001 From: Greg Shuflin Date: Wed, 3 Mar 2021 00:49:57 -0800 Subject: [PATCH] parse_config port to rust --- radio.c | 106 --------------------------------------------------- src/radio.rs | 97 +++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 91 insertions(+), 112 deletions(-) diff --git a/radio.c b/radio.c index 68dddf1..7a1f2e5 100644 --- a/radio.c +++ b/radio.c @@ -35,109 +35,3 @@ #include "radio.h" #include "util.h" -/* -typedef struct { char* ident; radio_device_t* device; } radio_tab_t; - -static radio_tab_t radio_tab[] = { - { "DR780", &radio_md380 }, // TYT MD-380, Retevis RT3, RT8 - { "MD390", &radio_md390 }, // TYT MD-390 - { "MD-UV380", &radio_uv380 }, // TYT MD-UV380 - { "MD-UV390", &radio_uv390 }, // TYT MD-UV390, Retevis RT3S - { "2017", &radio_md2017 }, // TYT MD-2017, Retevis RT82 - { "MD9600", &radio_md9600 }, // TYT MD-9600 - { "BF-5R", &radio_rd5r }, // Baofeng RD-5R, TD-5R - { "1801", &radio_dm1801 }, // Baofeng DM-1801 - { "DM-1701", &radio_rt84 }, // Baofeng DM-1701, Retevis RT84 - { "MD-760P", &radio_gd77 }, // Radioddity GD-77, version 3.1.1 and later - { "D868UVE", &radio_d868uv }, // Anytone AT-D868UV - { "D878UV", &radio_d878uv }, // Anytone AT-D878UV - { "D6X2UV", &radio_dmr6x2 }, // BTECH DMR-6x2 - { "ZD3688", &radio_d900 }, // Zastone D900 - { "TP660", &radio_dp880 }, // Zastone DP880 - { "ZN><:", &radio_rt27d }, // Radtel RT-27D - { 0, 0 } -}; -*/ - -// -// Read the configuration from text file, and modify the firmware. -// -void radio_parse_config(radio_device_t* device, const char *filename) -{ - FILE *conf; - char line [256], *p, *v; - int table_id = 0, table_dirty = 0; - - fprintf(stderr, "Read configuration from file '%s'.\n", filename); - conf = fopen(filename, "r"); - if (! conf) { - perror(filename); - exit(-1); - } - - device->channel_count = 0; - while (fgets(line, sizeof(line), conf)) { - line[sizeof(line)-1] = 0; - - // Strip comments. - v = strchr(line, '#'); - if (v) - *v = 0; - - // Strip trailing spaces and newline. - v = line + strlen(line) - 1; - while (v >= line && (*v=='\n' || *v=='\r' || *v==' ' || *v=='\t')) - *v-- = 0; - - // Ignore comments and empty lines. - p = line; - if (*p == 0) - continue; - - if (*p != ' ') { - // Table finished. - table_id = 0; - - // Find the value. - v = strchr(p, ':'); - if (! v) { - // Table header: get table type. - table_id = device->parse_header(device, p); - if (! table_id) { -badline: fprintf(stderr, "Invalid line: '%s'\n", line); - exit(-1); - } - table_dirty = 0; - continue; - } - - // Parameter. - *v++ = 0; - - // Skip spaces. - while (*v == ' ' || *v == '\t') - v++; - - device->parse_parameter(device, p, v); - - } else { - // Table row or comment. - // Skip spaces. - // Ignore comments and empty lines. - while (*p == ' ' || *p == '\t') - p++; - if (*p == '#' || *p == 0) - continue; - if (! table_id) { - goto badline; - } - - if (! device->parse_row(device, table_id, ! table_dirty, p)) { - goto badline; - } - table_dirty = 1; - } - } - fclose(conf); - device->update_timestamp(device); -} diff --git a/src/radio.rs b/src/radio.rs index 6bce35c..33a9798 100644 --- a/src/radio.rs +++ b/src/radio.rs @@ -37,8 +37,6 @@ pub static mut radio_mem: [u8; 1024*1024*2] = [0; 1024*1024*2]; extern { - fn radio_parse_config(device: *const radio_device_t, filename: *const c_char); - fn dfu_init(vid: c_uint, pid: c_uint) -> *const c_char; fn dfu_reboot(); fn dfu_close(); @@ -311,12 +309,99 @@ pub fn save_image(radio: &Radio, filename: &str) { } } -/// Read the configuration from text file, and modify the firmware. +/// Read the configuration from a text file, and modify the firmware. pub fn parse_config(radio: &Radio, filename: &str) { - let device = radio.ptr; - let filename = CString::new(filename.to_string()).unwrap(); + use std::io::{BufRead, BufReader}; + + let device = radio.ptr as *mut radio_device_t; + + let parse_header_fn = unsafe { + (*device).parse_header.unwrap() + }; + + let parse_parameter_fn = unsafe { + (*device).parse_parameter.unwrap() + }; + + let parse_row_fn = unsafe { + (*device).parse_row.unwrap() + }; + + let update_timestamp_fn = unsafe { + (*device).update_timestamp.unwrap() + }; + + eprintln!("Read configuration from file '{}'.", filename); + let file = std::fs::File::open(filename).unwrap(); + let file = BufReader::new(file); + + let mut table_id: c_int = 0; + let mut table_dirty: c_int = 0; + + for line in file.lines() { + let line = line.unwrap(); + // Strip text after comment marker '#' + let trimmed_line = line + .split('#') + .next() + .unwrap() + .trim_end(); + + // Skip comments and blank lines + if trimmed_line.is_empty() { + continue; + } + + // Table row + if trimmed_line.chars().nth(0) == Some(' ') { + if table_id == 0 { + eprintln!("Invalid line: '{}'", line); + exit(-1); + } + + let trimmed_more = CString::new(trimmed_line.trim_start()).unwrap(); + let ptr = trimmed_more.as_ptr() as *mut c_char; + let output = unsafe { parse_row_fn(device, table_id, !table_dirty, ptr) }; + if output == 0 { + eprintln!("Invalid line: '{}'", line); + exit(-1); + } + table_dirty = 1; + } else { + // Table finished + table_id = 0; + + // Find the value + if let Some(colon_byte_idx) = line.find(':') { + + let (param_str, value_str) = line.split_at(colon_byte_idx); + let stripped_value_str = value_str.strip_prefix(':').unwrap(); + + let param_c_str = CString::new(param_str.trim_start()).unwrap(); + let param_ptr = param_c_str.as_ptr() as *mut c_char; + + let value_c_str = CString::new(stripped_value_str.trim_start()).unwrap(); + let value_ptr = value_c_str.as_ptr() as *mut c_char; + + unsafe { + parse_parameter_fn(device, param_ptr, value_ptr); + } + } else { // Table header + let c_line = CString::new(trimmed_line).unwrap(); + let ptr = c_line.as_ptr() as *mut c_char; + table_id = unsafe { parse_header_fn(device, ptr) }; + + if table_id == 0 { + eprintln!("Invalid line: '{}'", line); + exit(-1); + } + table_dirty = 0; + } + } + } + unsafe { - radio_parse_config(device, filename.as_ptr()) + update_timestamp_fn(device); } }