@@ -10,20 +10,29 @@ import (
1010)
1111
1212// recordingPort tracks all calls to SetDTR and SetRTS for testing.
13- // Each call is recorded as a separate event to allow testing the order and
14- // combinations of line state transitions.
13+ // Separate dtrCalls/rtsCalls slices preserve the per-line value history;
14+ // the unified calls slice preserves the full cross-line ordering needed
15+ // by tests that assert on interleaving.
1516type recordingPort struct {
1617 dtrCalls []bool
1718 rtsCalls []bool
19+ calls []lineCall
20+ }
21+
22+ type lineCall struct {
23+ line string // "DTR" or "RTS"
24+ value bool
1825}
1926
2027func (r * recordingPort ) SetDTR (dtr bool ) error {
2128 r .dtrCalls = append (r .dtrCalls , dtr )
29+ r .calls = append (r .calls , lineCall {line : "DTR" , value : dtr })
2230 return nil
2331}
2432
2533func (r * recordingPort ) SetRTS (rts bool ) error {
2634 r .rtsCalls = append (r .rtsCalls , rts )
35+ r .calls = append (r .calls , lineCall {line : "RTS" , value : rts })
2736 return nil
2837}
2938
@@ -35,10 +44,19 @@ func (r *recordingPort) SetWriteTimeout(t time.Duration) error {
3544func (r * recordingPort ) Close () error { return nil }
3645func (r * recordingPort ) ResetInputBuffer () error { return nil }
3746func (r * recordingPort ) ResetOutputBuffer () error { return nil }
38- func (r * recordingPort ) GetModemStatusBits () (* serial.ModemStatusBits , error ) { return nil , nil }
47+ func (r * recordingPort ) GetModemStatusBits () (* serial.ModemStatusBits , error ) { return nil , nil }
3948func (r * recordingPort ) Break (t time.Duration ) error { return nil }
4049func (r * recordingPort ) Drain () error { return nil }
4150
51+ func indexOf (calls []lineCall , line string , value bool , startAt int ) int {
52+ for i := startAt ; i < len (calls ); i ++ {
53+ if calls [i ].line == line && calls [i ].value == value {
54+ return i
55+ }
56+ }
57+ return - 1
58+ }
59+
4260// TestClassicReset verifies the classic reset sequence.
4361func TestClassicReset (t * testing.T ) {
4462 port := & recordingPort {}
@@ -161,3 +179,36 @@ func TestResetDelayConstants(t *testing.T) {
161179 assert .Equal (t , 50 * time .Millisecond , defaultResetDelay , "defaultResetDelay should be 50ms" )
162180 assert .Equal (t , 550 * time .Millisecond , extraResetDelay , "extraResetDelay should be 550ms" )
163181}
182+
183+ // TestHardResetNonUSBReleasesDTRBeforeReleasingReset verifies that on the
184+ // non-USB path, hardReset deasserts DTR before releasing EN (RTS=false).
185+ // Otherwise a leftover DTR=true from a prior operation holds IO0 LOW when
186+ // EN goes HIGH and the chip re-enters the download-mode bootloader.
187+ func TestHardResetNonUSBReleasesDTRBeforeReleasingReset (t * testing.T ) {
188+ port := & recordingPort {}
189+ hardReset (port , false )
190+
191+ rtsTrue := indexOf (port .calls , "RTS" , true , 0 )
192+ require := assert .New (t )
193+ require .GreaterOrEqual (rtsTrue , 0 , "expected SetRTS(true) to pull EN LOW" )
194+
195+ dtrFalse := indexOf (port .calls , "DTR" , false , rtsTrue )
196+ require .Greater (dtrFalse , rtsTrue , "SetDTR(false) must happen after EN is pulled LOW" )
197+
198+ rtsFalseFinal := indexOf (port .calls , "RTS" , false , dtrFalse )
199+ require .Greater (rtsFalseFinal , dtrFalse ,
200+ "final SetRTS(false) (release reset) must happen after SetDTR(false) so IO0 is HIGH when EN goes HIGH" )
201+ }
202+
203+ // TestHardResetUSBDeassertsDTRFirst verifies that on the USB-JTAG path,
204+ // hardReset deasserts DTR before driving EN, so GPIO0 is HIGH (normal boot,
205+ // not bootloader) at the moment the USB-JTAG peripheral latches the reset.
206+ func TestHardResetUSBDeassertsDTRFirst (t * testing.T ) {
207+ port := & recordingPort {}
208+ hardReset (port , true )
209+
210+ assert .NotEmpty (t , port .calls )
211+ first := port .calls [0 ]
212+ assert .Equal (t , "DTR" , first .line , "first call must be SetDTR on USB path" )
213+ assert .False (t , first .value , "first SetDTR must be false (release GPIO0)" )
214+ }
0 commit comments