Skip to content

Commit

Permalink
Added Hamming(8,4) coding and basic, primitive, to-be-improved ASK mo…
Browse files Browse the repository at this point in the history
…dulation, plus some primitive, also to-be-improved tests for them.
  • Loading branch information
kzhws committed Sep 23, 2024
1 parent 7f1ceac commit bb7f0b2
Show file tree
Hide file tree
Showing 6 changed files with 192 additions and 1 deletion.
50 changes: 50 additions & 0 deletions src/modulation/ask.rs
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;
}
}
1 change: 1 addition & 0 deletions src/modulation/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod ask;
89 changes: 89 additions & 0 deletions src/radios/hamming84.rs
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);
}
3 changes: 2 additions & 1 deletion src/radios/mod.rs
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;
34 changes: 34 additions & 0 deletions tests/hammingcode.rs
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!"),
}
}
16 changes: 16 additions & 0 deletions tests/tester_dummy.rs
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}");
}
}

0 comments on commit bb7f0b2

Please sign in to comment.