@@ -28,8 +28,9 @@ import (
2828)
2929
3030type windowsPort struct {
31- mu sync.Mutex
32- handle windows.Handle
31+ mu sync.Mutex
32+ handle windows.Handle
33+ hasTimeout bool
3334}
3435
3536func nativeGetPortsList () ([]string , error ) {
@@ -72,26 +73,33 @@ func (port *windowsPort) Read(p []byte) (int, error) {
7273 }
7374 defer windows .CloseHandle (ev .HEvent )
7475
75- err = windows .ReadFile (port .handle , p , & readed , ev )
76- if err == windows .ERROR_IO_PENDING {
77- err = windows .GetOverlappedResult (port .handle , ev , & readed , true )
78- }
79- switch err {
80- case nil :
81- // operation completed successfully
82- case windows .ERROR_OPERATION_ABORTED :
83- // port may have been closed
84- return int (readed ), & PortError {code : PortClosed , causedBy : err }
85- default :
86- // error happened
87- return int (readed ), err
88- }
89- if readed > 0 {
90- return int (readed ), nil
91- }
76+ for {
77+ err = windows .ReadFile (port .handle , p , & readed , ev )
78+ if err == windows .ERROR_IO_PENDING {
79+ err = windows .GetOverlappedResult (port .handle , ev , & readed , true )
80+ }
81+ switch err {
82+ case nil :
83+ // operation completed successfully
84+ case windows .ERROR_OPERATION_ABORTED :
85+ // port may have been closed
86+ return int (readed ), & PortError {code : PortClosed , causedBy : err }
87+ default :
88+ // error happened
89+ return int (readed ), err
90+ }
91+ if readed > 0 {
92+ return int (readed ), nil
93+ }
9294
93- // Timeout
94- return 0 , nil
95+ // Timeout
96+ port .mu .Lock ()
97+ hasTimeout := port .hasTimeout
98+ port .mu .Unlock ()
99+ if hasTimeout {
100+ return 0 , nil
101+ }
102+ }
95103}
96104
97105func (port * windowsPort ) Write (p []byte ) (int , error ) {
@@ -275,10 +283,19 @@ func (port *windowsPort) GetModemStatusBits() (*ModemStatusBits, error) {
275283}
276284
277285func (port * windowsPort ) SetReadTimeout (timeout time.Duration ) error {
286+ // This is a brutal hack to make the CH340 chipset work properly.
287+ // Normally this value should be 0xFFFFFFFE but, after a lot of
288+ // tinkering, I discovered that any value with the highest
289+ // bit set will make the CH340 driver behave like the timeout is 0,
290+ // in the best cases leading to a spinning loop...
291+ // (could this be a wrong signed vs unsigned conversion in the driver?)
292+ // https://github.com/arduino/serial-monitor/issues/112
293+ const MaxReadTotalTimeoutConstant = 0x7FFFFFFE
294+
278295 commTimeouts := & windows.CommTimeouts {
279296 ReadIntervalTimeout : 0xFFFFFFFF ,
280297 ReadTotalTimeoutMultiplier : 0xFFFFFFFF ,
281- ReadTotalTimeoutConstant : 0xFFFFFFFE ,
298+ ReadTotalTimeoutConstant : MaxReadTotalTimeoutConstant ,
282299 WriteTotalTimeoutConstant : 0 ,
283300 WriteTotalTimeoutMultiplier : 0 ,
284301 }
@@ -287,12 +304,20 @@ func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
287304 if ms > 0xFFFFFFFE || ms < 0 {
288305 return & PortError {code : InvalidTimeoutValue }
289306 }
307+
308+ if ms > MaxReadTotalTimeoutConstant {
309+ ms = MaxReadTotalTimeoutConstant
310+ }
311+
290312 commTimeouts .ReadTotalTimeoutConstant = uint32 (ms )
291313 }
292314
315+ port .mu .Lock ()
316+ defer port .mu .Unlock ()
293317 if err := windows .SetCommTimeouts (port .handle , commTimeouts ); err != nil {
294318 return & PortError {code : InvalidTimeoutValue , causedBy : err }
295319 }
320+ port .hasTimeout = (timeout != NoTimeout )
296321
297322 return nil
298323}
0 commit comments