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
use crate::common::{
    u16_get_u8_high, u16_get_u8_low, Action, Request, INDEX_ADDRESS,
    INDEX_CONTROL_COMMAND_0, INDEX_CONTROL_COMMAND_1, INDEX_READ_WRITE, INDEX_SET_VALUE_LOW,
    MESSAGE_LENGTH, READ_RESPONSE_LENGTH, VALUE_ADDRESS, VALUE_READ, VALUE_WRITE
};
use crate::crc;
use crate::current;
use crate::port;
use crate::result::{Hm305pError, ErrorKind};
use crate::voltage;

pub fn send_and_receive(request: Request) -> Result<u16, Hm305pError> {
    let mut port = port::connect()?;
    let mut message = [0; MESSAGE_LENGTH];
    message[INDEX_ADDRESS] = VALUE_ADDRESS;
    message[INDEX_READ_WRITE] = match request {
        Request::Read(_) => VALUE_READ,
        Request::Write(_) => VALUE_WRITE,
    };

    match request {
        Request::Read(Action::CurrentmA) => {
            message[INDEX_CONTROL_COMMAND_0] = 0x00;
            message[INDEX_CONTROL_COMMAND_1] = 0x11;
        },
        Request::Read(Action::VoltagemV) => {
            message[INDEX_CONTROL_COMMAND_0] = 0x00;
            message[INDEX_CONTROL_COMMAND_1] = 0x10;
        },
        Request::Write((Action::CurrentmA, _)) => {
            message[INDEX_CONTROL_COMMAND_0] = 0x00;
            message[INDEX_CONTROL_COMMAND_1] = 0x31;
        },
        Request::Write((Action::VoltagemV, _)) => {
            message[INDEX_CONTROL_COMMAND_0] = 0x00;
            message[INDEX_CONTROL_COMMAND_1] = 0x30;
        },
        Request::Write((Action::OnOff, _)) => {
            message[INDEX_CONTROL_COMMAND_0] = 0x00;
            message[INDEX_CONTROL_COMMAND_1] = 0x01;
        },
        _ => unimplemented!("Option has not yet been implemented"),
    }

    match request {
        Request::Read(_) => {
            message[4] = 0x00;
            message[5] = 0x01;
        },
        Request::Write((Action::CurrentmA, value)) => current::set(value, &mut message),
        Request::Write((Action::OnOff, value)) => message[INDEX_SET_VALUE_LOW] = value as u8,
        Request::Write((Action::VoltagemV, value)) => voltage::set(value, &mut message),
    }

    crc::fill(&mut message);
    port.write(&message)?;
    let response = port::read(&mut port)?;

    match request {
        Request::Read(_) => verify_read(response)?,
        Request::Write(_) => verify_write(response)?,
    }

    match request {
        Request::Read(Action::CurrentmA) => {
            let current_ma = current::get(response);
            return Ok(current_ma)
        }
        Request::Read(Action::VoltagemV) => {
            let voltage_mv = voltage::get(response);
            return Ok(voltage_mv)
        },
        Request::Read(_) => unimplemented!("Option has not yet been implemented"),
        Request::Write(_) => return Ok(0),
    }
}

fn verify_read(response: [u8; MESSAGE_LENGTH]) -> Result<(), Hm305pError> {
    if response[INDEX_ADDRESS] != VALUE_ADDRESS
        || response[INDEX_READ_WRITE] != VALUE_READ
        || response[2] != 2 {
        return Err(Hm305pError::new(ErrorKind::UnexpectedResponse, "Unexpected response from power supply"));
    }

    let crc = crc::compute(&response, READ_RESPONSE_LENGTH);

    if response[5] != u16_get_u8_low(crc) || response[6] != u16_get_u8_high(crc) {
        return Err(Hm305pError::new(ErrorKind::InvalidCrc, "Power supply CRC is invalid"));
    }

    Ok(())
}

fn verify_write(response: [u8; MESSAGE_LENGTH]) -> Result<(), Hm305pError> {
    if response[INDEX_ADDRESS] != VALUE_ADDRESS
        || response[INDEX_READ_WRITE] != VALUE_WRITE
        || response[2] != 0 {
        let text = format!("Power supply response: {:?}", response);
        return Err(Hm305pError::new(ErrorKind::UnexpectedResponse, &text));
    }

    let crc = crc::compute(&response, MESSAGE_LENGTH);

    if response[6] != u16_get_u8_low(crc) || response[7] != u16_get_u8_high(crc) {
        return Err(Hm305pError::new(ErrorKind::InvalidCrc, "Power supply CRC is invalid"));
    }

    Ok(())
}

#[cfg(test)]
#[path = "./test_message.rs"]
mod test_message;