#[macro_use]
extern crate bitflags;
extern crate byteorder;
extern crate spidev;
use std::io;
use std::path::Path;
use spidev::{Spidev, SpidevOptions, SpidevTransfer, SPI_MODE_3};
use std::{thread, time};
use byteorder::{ByteOrder, BigEndian};
pub mod register;
pub use register::Register;
bitflags! {
pub struct Motors: u8 {
const M1 = 0b00000001;
const M2 = 0b00000010;
const M3 = 0b00000100;
const M4 = 0b00001000;
const M5 = 0b00010000;
const M6 = 0b00100000;
const M7 = 0b01000000;
const M8 = 0b10000000;
}
}
#[derive(PartialEq)]
pub enum Direction {
CW,
CCW,
}
pub struct L6470 {
spi: Spidev,
daisy_chain: u8
}
bitflags! {
pub struct StepMode: u8 {
const DIV1 = 0;
const DIV2 = 0b00000001;
const DIV4 = 0b00000010;
const DIV16 = 0b00000100;
const DIV8 = Self::DIV2.bits | Self::DIV4.bits;
const DIV32 = Self::DIV2.bits | Self::DIV16.bits;
const DIV64 = Self::DIV4.bits | Self::DIV16.bits;
const DIV128 = Self::DIV2.bits | Self::DIV4.bits | Self::DIV16.bits;
}
}
impl L6470{
pub fn init(&self) {
self.resync_com();
self.send_reset(Motors::all());
self.write_register(Motors::all(), ®ister::ALARM_EN, 0b1000_0011 as u32);
self.get_status(Motors::all());
self.set_step_mode(Motors::all(), StepMode::DIV16);
self.init_speed();
}
pub fn init_speed(&self){
let tick_ns = 250;
self.write_register(Motors::all(), ®ister::ACC, 0xE);
self.write_register( Motors::all(), ®ister::DEC, 0xE);
self.write_register(Motors::all(), ®ister::MAX_SPEED, 0xE);
self.write_register( Motors::all(), ®ister::MIN_SPEED, 40);
}
pub fn get_status(&self, motors: Motors){
self.send_byte(motors, 0xD0);
self.send_byte(motors, 0xFF);
self.send_byte(motors, 0xFF);
}
pub fn send_run(&self, motors: Motors, dir: Direction, speed: u32){
let mut command = 0x50u8;
if dir == Direction::CW {
command += 1;
}
self.send_byte(motors, command );
let mut buf= [0;4];
BigEndian::write_u32(&mut buf, speed);
self.send_byte(motors, buf[1] );
self.send_byte(motors, buf[2] );
self.send_byte(motors, buf[3] );
}
pub fn send_go_until(&self, motors: Motors, dir: Direction, speed: u32){
let mut command = 0b10001010;
if dir == Direction::CW {
command += 1;
}
self.send_byte(motors, command );
let mut buf= [0;4];
BigEndian::write_u32(&mut buf, speed);
self.send_byte(motors, buf[1] );
self.send_byte(motors, buf[2] );
self.send_byte(motors, buf[3] );
}
pub fn send_reset(&self, motors: Motors){
self.send_byte(motors, 0xC0);
let ten_millis = time::Duration::from_millis(1000);
thread::sleep(ten_millis);
}
pub fn resync_com(&self) {
self.send_byte(Motors::all(), 0x00);
self.send_byte(Motors::all(), 0x00);
self.send_byte(Motors::all(), 0x00);
self.send_byte(Motors::all(), 0x00);
}
fn set_step_mode(&self, motors: Motors, step_mode: StepMode){
self.write_register(motors, ®ister::STEP_MODE, step_mode.bits as u32 );
}
pub fn send_byte(&self, motors: Motors, byte: u8){
let mut buf = [0,8];
if self.daisy_chain >= 8 {
unimplemented!();
}
for i in 0..self.daisy_chain {
if motors.bits & (1<<i) != 0 {
buf[i as usize] = byte;
} else {
buf[i as usize] = 0; }
}
self.transfer(&buf[0..self.daisy_chain as usize]);
}
pub fn write_register(&self, motors: Motors, reg: &Register, value: u32 ) {
self.send_byte(motors, 0x00 | reg.address );
let mut buf= [0;4];
BigEndian::write_u32(&mut buf, value);
let buf_size = match reg.len_bit {
1..=8 => 1,
9..=16 => 2,
17..=24 => 3,
_ => unreachable!(),
};
match buf_size {
1 => {
self.send_byte(motors, buf[3]);
},
2 => {
self.send_byte(motors, buf[2]);
self.send_byte(motors, buf[3]);
},
3 => {
self.send_byte(motors, buf[1]);
self.send_byte(motors, buf[2]);
self.send_byte(motors, buf[3]);
},
_ => unreachable!(),
}
}
pub fn transfer(&self, input: &[u8]) -> io::Result<Vec<u8>> {
let mut rx_buf = input.to_vec();
{
let mut transfer = SpidevTransfer::read_write(&input, &mut rx_buf);
try!(self.spi.transfer(&mut transfer));
}
let ten_millis = time::Duration::from_millis(1);
thread::sleep(ten_millis);
println!("tx: {:02X?}, rx: {:02X?}", input, rx_buf);
Ok(rx_buf)
}
}
pub struct L6470Connector{
spi_bus: io::Result<Spidev>,
spi_options: SpidevOptions,
daisy_chain: u8,
}
impl L6470Connector {
pub fn new<P: AsRef<Path>>(path: P) -> L6470Connector {
L6470Connector {
spi_bus: Spidev::open(path),
spi_options: SpidevOptions::new()
.bits_per_word(8)
.max_speed_hz(20_000) .mode(SPI_MODE_3)
.build(),
daisy_chain: 2,
}
}
pub fn set_spi_clock_hz(&mut self, clock_hz: u32){
self.spi_options.max_speed_hz(clock_hz);
}
pub fn build(self) -> io::Result<L6470> {
let mut spi = self.spi_bus?;
spi.configure(&self.spi_options)?;
Ok(L6470{
spi: spi,
daisy_chain: self.daisy_chain,
})
}
}
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
assert_eq!(2 + 2, 4);
}
}