1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
//     RustDuino : A generic HAL implementation for Arduino Boards in Rust
//     Copyright (C) 2021  Devansh Kumar Jha, Indian Institute of Technology Kanpur
//
//     This program is free software: you can redistribute it and/or modify
//     it under the terms of the GNU Affero General Public License as published
//     by the Free Software Foundation, either version 3 of the License, or
//     (at your option) any later version.
//
//     This program is distributed in the hope that it will be useful,
//     but WITHOUT ANY WARRANTY; without even the implied warranty of
//     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//     GNU Affero General Public License for more details.
//
//     You should have received a copy of the GNU Affero General Public License
//     along with this program.  If not, see <https://www.gnu.org/licenses/>

use crate::delay::delay_ms;
use crate::hal::pin::Pins;

use crate::sensors::*;
use bit_field::BitField;

/// Selection of method to generate number.
#[derive(Clone, Copy)]
pub enum Generator {
    Analog,
    Mpu,
}

/// Controls the implementation of Random Number Generators.
/// # Elements
/// * `pins` - structure containing array to control all pins of micro-controller.
/// * `mpu` - a static mutable reference to the pointer location to control MPU6050 gyroscope.
/// * `mode` - a `Generator` object, which stores the implementation method for random number generator.
#[repr(C, packed)]
pub struct RandomNumberGenerator {
    pins: Pins,
    mpu: &'static mut MPU6050<'static>,
    mode: Generator,
}

impl RandomNumberGenerator {
    /// Create a new structure object for Random Number Generation.
    /// This structure contains elements for both ways of number generation implemented.
    /// # Returns
    /// * `a struct of type Random Number Generator` - to be used for the struct's implementation.
    pub fn new(mode1: Generator) -> RandomNumberGenerator {
        RandomNumberGenerator {
            pins: Pins::new(),
            mpu: MPU6050::new(),
            mode: mode1,
        }
    }

    /// Generation of random number through random noise in environment
    /// detected by read through analog pins input.
    /// # Returns
    /// * `a u8` - a random number generated by random noise as detected by analog pins during reading.
    pub fn generate_by_analog(&mut self) -> u8 {
        match self.mode {
            Generator::Mpu => unreachable!(),
            Generator::Analog => (),
        }

        let mut bits1: u8 = unsafe { xor_rotate() };

        bits1 = xor_shift(bits1);

        let bits2: u8 = unsafe { xor_rotate() };

        bits1 = xor(bits1, bits2);

        let mut lbuf: u8 = unsafe { xor_rotate() };
        let mut rbuf: u8 = unsafe { xor_rotate() };
        let buf: u8 = xor(lbuf, rbuf);

        let mut bits3: u8 = 0;

        for i in 1..4 {
            let left: u8;
            let right: u8;

            delay_ms(100);
            left = self.pins.analog[0].read() as u8;

            delay_ms(100);
            right = self.pins.analog[0].read() as u8;

            bits3 = xor(bits3, rotate(left, i));
            bits3 = xor(bits3, rotate(right, 7 - i));

            for j in 1..8 {
                let lb = left.get_bit(j);
                let rb = right.get_bit(j);

                if lb != rb {
                    if buf % 2 == 0 {
                        lbuf = push_left(lbuf, lb as u8);
                    } else {
                        rbuf = push_right(rbuf, lb as u8);
                    }
                }
            }
        }

        bits1 = xor_shift(bits1);

        bits1 = xor(bits1, bits3);

        xor(bits1, xor(lbuf, rbuf))
    }

    /// Generation of random number through random noise in environment
    /// detected through the MPU6050 sensor in the orthonormal set of axes.
    /// # Returns
    /// * `a u8` - a random number generated by multiple seeding within numbers generated by MPU6050 sensor.
    pub fn generate_by_mpu(&mut self) -> u8 {
        match self.mode {
            Generator::Analog => unreachable!(),
            Generator::Mpu => (),
        }

        let (a, b, c, d, e, f) = generate_mpu();

        let a1 = (a & 0x3) << 6;
        let a2 = (d & 0x3) << 6;
        let mut bits1 = xor(a1, xor(c << 4, xor(b << 2, xor(a, c >> 2))));
        let bits2 = xor(a2, xor(f << 4, xor(e << 2, xor(d, f >> 2))));

        bits1 = xor_shift(bits1);

        bits1 = xor(bits1, bits2);

        bits1
    }
}

/// Rotate the unsigned integer of 8 bits by n towards left
/// and surrounding back with the overflowing bits.
/// # Arguments
/// * `b` - a u8, the number whose bits will be rotated.
/// * `n` - a u8, by how many places bits are to be rotated.
/// # Returns
/// * `a u8` - the bit-shifted number.
pub fn rotate(b: u8, n: u8) -> u8 {
    (b >> n) | (b << (8 - n))
}

/// Get the bitwise XOR (exclusive OR) of two 8 bits unsigned integers.
/// # Arguments
/// * `a` - a u8, first unsigned integer.
/// * `b` - a u8, second unsigned integer.
/// # Returns
/// * `a u8` - bitwise XOR.
pub fn xor(a: u8, b: u8) -> u8 {
    (a | b) - (a & b)
}

/// XOR Shift for stability in number generation.
/// It implements one round of XORShift PRNG algorithm for statistical stability.
/// # Arguments
/// * `a` - a u8, the number whose bits will be shifted.
/// # Returns
/// * `a u8` - the bit-shifted number.
pub fn xor_shift(a: u8) -> u8 {
    let mut ans: u8 = 0;

    ans = xor(ans, a);
    ans = xor(ans, a >> 3);
    ans = xor(ans, a << 5);
    ans = xor(ans, a >> 4);

    ans
}

/// Generate XOR Rotation number.
/// # Returns
/// * `a u8` - A random number generated by various XOR's on sample generated through analog read.
pub unsafe fn xor_rotate() -> u8 {
    let mut bits1: u8 = 0;
    let mut obj = RandomNumberGenerator::new(Generator::Analog);

    for i in 1..8 {
        let a: u8 = obj.pins.analog[0].read() as u8;
        bits1 = xor(bits1, rotate(a, i));
        delay_ms(20);
    }

    bits1
}

/// Push the required bit with left bias.
/// # Arguments
/// * `val`    - a u8, the number to whom the bits are to be added.
/// * `change` - a u8, the extent of rotation before XOR of the bits of `val`.
/// # Returns
/// * `a u8` - The bit changed value of `val`.
pub fn push_left(val: u8, change: u8) -> u8 {
    xor(val << 1, xor(change, val))
}

/// Push the required bit with right bias.
/// # Arguments
/// * `val`    - a u8, the number to whom the bits are to be added.
/// * `change` - a u8, the extent of rotation before XOR of the bits of `val`.
/// # Returns
/// * `a u8` - The bit changed value of `val`.
pub fn push_right(val: u8, change: u8) -> u8 {
    xor(val >> 1, xor(change << 7, val))
}

/// Function to generate tuple containing u8 numbers
/// accordingly through MPU6050 Gyroscopic Sensor.
/// # Returns
/// * `a tuple of 6 u8's` - The x,y,z axes accelerations and gyroscopic detections by MPU6050 sensor respectively.
pub fn generate_mpu() -> (u8, u8, u8, u8, u8, u8) {
    let obj = RandomNumberGenerator::new(Generator::Mpu);

    obj.mpu
        .begin(MPUdpsT::MPU6050Scale250DPS, MPURangeT::MPU6050Range2G);

    obj.mpu.read_gyro();
    delay_ms(1000);

    obj.mpu.read_accel();
    delay_ms(1000);

    let d: u8 = obj.mpu.gyro_output[0] as u8;
    let e: u8 = obj.mpu.gyro_output[1] as u8;
    let f: u8 = obj.mpu.gyro_output[2] as u8;
    let a: u8 = obj.mpu.accel_output[0] as u8;
    let b: u8 = obj.mpu.accel_output[1] as u8;
    let c: u8 = obj.mpu.accel_output[2] as u8;
    (a, b, c, d, e, f)
}