-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
0ed13ca
commit 474af2e
Showing
15 changed files
with
377 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
/// TODO: What exactly is an attribute? | ||
pub struct Attribute { | ||
pub key: String, | ||
pub value: String, | ||
} | ||
|
||
impl Attribute { | ||
/// Intrepret raw bytes, according to the Tock Format (TODO: Source??) | ||
pub fn parse_raw(bytes: Vec<u8>) -> Attribute { | ||
todo!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
#![allow(unused)] | ||
// "This was chosen as it is infrequent in .bin files" - immesys | ||
pub const ESCAPE_CHAR: u8 = 0xFC; | ||
|
||
// Commands from this tool to the bootloader. (tockloader) | ||
// The "X" commands are for external flash. (tockloader) | ||
pub const COMMAND_PING: u8 = 0x01; | ||
pub const COMMAND_INFO: u8 = 0x03; | ||
pub const COMMAND_ID: u8 = 0x04; | ||
pub const COMMAND_RESET: u8 = 0x05; | ||
pub const COMMAND_ERASE_PAGE: u8 = 0x06; | ||
pub const COMMAND_WRITE_PAGE: u8 = 0x07; | ||
pub const COMMAND_XEBLOCK: u8 = 0x08; | ||
pub const COMMAND_XWPAGE: u8 = 0x09; | ||
pub const COMMAND_CRCRX: u8 = 0x10; | ||
pub const COMMAND_READ_RANGE: u8 = 0x11; | ||
pub const COMMAND_XRRANGE: u8 = 0x12; | ||
pub const COMMAND_SET_ATTRIBUTE: u8 = 0x13; | ||
pub const COMMAND_GET_ATTRIBUTE: u8 = 0x14; | ||
pub const COMMAND_CRC_INTERNAL_FLASH: u8 = 0x15; | ||
pub const COMMAND_CRCEF: u8 = 0x16; | ||
pub const COMMAND_XEPAGE: u8 = 0x17; | ||
pub const COMMAND_XFINIT: u8 = 0x18; | ||
pub const COMMAND_CLKOUT: u8 = 0x19; | ||
pub const COMMAND_WUSER: u8 = 0x20; | ||
pub const COMMAND_CHANGE_BAUD_RATE: u8 = 0x21; | ||
pub const COMMAND_EXIT: u8 = 0x22; | ||
pub const COMMAND_SET_START_ADDRESS: u8 = 0x23; | ||
|
||
// Responses from the bootloader. (tockloader) | ||
pub const RESPONSE_OVERFLOW: u8 = 0x10; | ||
pub const RESPONSE_PONG: u8 = 0x11; | ||
pub const RESPONSE_BADADDR: u8 = 0x12; | ||
pub const RESPONSE_INTERROR: u8 = 0x13; | ||
pub const RESPONSE_BADARGS: u8 = 0x14; | ||
pub const RESPONSE_OK: u8 = 0x15; | ||
pub const RESPONSE_UNKNOWN: u8 = 0x16; | ||
pub const RESPONSE_XFTIMEOUT: u8 = 0x17; | ||
pub const RESPONSE_XFEPE: u8 = 0x18; | ||
pub const RESPONSE_CRCRX: u8 = 0x19; | ||
pub const RESPONSE_READ_RANGE: u8 = 0x20; | ||
pub const RESPONSE_XRRANGE: u8 = 0x21; | ||
pub const RESPONSE_GET_ATTRIBUTE: u8 = 0x22; | ||
pub const RESPONSE_CRC_INTERNAL_FLASH: u8 = 0x23; | ||
pub const RESPONSE_CRCXF: u8 = 0x24; | ||
pub const RESPONSE_INFO: u8 = 0x25; | ||
pub const RESPONSE_CHANGE_BAUD_FAIL: u8 = 0x26; | ||
|
||
pub fn escape(source: Vec<u8>) -> Vec<u8> { | ||
let mut result = Vec::with_capacity(source.len()); | ||
for byte in source { | ||
result.push(byte); | ||
// Escape the escape char | ||
if byte == ESCAPE_CHAR { | ||
result.push(ESCAPE_CHAR) | ||
} | ||
} | ||
|
||
result | ||
} | ||
|
||
pub fn deescape(source: Vec<u8>) -> Vec<u8> { | ||
let mut result = Vec::with_capacity(source.len()); | ||
|
||
if !source.is_empty() { | ||
result.push(source[0]); | ||
} | ||
|
||
for i in 1..source.len() { | ||
if source[i] == ESCAPE_CHAR && source[i - 1] == ESCAPE_CHAR { | ||
// The previous char was already pushed, so we can skip | ||
// pushing this one | ||
continue; | ||
} else { | ||
result.push(source[i]); | ||
} | ||
} | ||
|
||
result | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
pub mod attribute; | ||
pub mod codes; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use async_trait::async_trait; | ||
|
||
use crate::{ | ||
bootloader::attribute::Attribute, errors::TockloaderError, | ||
interfaces::traits::BootloaderInterface, interfaces::JLinkInterface, | ||
}; | ||
|
||
#[async_trait] | ||
impl BootloaderInterface for JLinkInterface { | ||
async fn enter_bootloader(&mut self) -> Result<bool, TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn ping(&mut self) -> Result<bool, TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn sync(&mut self) -> Result<(), TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn get_attribute(&mut self) -> Result<Attribute, TockloaderError> { | ||
todo!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
use async_trait::async_trait; | ||
|
||
use crate::{ | ||
bootloader::attribute::Attribute, errors::TockloaderError, | ||
interfaces::traits::BootloaderInterface, interfaces::OpenOCDInterface, | ||
}; | ||
|
||
#[async_trait] | ||
impl BootloaderInterface for OpenOCDInterface { | ||
async fn enter_bootloader(&mut self) -> Result<bool, TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn ping(&mut self) -> Result<bool, TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn sync(&mut self) -> Result<(), TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn get_attribute(&mut self) -> Result<Attribute, TockloaderError> { | ||
todo!() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
use crate::errors::TockloaderError; | ||
use bytes::{BufMut, BytesMut}; | ||
use tokio_util::codec::{Decoder, Encoder}; | ||
|
||
pub struct BinaryCodec; | ||
|
||
impl Decoder for BinaryCodec { | ||
type Item = Vec<u8>; | ||
type Error = TockloaderError; | ||
|
||
fn decode(&mut self, source: &mut BytesMut) -> Result<Option<Self::Item>, Self::Error> { | ||
if source.is_empty() { | ||
return Ok(None); | ||
} | ||
|
||
Ok(Some(Vec::from(&source[..]))) | ||
} | ||
} | ||
|
||
impl Encoder<Vec<u8>> for BinaryCodec { | ||
type Error = TockloaderError; | ||
|
||
fn encode(&mut self, item: Vec<u8>, dst: &mut BytesMut) -> Result<(), Self::Error> { | ||
dst.put(&item[..]); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl Encoder<&[u8]> for BinaryCodec { | ||
type Error = TockloaderError; | ||
|
||
fn encode(&mut self, item: &[u8], dst: &mut BytesMut) -> Result<(), Self::Error> { | ||
dst.put(item); | ||
Ok(()) | ||
} | ||
} | ||
|
||
impl<const N: usize> Encoder<[u8; N]> for BinaryCodec { | ||
type Error = TockloaderError; | ||
|
||
fn encode(&mut self, item: [u8; N], dst: &mut BytesMut) -> Result<(), Self::Error> { | ||
dst.put(&item[..]); | ||
Ok(()) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
use super::binary_codec::BinaryCodec; | ||
use crate::{ | ||
bootloader::{ | ||
attribute::Attribute, | ||
codes::{ESCAPE_CHAR, RESPONSE_PONG}, | ||
}, | ||
errors::TockloaderError, | ||
interfaces::traits::BootloaderInterface, | ||
interfaces::SerialInterface, | ||
}; | ||
use async_trait::async_trait; | ||
use futures::{SinkExt, StreamExt}; | ||
use std::time::Duration; | ||
use tokio_serial::SerialPort; | ||
use tokio_util::codec::Decoder; | ||
|
||
#[async_trait] | ||
impl BootloaderInterface for SerialInterface { | ||
async fn enter_bootloader(&mut self) -> Result<bool, TockloaderError> { | ||
// These methods are taken from the python version of tockloader | ||
// bootlaoder_serial.py:518 [_toggle_bootloader_entry_DTR_RTS()] | ||
|
||
if self.stream.is_none() { | ||
return Err(TockloaderError::StreamClosed); | ||
} | ||
|
||
// Method 0: We are already in bootloader mode | ||
if self.bootloader_open().await { | ||
return Ok(true); | ||
} | ||
|
||
// Method 1: Change baud rate to 1200 and change back. | ||
// TODO: When does this work? | ||
self.stream | ||
.as_mut() | ||
.unwrap() | ||
.set_baud_rate(1200) | ||
.map_err(TockloaderError::TokioSeriallError)?; | ||
tokio::time::sleep(Duration::from_millis(1000)).await; | ||
|
||
if self.bootloader_open().await { | ||
return Ok(true); | ||
} | ||
|
||
self.stream | ||
.as_mut() | ||
.unwrap() | ||
.set_baud_rate(self.baud_rate) | ||
.map_err(TockloaderError::TokioSeriallError)?; | ||
tokio::time::sleep(Duration::from_millis(1000)).await; | ||
|
||
// Method 2: DTR & RTS | ||
// > Use the DTR and RTS lines on UART to reset the chip and assert the | ||
// > bootloader select pin to enter bootloader mode so that the chip will | ||
// > start in bootloader mode. | ||
// - tocklaoder | ||
|
||
// > Reset the SAM4L | ||
self.stream | ||
.as_mut() | ||
.unwrap() | ||
.write_data_terminal_ready(true) | ||
.map_err(TockloaderError::TokioSeriallError)?; | ||
|
||
// > Set RTS to make the SAM4L go into bootloader mode | ||
self.stream | ||
.as_mut() | ||
.unwrap() | ||
.write_request_to_send(true) | ||
.map_err(TockloaderError::TokioSeriallError)?; | ||
|
||
tokio::time::sleep(Duration::from_millis(100)).await; | ||
|
||
// > Let the SAM4L startup | ||
self.stream | ||
.as_mut() | ||
.unwrap() | ||
.write_data_terminal_ready(false) | ||
.map_err(TockloaderError::TokioSeriallError)?; | ||
|
||
// > make sure the bootloader enters bootloader mode | ||
tokio::time::sleep(Duration::from_millis(500)).await; | ||
|
||
self.stream | ||
.as_mut() | ||
.unwrap() | ||
.write_request_to_send(false) | ||
.map_err(TockloaderError::TokioSeriallError)?; | ||
|
||
if self.bootloader_open().await { | ||
return Ok(true); | ||
} | ||
|
||
Ok(false) | ||
} | ||
|
||
async fn ping(&mut self) -> Result<bool, TockloaderError> { | ||
let mut channel = BinaryCodec.framed(self.stream.as_mut().unwrap()); | ||
|
||
channel.send([ESCAPE_CHAR, 0x1]).await?; | ||
|
||
if let Ok(response) = | ||
tokio::time::timeout(Duration::from_millis(1000), channel.next()).await | ||
{ | ||
if let Some(decoder_result) = response { | ||
let response = decoder_result?; | ||
if response == [ESCAPE_CHAR, RESPONSE_PONG] { | ||
return Ok(true); | ||
} | ||
} | ||
|
||
Ok(false) | ||
} else { | ||
// Timeout | ||
Ok(false) | ||
} | ||
} | ||
|
||
async fn sync(&mut self) -> Result<(), TockloaderError> { | ||
todo!() | ||
} | ||
|
||
async fn get_attribute(&mut self) -> Result<Attribute, TockloaderError> { | ||
todo!() | ||
} | ||
} |
Oops, something went wrong.