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
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
use super::{Buffer, MAX_BIT_RATE};
use utils::{as_bool, as_u16, as_u32};

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ChipStatus {
    pub is_bus_release_pending: bool,
    pub bus_owner: BusOwner,
    pub password_attempt_count: u8,
    pub is_password_guessed: bool,
}

impl ChipStatus {
    pub fn from_buffer(buf: &Buffer) -> Result<ChipStatus, String> {
        Ok(ChipStatus {
            is_bus_release_pending: !as_bool(buf[2])
                .map_err(|v| format!("Invalid is_bus_release_pending value: {:02x}", v))?,
            bus_owner: BusOwner::from_u8(buf[3])
                .map_err(|v| format!("Invalid bus_owner value: {:02x}", v))?,
            password_attempt_count: buf[4],
            is_password_guessed: as_bool(buf[5])
                .map_err(|v| format!("Invalid is_password_guessed value: {:02x}", v))?,
        })
    }
}

bitflags!(
    pub struct ChipSelect: u16 {
        const CS0 = 0b000000001;
        const CS1 = 0b000000010;
        const CS2 = 0b000000100;
        const CS3 = 0b000001000;
        const CS4 = 0b000010000;
        const CS5 = 0b000100000;
        const CS6 = 0b001000000;
        const CS7 = 0b010000000;
        const CS8 = 0b100000000;
        const ALL_HIGH = 0b111111111;
        const ALL_LOW = 0b000000000;
    }
);

bitflags!(
    pub struct GpioValue: u16 {
        const GP0 = 0b000000001;
        const GP1 = 0b000000010;
        const GP2 = 0b000000100;
        const GP3 = 0b000001000;
        const GP4 = 0b000010000;
        const GP5 = 0b000100000;
        const GP6 = 0b001000000;
        const GP7 = 0b010000000;
        const GP8 = 0b100000000;
        const ALL_HIGH = 0b111111111;
        const ALL_LOW = 0b000000000;
    }
);

impl Default for GpioValue {
    fn default() -> GpioValue {
        GpioValue::ALL_HIGH
    }
}

bitflags!(
    pub struct GpioDirection: u16 {
        const GP0DIR = 0b000000001;
        const GP1DIR = 0b000000010;
        const GP2DIR = 0b000000100;
        const GP3DIR = 0b000001000;
        const GP4DIR = 0b000010000;
        const GP5DIR = 0b000100000;
        const GP6DIR = 0b001000000;
        const GP7DIR = 0b010000000;
        const GP8DIR = 0b100000000;
        const ALL_INPUTS = 0b111111111;
        const ALL_OUTPUTS = 0b000000000;
    }
);

impl Default for GpioDirection {
    fn default() -> GpioDirection {
        GpioDirection::ALL_INPUTS
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum PinMode {
    Gpio = 0x00,
    ChipSelect = 0x01,
    Dedicated = 0x02,
}

impl PinMode {
    fn from_u8(v: u8) -> Result<PinMode, u8> {
        match v {
            0x00 => Ok(PinMode::Gpio),
            0x01 => Ok(PinMode::ChipSelect),
            0x02 => Ok(PinMode::Dedicated),
            _ => Err(v),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum BusOwner {
    None,
    UsbBridge,
    ExternalMaster,
}

impl BusOwner {
    fn from_u8(v: u8) -> Result<BusOwner, u8> {
        match v {
            0x00 => Ok(BusOwner::None),
            0x01 => Ok(BusOwner::UsbBridge),
            0x02 => Ok(BusOwner::ExternalMaster),
            _ => Err(v),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct UsbParameters {
    vid: u16,
    pid: u16,
    power_option: UsbPowerOption,
    remote_wakeup_capable: bool,
    requested_current: u8,
}

impl Default for UsbParameters {
    fn default() -> UsbParameters {
        UsbParameters {
            vid: 0x04d8,
            pid: 0x00de,
            power_option: UsbPowerOption::HostPowered,
            remote_wakeup_capable: false,
            requested_current: 50,
        }
    }
}

impl UsbParameters {
    pub fn from_buffer(buf: &Buffer) -> Result<UsbParameters, String> {
        Ok(UsbParameters {
            vid: as_u16(buf[12], buf[13]),
            pid: as_u16(buf[14], buf[15]),
            power_option: UsbPowerOption::from_u8(buf[29] >> 6)
                .map_err(|v| format!("Invalid power_option value: {:02x}", v))?,
            remote_wakeup_capable: buf[29] & 0b100000 != 0,
            requested_current: buf[30],
        })
    }
    pub fn write_to_buffer(&self, buf: &mut Buffer) {
        buf[4] = self.vid as u8;
        buf[5] = (self.vid >> 8) as u8;
        buf[6] = self.pid as u8;
        buf[7] = (self.pid >> 8) as u8;
        buf[8] = ((self.power_option as u8) << 6) | (if self.remote_wakeup_capable {
            0b100000
        } else {
            0
        });
        buf[9] = self.requested_current;
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum UsbPowerOption {
    SelfPowered = 0b01,
    HostPowered = 0b10,
}

impl UsbPowerOption {
    fn from_u8(v: u8) -> Result<UsbPowerOption, u8> {
        match v {
            0b10 => Ok(UsbPowerOption::HostPowered),
            0b01 => Ok(UsbPowerOption::SelfPowered),
            _ => Err(v),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ChipSettings {
    pub gp0_mode: PinMode,
    pub gp1_mode: PinMode,
    pub gp2_mode: PinMode,
    pub gp3_mode: PinMode,
    pub gp4_mode: PinMode,
    pub gp5_mode: PinMode,
    pub gp6_mode: PinMode,
    pub gp7_mode: PinMode,
    pub gp8_mode: PinMode,
    pub default_gpio_value: GpioValue,
    pub default_gpio_direction: GpioDirection,
    pub remote_wakeup: bool,
    pub interrupt_mode: InterruptMode,
    pub bus_release: bool,
    pub nvram_access_control: NvramAccessControl,
}

impl ChipSettings {
    pub fn from_buffer(buf: &Buffer) -> Result<ChipSettings, String> {
        Ok(ChipSettings {
            gp0_mode: PinMode::from_u8(buf[4])
                .map_err(|v| format!("Invalid gp0_mode value: {:02x}", v))?,
            gp1_mode: PinMode::from_u8(buf[5])
                .map_err(|v| format!("Invalid gp1_mode value: {:02x}", v))?,
            gp2_mode: PinMode::from_u8(buf[6])
                .map_err(|v| format!("Invalid gp2_mode value: {:02x}", v))?,
            gp3_mode: PinMode::from_u8(buf[7])
                .map_err(|v| format!("Invalid gp3_mode value: {:02x}", v))?,
            gp4_mode: PinMode::from_u8(buf[8])
                .map_err(|v| format!("Invalid gp4_mode value: {:02x}", v))?,
            gp5_mode: PinMode::from_u8(buf[9])
                .map_err(|v| format!("Invalid gp5_mode value: {:02x}", v))?,
            gp6_mode: PinMode::from_u8(buf[10])
                .map_err(|v| format!("Invalid gp6_mode value: {:02x}", v))?,
            gp7_mode: PinMode::from_u8(buf[11])
                .map_err(|v| format!("Invalid gp7_mode value: {:02x}", v))?,
            gp8_mode: PinMode::from_u8(buf[12])
                .map_err(|v| format!("Invalid gp8_mode value: {:02x}", v))?,
            default_gpio_value: GpioValue::from_bits_truncate(as_u16(buf[13], buf[14])),
            default_gpio_direction: GpioDirection::from_bits_truncate(as_u16(buf[15], buf[16])),
            remote_wakeup: buf[17] & 0b10000 != 0,
            interrupt_mode: InterruptMode::from_u8((buf[17] >> 1) & 0b111)
                .map_err(|v| format!("Invalid interrupt_mode value: {:02x}", v))?,
            bus_release: buf[17] & 0b1 == 0,
            nvram_access_control: NvramAccessControl::from_u8(buf[18])
                .map_err(|v| format!("Invalid nvram_access_control value: {:02x}", v))?,
        })
    }
    pub fn write_to_buffer(&self, buf: &mut Buffer) {
        let default_gpio_value = self.default_gpio_value.bits();
        let default_gpio_direction = self.default_gpio_direction.bits();
        buf[4] = self.gp0_mode as u8;
        buf[5] = self.gp1_mode as u8;
        buf[6] = self.gp2_mode as u8;
        buf[7] = self.gp3_mode as u8;
        buf[8] = self.gp4_mode as u8;
        buf[9] = self.gp5_mode as u8;
        buf[10] = self.gp6_mode as u8;
        buf[11] = self.gp7_mode as u8;
        buf[12] = self.gp8_mode as u8;
        buf[13] = default_gpio_value as u8;
        buf[14] = (default_gpio_value >> 8) as u8;
        buf[15] = default_gpio_direction as u8;
        buf[16] = (default_gpio_direction >> 8) as u8;
        buf[17] = (if self.remote_wakeup { 0b10000 } else { 0 })
            | ((self.interrupt_mode as u8) << 1)
            | (if self.bus_release { 0 } else { 0b1 });
        buf[18] = self.nvram_access_control as u8;
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum NvramAccessControl {
    None,
    Password = 0x40,
    PermanentlyLocked = 0x80,
}

impl Default for NvramAccessControl {
    fn default() -> NvramAccessControl {
        NvramAccessControl::None
    }
}

impl NvramAccessControl {
    fn from_u8(v: u8) -> Result<NvramAccessControl, u8> {
        match v {
            0x00 => Ok(NvramAccessControl::None),
            0x40 => Ok(NvramAccessControl::Password),
            0x80 => Ok(NvramAccessControl::PermanentlyLocked),
            _ => Err(v),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum InterruptMode {
    None = 0b000,
    FallingEdges = 0b001,
    RisingEdges = 0b010,
    LowPulses = 0b011,
    HighPulses = 0b100,
}

impl Default for InterruptMode {
    fn default() -> InterruptMode {
        InterruptMode::None
    }
}

impl InterruptMode {
    fn from_u8(v: u8) -> Result<InterruptMode, u8> {
        match v {
            0b100 => Ok(InterruptMode::HighPulses),
            0b011 => Ok(InterruptMode::LowPulses),
            0b010 => Ok(InterruptMode::RisingEdges),
            0b001 => Ok(InterruptMode::FallingEdges),
            0b000 => Ok(InterruptMode::None),
            _ => Err(v),
        }
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct SpiTransferSettings {
    pub bit_rate: u32,
    pub cs_idle: ChipSelect,
    pub cs_active: ChipSelect,
    pub delay_cs_to_data: u16,
    pub delay_last_data_to_cs: u16,
    pub delay_between_data: u16,
    pub bytes_per_tx: u16,
    pub spi_mode: SpiMode,
}

impl Default for SpiTransferSettings {
    fn default() -> SpiTransferSettings {
        SpiTransferSettings {
            bit_rate: MAX_BIT_RATE,
            cs_idle: ChipSelect::ALL_HIGH,
            cs_active: ChipSelect::ALL_LOW,
            delay_cs_to_data: 0,
            delay_last_data_to_cs: 0,
            delay_between_data: 0,
            bytes_per_tx: 4,
            spi_mode: SpiMode::Mode0,
        }
    }
}

impl SpiTransferSettings {
    pub fn from_buffer(buf: &Buffer) -> Result<SpiTransferSettings, String> {
        Ok(SpiTransferSettings {
            bit_rate: as_u32(buf[4], buf[5], buf[6], buf[7]),
            cs_idle: ChipSelect::from_bits_truncate(as_u16(buf[8], buf[9])),
            cs_active: ChipSelect::from_bits_truncate(as_u16(buf[10], buf[11])),
            delay_cs_to_data: as_u16(buf[12], buf[13]),
            delay_last_data_to_cs: as_u16(buf[14], buf[15]),
            delay_between_data: as_u16(buf[16], buf[17]),
            bytes_per_tx: as_u16(buf[18], buf[19]),
            spi_mode: SpiMode::from_u8(buf[20])
                .map_err(|v| format!("Invalid spi_mode value: {:02x}", v))?,
        })
    }
    pub fn write_to_buffer(&self, buf: &mut Buffer) {
        let cs_idle = self.cs_idle.bits();
        let cs_active = self.cs_active.bits();
        buf[4] = self.bit_rate as u8;
        buf[5] = (self.bit_rate >> 8) as u8;
        buf[6] = (self.bit_rate >> 16) as u8;
        buf[7] = (self.bit_rate >> 24) as u8;
        buf[8] = cs_idle as u8;
        buf[9] = (cs_idle >> 8) as u8;
        buf[10] = cs_active as u8;
        buf[11] = (cs_active >> 8) as u8;
        buf[12] = self.delay_cs_to_data as u8;
        buf[13] = (self.delay_cs_to_data >> 8) as u8;
        buf[14] = self.delay_last_data_to_cs as u8;
        buf[15] = (self.delay_last_data_to_cs >> 8) as u8;
        buf[16] = self.delay_between_data as u8;
        buf[17] = (self.delay_between_data >> 8) as u8;
        buf[18] = self.bytes_per_tx as u8;
        buf[19] = (self.bytes_per_tx >> 8) as u8;
        buf[20] = self.spi_mode as u8;
    }
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SpiMode {
    Mode0 = 0x00,
    Mode1 = 0x01,
    Mode2 = 0x02,
    Mode3 = 0x03,
}

impl SpiMode {
    fn from_u8(v: u8) -> Result<SpiMode, u8> {
        match v {
            0x00 => Ok(SpiMode::Mode0),
            0x01 => Ok(SpiMode::Mode1),
            0x02 => Ok(SpiMode::Mode2),
            0x03 => Ok(SpiMode::Mode3),
            _ => Err(v),
        }
    }
}

#[derive(Clone, Debug)]
pub struct SpiTransferResponse<'a> {
    pub data: &'a [u8],
    pub status: SpiTransferStatus,
}

#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SpiTransferStatus {
    Started,
    Pending,
    Finished,
}

impl SpiTransferStatus {
    pub(crate) fn from_u8(v: u8) -> Result<SpiTransferStatus, u8> {
        match v {
            0x20 => Ok(SpiTransferStatus::Started),
            0x30 => Ok(SpiTransferStatus::Pending),
            0x10 => Ok(SpiTransferStatus::Finished),
            _ => Err(v),
        }
    }
}