55 */
66
77use crate :: { Error , Result } ;
8+ use i2cdev:: { core:: I2CDevice , linux:: LinuxI2CDevice } ;
89use log:: { error, info} ;
910use std:: {
10- fs:: { self , OpenOptions } ,
11- io:: Read ,
12- path, thread,
11+ str:: FromStr ,
12+ thread,
1313 time:: { Duration , Instant } ,
1414} ;
1515
1616const RECONNECT_TIMEOUT : Duration = Duration :: from_secs ( 3 ) ;
1717const POLL_WAIT : Duration = Duration :: from_millis ( 100 ) ;
1818const RECONNECT_WAIT : Duration = Duration :: from_secs ( 1 ) ;
1919
20+ const TPS_REG_MODE : u8 = 0x03 ;
21+ const TPS_REG_CMD1 : u8 = 0x08 ;
22+ const TPS_REG_DATA1 : u8 = 0x09 ;
23+ const TPS_REG_POWER_STATUS : u8 = 0x3f ;
24+
2025#[ allow( dead_code) ]
2126enum VdmSopType {
2227 Sop = 0b00 ,
@@ -25,106 +30,222 @@ enum VdmSopType {
2530 SopStar = 0b11 ,
2631}
2732
33+ #[ allow( dead_code) ]
34+ #[ derive( Debug , PartialEq ) ]
35+ enum TpsMode {
36+ TpsModeApp ,
37+ TpsModeBoot ,
38+ TpsModeBist ,
39+ TpsModeDisc ,
40+ TpsModePtch ,
41+ TpsModeDbma ,
42+ }
43+
44+ impl FromStr for TpsMode {
45+ type Err = ( ) ;
46+ fn from_str ( input : & str ) -> std:: result:: Result < TpsMode , ( ) > {
47+ match input {
48+ "APP " => Ok ( TpsMode :: TpsModeApp ) ,
49+ "BOOT" => Ok ( TpsMode :: TpsModeBoot ) ,
50+ "BIST" => Ok ( TpsMode :: TpsModeBist ) ,
51+ "DISC" => Ok ( TpsMode :: TpsModeDisc ) ,
52+ "PTCH" => Ok ( TpsMode :: TpsModePtch ) ,
53+ "DBMa" => Ok ( TpsMode :: TpsModeDbma ) ,
54+ _ => Err ( ( ) ) ,
55+ }
56+ }
57+ }
58+
59+ fn is_invalid_cmd ( val : u32 ) -> bool {
60+ val == 0x444d4321
61+ }
62+
2863pub ( crate ) struct Device {
29- path : path :: PathBuf ,
64+ i2c : LinuxI2CDevice ,
3065 key : Vec < u8 > ,
3166}
3267
33- fn verify_device ( dev : & str ) -> Result < path:: PathBuf > {
34- let mut fname = OpenOptions :: new ( )
35- . read ( true )
36- . open ( path:: Path :: new ( dev) . join ( "name" ) )
37- . unwrap ( ) ;
38- let mut data = Vec :: new ( ) ;
39- fname. read_to_end ( & mut data) . unwrap ( ) ;
40- let name = std:: str:: from_utf8 ( & data) . map_err ( Error :: Utf8 ) ?. trim ( ) ;
41- if name != "cd321x" {
42- error ! ( "{dev}/name \" {name}\" does not match \" cd321x\" " ) ;
43- return Err ( Error :: TypecController ) ;
44- }
45-
46- let vdm_dir = path:: Path :: new ( dev) . join ( "cd321x_vdm" ) ;
47- if !vdm_dir. exists ( ) {
48- error ! ( "{} does not exists" , vdm_dir. display( ) ) ;
49- return Err ( Error :: FeatureMissing ) ;
50- }
51- Ok ( vdm_dir. to_path_buf ( ) )
68+ /// Try to open the given I2C bus and slave address.
69+ /// Returns a configured LinuxI2CDevice on success.
70+ fn verify_i2c_device ( bus : & str , slave_address : u16 ) -> Result < LinuxI2CDevice > {
71+ match LinuxI2CDevice :: new ( bus, slave_address) {
72+ Ok ( dev) => {
73+ return Ok ( dev) ;
74+ }
75+ Err ( _) => { } // Fall through to attempt forced open
76+ }
77+
78+ info ! ( "Safely opening failed ==> Forcefully opening device..." ) ;
79+ let forced = unsafe { LinuxI2CDevice :: force_new ( bus, slave_address) } ;
80+ match forced {
81+ Ok ( dev) => Ok ( dev) ,
82+ Err ( _) => Err ( Error :: I2CError ) ,
83+ }
5284}
5385
5486impl Device {
55- pub ( crate ) fn new ( dev : & str , code : String ) -> Result < Self > {
56- let device = Self {
57- path : verify_device ( dev ) ?,
87+ pub ( crate ) fn new ( bus : & str , address : u16 , code : String ) -> Result < Self > {
88+ let mut device = Self {
89+ i2c : verify_i2c_device ( bus , address ) ?,
5890 key : code. into_bytes ( ) . into_iter ( ) . rev ( ) . collect :: < Vec < u8 > > ( ) ,
5991 } ;
60- device. lock ( device. key . as_slice ( ) ) ?;
92+ device. lock ( device. key . clone ( ) . as_slice ( ) ) ?;
6193 device. dbma ( true ) ?;
6294
6395 Ok ( device)
6496 }
6597
66- fn command ( & self , command : & [ u8 ; 4 ] , data : & [ u8 ] ) -> Result < ( ) > {
67- let data: Vec < u8 > = [ command, data] . concat ( ) ;
68- fs:: write ( self . path . as_path ( ) . join ( "command" ) , & data) . map_err ( Error :: Io )
98+ fn exec_cmd ( & mut self , cmd_tag : & [ u8 ; 4 ] , in_data : & [ u8 ] ) -> Result < ( ) > {
99+ self . exec_cmd_with_timing ( cmd_tag, in_data, Duration :: from_secs ( 1 ) , Duration :: ZERO )
69100 }
70101
71- fn lock ( & self , key : & [ u8 ] ) -> Result < ( ) > {
72- self . command ( b"LOCK" , key)
102+ fn exec_cmd_with_timing (
103+ & mut self ,
104+ cmd_tag : & [ u8 ; 4 ] ,
105+ in_data : & [ u8 ] ,
106+ cmd_timeout : Duration ,
107+ res_delay : Duration ,
108+ ) -> Result < ( ) > {
109+ // First: Check CMD1 Register busy
110+ {
111+ let mut status_buf = [ 0u8 ; 4 ] ;
112+ self . read_block ( TPS_REG_CMD1 , & mut status_buf) ?;
113+ let val = u32:: from_le_bytes ( status_buf) ;
114+ if val != 0 && !is_invalid_cmd ( val) {
115+ info ! ( "Busy Check Failed with VAL = {:?}" , val) ;
116+ return Err ( Error :: TypecController ) ;
117+ }
118+ }
119+
120+ // Write input Data to DATA1
121+ if !in_data. is_empty ( ) {
122+ self . write_block ( TPS_REG_DATA1 , in_data) ?;
123+ info ! ( "Wrote Data: {:02X?}" , in_data) ;
124+ }
125+
126+ // Write 4-byte command tag
127+ self . write_block ( TPS_REG_CMD1 , cmd_tag) ?;
128+
129+ // Poll until CMD1 becomes zero or timeout
130+ let start = Instant :: now ( ) ;
131+ loop {
132+ let mut status_buf = [ 0u8 ; 4 ] ;
133+ self . read_block ( TPS_REG_CMD1 , & mut status_buf) ?;
134+ let val = u32:: from_le_bytes ( status_buf) ;
135+
136+ if is_invalid_cmd ( val) {
137+ info ! ( "Invalid Command" ) ;
138+ return Err ( Error :: InvalidArgument ) ;
139+ }
140+
141+ if val == 0 {
142+ break ;
143+ }
144+ if start. elapsed ( ) > cmd_timeout {
145+ return Err ( Error :: ControllerTimeout ) ;
146+ }
147+ }
148+ thread:: sleep ( res_delay) ;
149+
150+ Ok ( ( ) )
151+ }
152+
153+ fn write_block ( & mut self , reg : u8 , data : & [ u8 ] ) -> Result < ( ) > {
154+ let mut buf = Vec :: with_capacity ( 1 + 1 + data. len ( ) ) ;
155+ let size: u8 = data. len ( ) . try_into ( ) . unwrap ( ) ;
156+ buf. push ( reg) ;
157+ buf. push ( size) ;
158+ buf. extend_from_slice ( data) ;
159+ self . i2c . write ( & buf) . map_err ( |_| Error :: I2CError ) ?;
160+ Ok ( ( ) )
161+ }
162+
163+ fn read_block ( & mut self , reg : u8 , buf : & mut [ u8 ] ) -> Result < ( ) > {
164+ self . i2c . write ( & [ reg] ) . map_err ( |_| Error :: I2CError ) ?;
165+ let mut internal_buf = vec ! [ 0u8 ; buf. len( ) + 1 ] ;
166+ self . i2c
167+ . read ( & mut internal_buf)
168+ . map_err ( |_| Error :: I2CError ) ?;
169+ buf. copy_from_slice ( & internal_buf[ 1 ..=buf. len ( ) ] ) ;
170+
171+ Ok ( ( ) )
73172 }
74173
75- fn dbma ( & self , debug : bool ) -> Result < ( ) > {
174+ fn get_mode ( & mut self ) -> Result < TpsMode > {
175+ let mut buf = [ 0u8 ; 4 ] ;
176+ self . read_block ( TPS_REG_MODE , & mut buf) ?;
177+ let s = std:: str:: from_utf8 ( & buf) . unwrap ( ) ;
178+ let m = TpsMode :: from_str ( s) . map_err ( |_| Error :: TypecController ) ?;
179+
180+ Ok ( m)
181+ }
182+
183+ fn lock ( & mut self , key : & [ u8 ] ) -> Result < ( ) > {
184+ self . exec_cmd ( b"LOCK" , & key)
185+ }
186+
187+ fn dbma ( & mut self , debug : bool ) -> Result < ( ) > {
76188 let data: [ u8 ; 1 ] = if debug { [ 1 ] } else { [ 0 ] } ;
77- self . command ( b"DBMa" , & data)
189+ self . exec_cmd ( b"DBMa" , & data) ?;
190+ if self . get_mode ( ) ? != TpsMode :: TpsModeDbma {
191+ return Err ( Error :: TypecController ) ;
192+ }
193+ Ok ( ( ) )
78194 }
79195
80- fn vdms ( & self , sop : VdmSopType , vdos : & [ u32 ] ) -> Result < ( ) > {
196+ fn vdms ( & mut self , sop : VdmSopType , vdos : & [ u32 ] ) -> Result < ( ) > {
81197 if vdos. is_empty ( ) || vdos. len ( ) > 7 {
82198 return Err ( Error :: InvalidArgument ) ;
83199 }
200+ if self . get_mode ( ) ? != TpsMode :: TpsModeDbma {
201+ return Err ( Error :: TypecController ) ;
202+ }
84203 let data = [
85204 vec ! [ ( ( sop as u8 ) << 4 ) | vdos. len( ) as u8 ] ,
86205 vdos. iter ( ) . flat_map ( |val| val. to_le_bytes ( ) ) . collect ( ) ,
87206 ]
88207 . concat ( ) ;
89- self . command ( b"VDMs" , & data)
208+ self . exec_cmd_with_timing (
209+ b"VDMs" ,
210+ & data,
211+ Duration :: from_millis ( 200 ) ,
212+ Duration :: from_millis ( 200 ) ,
213+ )
90214 }
91215
92- fn dven ( & self , vdos : & [ u32 ] ) -> Result < ( ) > {
216+ fn dven ( & mut self , vdos : & [ u32 ] ) -> Result < ( ) > {
93217 let data: Vec < u8 > = vdos. iter ( ) . flat_map ( |val| val. to_le_bytes ( ) ) . collect ( ) ;
94- self . command ( b"DEVn" , & data)
218+ self . exec_cmd ( b"DEVn" , & data)
95219 }
96220
97- fn is_connected ( & self ) -> Option < bool > {
98- let data: Vec < u8 > = fs:: read ( self . path . as_path ( ) . join ( "power_status" ) ) . ok ( ) ?;
99- let string = std:: str:: from_utf8 ( & data) . ok ( ) ?;
100- if string. len ( ) < 6 {
101- return None ;
102- }
103- let power_status = u16:: from_str_radix ( & string[ 2 ..6 ] , 16 ) . ok ( ) ?;
104-
105- Some ( ( power_status & 1 ) != 0 )
221+ fn check_connected ( & mut self ) -> Result < bool > {
222+ let mut buf = [ 0u8 ; 2 ] ;
223+ self . read_block ( TPS_REG_POWER_STATUS , & mut buf) ?;
224+ let power_status = u16:: from_le_bytes ( buf) ;
225+ Ok ( ( power_status & 1 ) != 0 )
106226 }
107227
108- pub ( crate ) fn dfu ( & self ) -> Result < ( ) > {
228+ pub ( crate ) fn dfu ( & mut self ) -> Result < ( ) > {
109229 let vdos: [ u32 ; 3 ] = [ 0x5ac8012 , 0x106 , 0x80010000 ] ;
110230 info ! ( "Rebooting target into DFU mode..." ) ;
111231 self . vdms ( VdmSopType :: SopStar , & vdos)
112232 }
113- pub ( crate ) fn reboot ( & self ) -> Result < ( ) > {
233+
234+ pub ( crate ) fn reboot ( & mut self ) -> Result < ( ) > {
114235 let vdos: [ u32 ; 3 ] = [ 0x5ac8012 , 0x105 , 0x80000000 ] ;
115236 info ! ( "Rebooting target into normal mode..." ) ;
116237 self . vdms ( VdmSopType :: SopStar , & vdos)
117238 }
118239
119- pub ( crate ) fn reboot_serial ( & self ) -> Result < ( ) > {
240+ pub ( crate ) fn reboot_serial ( & mut self ) -> Result < ( ) > {
120241 self . reboot ( ) ?;
121242 info ! ( "Waiting for connection..." ) ;
122243
123244 thread:: sleep ( RECONNECT_WAIT ) ;
124245
125246 let now = Instant :: now ( ) ;
126247 loop {
127- if self . is_connected ( ) . unwrap_or ( false ) {
248+ if self . check_connected ( ) . unwrap_or ( false ) {
128249 break ;
129250 }
130251 thread:: sleep ( POLL_WAIT ) ;
@@ -138,11 +259,14 @@ impl Device {
138259 self . serial ( )
139260 }
140261
141- pub ( crate ) fn serial ( & self ) -> Result < ( ) > {
262+ pub ( crate ) fn serial ( & mut self ) -> Result < ( ) > {
142263 let vdos: [ u32 ; 2 ] = [ 0x5ac8012 , 0x1840306 ] ;
143264 info ! ( "Putting target into serial mode..." ) ;
144265 self . vdms ( VdmSopType :: SopStar , & vdos) ?;
145266 info ! ( "Putting local end into serial mode... " ) ;
267+ if self . get_mode ( ) ? != TpsMode :: TpsModeDbma {
268+ return Err ( Error :: TypecController ) ;
269+ }
146270 self . dven ( & vdos[ 1 ..2 ] )
147271 }
148272}
0 commit comments