1
+ use super :: logs:: advance;
1
2
use crate :: args:: MonitorArgs ;
2
3
use crate :: net:: connect;
3
4
use anyhow:: { Context , Result } ;
@@ -14,6 +15,8 @@ const RBORD: u16 = 21;
14
15
const KB : u32 = 1024 ;
15
16
const MB : u32 = 1024 * KB ;
16
17
18
+ type Port = Box < dyn serialport:: SerialPort > ;
19
+
17
20
#[ derive( Default ) ]
18
21
struct Stats {
19
22
update : Option < serial:: Fuel > ,
@@ -22,17 +25,65 @@ struct Stats {
22
25
mem : Option < serial:: Memory > ,
23
26
}
24
27
28
+ impl Stats {
29
+ const fn is_default ( & self ) -> bool {
30
+ self . update . is_none ( ) && self . render . is_none ( ) && self . cpu . is_none ( ) && self . mem . is_none ( )
31
+ }
32
+ }
33
+
25
34
pub fn cmd_monitor ( _vfs : & Path , args : & MonitorArgs ) -> Result < ( ) > {
26
35
execute ! ( io:: stdout( ) , terminal:: EnterAlternateScreen ) . context ( "enter alt screen" ) ?;
27
36
execute ! ( io:: stdout( ) , cursor:: Hide ) . context ( "hide cursor" ) ?;
28
37
terminal:: enable_raw_mode ( ) . context ( "enable raw mode" ) ?;
29
- let res = monitor_emulator ( args) ;
38
+ let res = if let Some ( port) = & args. port {
39
+ monitor_device ( port, args)
40
+ } else {
41
+ monitor_emulator ( )
42
+ } ;
30
43
terminal:: disable_raw_mode ( ) . context ( "disable raw mode" ) ?;
31
44
execute ! ( io:: stdout( ) , terminal:: LeaveAlternateScreen ) . context ( "leave alt screen" ) ?;
32
45
res
33
46
}
34
47
35
- fn monitor_emulator ( _args : & MonitorArgs ) -> Result < ( ) > {
48
+ fn monitor_device ( port : & str , args : & MonitorArgs ) -> Result < ( ) > {
49
+ let mut port = connect_device ( port, args) ?;
50
+ let mut stats = Stats :: default ( ) ;
51
+ let mut buf = Vec :: new ( ) ;
52
+ loop {
53
+ if should_exit ( ) {
54
+ return Ok ( ( ) ) ;
55
+ }
56
+ buf = read_device ( & mut port, buf, & mut stats) ?;
57
+ render_stats ( & stats) . context ( "render stats" ) ?;
58
+ }
59
+ }
60
+
61
+ /// Connect to running emulator using serial USB port (JTag-over-USB).
62
+ fn connect_device ( port : & str , args : & MonitorArgs ) -> Result < Port > {
63
+ let mut port = serialport:: new ( port, args. baud_rate )
64
+ . timeout ( Duration :: from_millis ( 10 ) )
65
+ . open ( )
66
+ . context ( "open the serial port" ) ?;
67
+
68
+ execute ! (
69
+ io:: stdout( ) ,
70
+ terminal:: Clear ( terminal:: ClearType :: All ) ,
71
+ cursor:: MoveTo ( 0 , 0 ) ,
72
+ style:: Print ( "waiting for stats..." ) ,
73
+ ) ?;
74
+
75
+ // enable stats collection
76
+ {
77
+ let req = serial:: Request :: Stats ( true ) ;
78
+ let buf = req. encode_vec ( ) . context ( "encode request" ) ?;
79
+ port. write_all ( & buf[ ..] ) . context ( "send request" ) ?;
80
+ port. flush ( ) . context ( "flush request" ) ?;
81
+ }
82
+
83
+ Ok ( port)
84
+ }
85
+
86
+ fn monitor_emulator ( ) -> Result < ( ) > {
36
87
let mut stream = connect_emulator ( ) ?;
37
88
let mut stats = Stats :: default ( ) ;
38
89
loop {
@@ -44,7 +95,7 @@ fn monitor_emulator(_args: &MonitorArgs) -> Result<()> {
44
95
}
45
96
}
46
97
47
- /// Receive and parse stats from emulator.
98
+ /// Receive and parse one stats message from emulator.
48
99
fn read_emulator ( mut stream : TcpStream , stats : & mut Stats ) -> Result < TcpStream > {
49
100
let mut buf = vec ! [ 0 ; 64 ] ;
50
101
let size = stream. read ( & mut buf) . context ( "read response" ) ?;
@@ -56,6 +107,31 @@ fn read_emulator(mut stream: TcpStream, stats: &mut Stats) -> Result<TcpStream>
56
107
Ok ( stream)
57
108
}
58
109
110
+ /// Receive and parse one stats message from device.
111
+ fn read_device ( port : & mut Port , mut buf : Vec < u8 > , stats : & mut Stats ) -> Result < Vec < u8 > > {
112
+ let mut chunk = vec ! [ 0 ; 64 ] ;
113
+ let n = match port. read ( chunk. as_mut_slice ( ) ) {
114
+ Ok ( n) => n,
115
+ Err ( err) => {
116
+ if err. kind ( ) == std:: io:: ErrorKind :: TimedOut {
117
+ return Ok ( buf) ;
118
+ }
119
+ return Err ( err) . context ( "read from serial port" ) ;
120
+ }
121
+ } ;
122
+
123
+ buf. extend_from_slice ( & chunk[ ..n] ) ;
124
+ loop {
125
+ let ( frame, rest) = advance ( & buf) ;
126
+ buf = Vec :: from ( rest) ;
127
+ if frame. is_empty ( ) {
128
+ break ;
129
+ }
130
+ parse_stats ( stats, & frame) ?;
131
+ }
132
+ Ok ( buf)
133
+ }
134
+
59
135
/// Parse raw stats message using postcard. Does NOT handle COBS frames.
60
136
fn parse_stats ( stats : & mut Stats , buf : & [ u8 ] ) -> Result < ( ) > {
61
137
let resp = serial:: Response :: decode ( buf) . context ( "decode response" ) ?;
@@ -136,6 +212,9 @@ fn should_exit() -> bool {
136
212
137
213
/// Display stats in the terminal.
138
214
fn render_stats ( stats : & Stats ) -> Result < ( ) > {
215
+ if stats. is_default ( ) {
216
+ return Ok ( ( ) ) ;
217
+ }
139
218
execute ! ( io:: stdout( ) , terminal:: Clear ( terminal:: ClearType :: All ) ) ?;
140
219
if let Some ( cpu) = & stats. cpu {
141
220
render_cpu ( cpu) . context ( "render cpu table" ) ?;
0 commit comments