-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Hamming(8,4) coding and basic, primitive, to-be-improved ASK mo…
…dulation, plus some primitive, also to-be-improved tests for them.
- Loading branch information
Showing
6 changed files
with
192 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
//WARNING! This hasn't been fully tested - I'm just putting it here so that we've got something to work with It should... mostly work. | ||
//OTHER WARNING! My *dheubhokhersos* didn't realize we're using the alloc crate, so this uses stock standard arrays. Prepare for stack overflows until I fix it. | ||
use libm::cosf; | ||
|
||
pub struct ASK<const NUM_BYTES: usize, const FINAL_BYTES: usize>{ | ||
frequency: f32, | ||
sample_rate: f32, | ||
samples_per_bit: usize, | ||
} | ||
|
||
impl<const NUM_BYTES: usize, const FINAL_BYTES: usize> ASK<NUM_BYTES, FINAL_BYTES>{ | ||
pub fn new(freq: f32, sample_rate: f32, samples_per_bit: usize) -> Self{ | ||
return ASK { frequency: (freq), sample_rate:(sample_rate), samples_per_bit: (samples_per_bit) } | ||
} | ||
pub fn run (self, data: [u8; NUM_BYTES], time: f32) -> [f32; FINAL_BYTES]{ | ||
//println!("Does this work???"); | ||
let pi = core::f32::consts::PI; | ||
let mut index: usize = 0; | ||
let timestep = 1.0/self.sample_rate; | ||
let mut time_offset = 0.0; | ||
let mut signal = [0.0f32; FINAL_BYTES]; | ||
for mut current_byte in data{ | ||
//println!("Working with byte {current_byte}"); | ||
let bit_one = current_byte&0x01; current_byte >>= 1; | ||
let bit_two = current_byte&0x01; current_byte >>= 1; | ||
let bit_three = current_byte&0x01; current_byte >>= 1; | ||
let bit_four = current_byte&0x01; current_byte >>= 1; | ||
let bit_five = current_byte&0x01; current_byte >>= 1; | ||
let bit_six = current_byte&0x01; current_byte >>= 1; | ||
let bit_seven = current_byte&0x01; current_byte >>= 1; | ||
let bit_eight = current_byte; | ||
let bit_array = [bit_one, bit_two, bit_three, bit_four, bit_five, bit_six, bit_seven, bit_eight]; | ||
for bit in bit_array{ | ||
//println!("Bit here is {bit}"); | ||
let mut bit_type = 1.0; | ||
if bit==0{bit_type = 0.1;} | ||
for _ in 0..self.samples_per_bit{ | ||
let current_radian = 2.0*pi*((time+time_offset)*self.frequency); | ||
//println!("Current radian is {current_radian}"); | ||
signal[index] = cosf(current_radian)*bit_type; | ||
//let dummy = cosf(current_radian)*bit_type; | ||
//println!("Writing {dummy} to {index}"); | ||
index+=1; | ||
time_offset+=timestep; | ||
} | ||
} | ||
} | ||
return signal; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
pub mod ask; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
|
||
//Takes one 8-bit byte and returns two Hamming(8,4)-coded SECDED bytes, at a rate of about 60MB/s. | ||
pub fn hamming_encode(data: u8) -> (u8, u8){ | ||
let mut data1 = data & 0xF0; | ||
let mut data2 = data << 4; | ||
//println!("Initial: Data 1 {data1}, data 2 {data2}"); | ||
data1 |= (data1&0x10) >> 1; data1 &= 0xEF; | ||
data2 |= (data2&0x10) >> 1; data2 &= 0xEF; | ||
//println!("Bits moved: Data 1 {data1}, data 2 {data2}"); | ||
let p1 = (data1 >> 3)&0x01 ^ (data1 >> 5)&0x01 ^ (data1 >> 7)&0x01; //Technically there's supposed to be another bit XOR'd in for each of these, but since that ends up being the p-bit itself it'll always be 0. | ||
let p2 = (data1 >> 3)&0x01 ^ (data1 >> 6)&0x01 ^ (data1 >> 7)&0x01; | ||
let p3 = (data1 >> 5)&0x01 ^ (data1 >> 6)&0x01 ^ (data1 >> 7)&0x01; | ||
data1 |= p1 << 1; | ||
data1 |= p2 << 2; | ||
data1 |= p3 << 4; | ||
let parity = (data1 >> 1)&0x01 ^ (data1 >> 2)&0x01 ^ (data1 >> 3)&0x01 ^ (data1 >> 4)&0x01 ^ (data1 >> 5)&0x01 ^ (data1 >> 6)&0x01 ^ (data1 >> 7)&0x01; | ||
data1 |= parity; | ||
let p1 = (data2 >> 3)&0x01 ^ (data2 >> 5)&0x01 ^ (data2 >> 7)&0x01; | ||
let p2 = (data2 >> 3)&0x01 ^ (data2 >> 6)&0x01 ^ (data2 >> 7)&0x01; | ||
let p3 = (data2 >> 5)&0x01 ^ (data2 >> 6)&0x01 ^ (data2 >> 7)&0x01; | ||
/*let x1 = (data2 >> 5)&0x01; | ||
let x2 = (data2 >> 6)&0x01; | ||
let x3 = (data2 >> 7)&0x01; | ||
println!("From {x1}, {x2}, and {x3} comes {p3}.");*/ | ||
data2 |= p1 << 1; | ||
data2 |= p2 << 2; | ||
data2 |= p3 << 4; | ||
let parity = (data2 >> 1)&0x01 ^ (data2 >> 2)&0x01 ^ (data2 >> 3)&0x01 ^ (data2 >> 4)&0x01 ^ (data2 >> 5)&0x01 ^ (data2 >> 6)&0x01 ^ (data2 >> 7)&0x01; | ||
data2 |= parity; | ||
return (data1, data2); | ||
} | ||
|
||
//Takes two 8-bit Hamming(8,4)-coded bytes, and returns a at a rate of about 60MB/s. | ||
pub fn hamming_decode(data: (u8, u8)) -> (u8, bool, bool){ //What a monstrous function - this is what happens when you go for speed over efficiency. | ||
let data1 = data.0; | ||
let data2 = data.1; | ||
let mut returned_byte: u8 = 0; | ||
let mut error1 = true; | ||
let mut error2 = true; | ||
let parity_found: bool = (data1&0x01) == 0x01; //I'm making an assumption that storing these as booleans now will save time later when comparing them. | ||
let parity_expected: bool = ((data1 >> 1)&0x01 ^ (data1 >> 2)&0x01 ^ (data1 >> 3)&0x01 ^ (data1 >> 4)&0x01 ^ (data1 >> 5)&0x01 ^ (data1 >> 6)&0x01 ^ (data1 >> 7)&0x01) == 0x01; | ||
//if parity_expected!=parity_found{println!("WRONG PARITY WITH VALUE {data1}")} | ||
let p1_found: bool = ((data1 >> 1)&0x01) == 0x01; | ||
let p2_found: bool = ((data1 >> 2)&0x01) == 0x01; | ||
let mut d1_found: bool = ((data1 >> 3)&0x01) == 0x01; | ||
let p3_found: bool = ((data1 >> 4)&0x01) == 0x01; | ||
let mut d2_found: bool = ((data1 >> 5)&0x01) == 0x01; | ||
let mut d3_found: bool = ((data1 >> 6)&0x01) == 0x01; | ||
let mut d4_found: bool = ((data1 >> 7)&0x01) == 0x01; | ||
//println!("Data found: D4 {d4_found} D3 {d3_found} D2 {d2_found} D1 {d1_found} P3 {p3_found} P2 {p2_found} P1 {p1_found} PP {parity_found}"); | ||
let group1_valid: bool = !(d4_found ^ d2_found ^ d1_found ^ p1_found); | ||
let group2_valid: bool = !(d4_found ^ d3_found ^ d1_found ^ p2_found); | ||
let group3_valid: bool = !(d4_found ^ d3_found ^ d2_found ^ p3_found); | ||
//println!("Groups found in byte 1: G1 {group1_valid} G2 {group2_valid} G3 {group3_valid}"); | ||
//if !group3_valid{ println!("Group 3 invalid with value {data1}"); } | ||
match(group1_valid, group2_valid, group3_valid){ | ||
(false, false, false) => d4_found = !d4_found, | ||
(true, false, false) => d3_found = !d3_found, | ||
(false, true, false) => d2_found = !d2_found, | ||
(false, false, true) => d1_found = !d1_found, | ||
_ => error1 = group1_valid&group2_valid&group3_valid | ||
} error1 = (parity_expected==parity_found)^error1; //If total parity was wrong but there's no hamming error, we have a double-bit error and need the byte to be retransmitted! | ||
returned_byte += ((d4_found as u8) << 7)+((d3_found as u8) << 6)+((d2_found as u8) << 5)+((d1_found as u8) << 4); | ||
let parity_found: bool = (data2&0x01) == 0x01; //I'm making an assumption that storing these as booleans now will save time later when comparing them. | ||
let parity_expected: bool = ((data2 >> 1)&0x01 ^ (data2 >> 2)&0x01 ^ (data2 >> 3)&0x01 ^ (data2 >> 4)&0x01 ^ (data2 >> 5)&0x01 ^ (data2 >> 6)&0x01 ^ (data2 >> 7)&0x01) == 0x01; | ||
//if parity_expected!=parity_found{println!("WRONG PARITY WITH VALUE {data2}")} | ||
let p1_found: bool = ((data2 >> 1)&0x01) == 0x01; | ||
let p2_found: bool = ((data2 >> 2)&0x01) == 0x01; | ||
let mut d1_found: bool = ((data2 >> 3)&0x01) == 0x01; | ||
let p3_found: bool = ((data2 >> 4)&0x01) == 0x01; | ||
let mut d2_found: bool = ((data2 >> 5)&0x01) == 0x01; | ||
let mut d3_found: bool = ((data2 >> 6)&0x01) == 0x01; | ||
let mut d4_found: bool = ((data2 >> 7)&0x01) == 0x01; | ||
//println!("Data found: D4 {d4_found} D3 {d3_found} D2 {d2_found} D1 {d1_found} P3 {p3_found} P2 {p2_found} P1 {p1_found} PP {parity_found}"); | ||
let group1_valid: bool = !(d4_found ^ d2_found ^ d1_found ^ p1_found); | ||
let group2_valid: bool = !(d4_found ^ d3_found ^ d1_found ^ p2_found); | ||
let group3_valid: bool = !(d4_found ^ d3_found ^ d2_found ^ p3_found); | ||
//println!("Groups found in byte 2: G1 {group1_valid} G2 {group2_valid} G3 {group3_valid}"); | ||
//if !group3_valid{ println!("Group 3 invalid with value {data2}"); } | ||
match(group1_valid, group2_valid, group3_valid){ | ||
(false, false, false) => d4_found = !d4_found, | ||
(true, false, false) => d3_found = !d3_found, | ||
(false, true, false) => d2_found = !d2_found, | ||
(false, false, true) => d1_found = !d1_found, | ||
_ => error2 = group1_valid&group2_valid&group3_valid | ||
} error2 = (parity_expected==parity_found)^error2; | ||
returned_byte += ((d4_found as u8) << 3)+((d3_found as u8) << 2)+((d2_found as u8) << 1)+((d1_found as u8)); | ||
return (returned_byte, error1, error2); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
#[cfg(feature = "bladerf")] | ||
pub mod bladerf; | ||
pub mod bladerf; | ||
pub mod hamming84; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
// Test Triangle Window | ||
use std::time::SystemTime; | ||
use superdsp::radios::hamming84::{self, hamming_decode}; | ||
|
||
|
||
#[test] | ||
pub fn encode_decode() { | ||
for i in 0..=255{ | ||
println!("Encoding {i}"); | ||
let rval = hamming84::hamming_encode(i); | ||
let n1 = rval.0; | ||
let n2 = rval.1; | ||
//println!("{i} turns into {n1},{n2}."); | ||
//println!("Decoding {i}"); | ||
let rval = hamming_decode((n1, n2)); | ||
//println!("{n1} and {n2} turn into {x1} with the first {v1} and second {v2}."); | ||
assert_eq!((i,false,false), rval); | ||
} | ||
} | ||
#[test] | ||
pub fn speed_test() { | ||
let start = SystemTime::now(); | ||
let mut big_i: u64 = 0; | ||
while big_i < (10_u64.pow(6)){ | ||
let i: u8 = (big_i%255) as u8; | ||
let r = hamming84::hamming_encode(i); | ||
hamming84::hamming_decode(r); | ||
big_i += 1; | ||
} | ||
match SystemTime::now().duration_since(start) { | ||
Ok(n) => println!("Process began {} milliseconds ago!", n.as_millis()), | ||
Err(_) => panic!("System traveled back in time!"), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
// Test this - test doesn't work properly, but good to have some output anyway | ||
|
||
use superdsp::modulation::ask; | ||
#[test] | ||
pub fn great_test() { | ||
let mut data_bytes: [u8; 50] = [0; 50]; | ||
for i in 0..data_bytes.len()-1{ | ||
data_bytes[i] = (i%(255 as usize)) as u8; | ||
} | ||
//FINAL_BYTES should be at least 8*data_bytes.len()*samples_exported_per_bit | ||
let ask_example = ask::ASK::<50, 80000>::new(10000.0, 100000.0, 200); | ||
let result = ask_example.run(data_bytes, 0.0); | ||
for f in result{ | ||
println!("{f}"); | ||
} | ||
} |