@@ -28,8 +28,9 @@ import (
28
28
)
29
29
30
30
type windowsPort struct {
31
- mu sync.Mutex
32
- handle windows.Handle
31
+ mu sync.Mutex
32
+ handle windows.Handle
33
+ hasTimeout bool
33
34
}
34
35
35
36
func nativeGetPortsList () ([]string , error ) {
@@ -72,26 +73,33 @@ func (port *windowsPort) Read(p []byte) (int, error) {
72
73
}
73
74
defer windows .CloseHandle (ev .HEvent )
74
75
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
+ }
92
94
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
+ }
95
103
}
96
104
97
105
func (port * windowsPort ) Write (p []byte ) (int , error ) {
@@ -275,10 +283,19 @@ func (port *windowsPort) GetModemStatusBits() (*ModemStatusBits, error) {
275
283
}
276
284
277
285
func (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
+
278
295
commTimeouts := & windows.CommTimeouts {
279
296
ReadIntervalTimeout : 0xFFFFFFFF ,
280
297
ReadTotalTimeoutMultiplier : 0xFFFFFFFF ,
281
- ReadTotalTimeoutConstant : 0xFFFFFFFE ,
298
+ ReadTotalTimeoutConstant : MaxReadTotalTimeoutConstant ,
282
299
WriteTotalTimeoutConstant : 0 ,
283
300
WriteTotalTimeoutMultiplier : 0 ,
284
301
}
@@ -287,12 +304,20 @@ func (port *windowsPort) SetReadTimeout(timeout time.Duration) error {
287
304
if ms > 0xFFFFFFFE || ms < 0 {
288
305
return & PortError {code : InvalidTimeoutValue }
289
306
}
307
+
308
+ if ms > MaxReadTotalTimeoutConstant {
309
+ ms = MaxReadTotalTimeoutConstant
310
+ }
311
+
290
312
commTimeouts .ReadTotalTimeoutConstant = uint32 (ms )
291
313
}
292
314
315
+ port .mu .Lock ()
316
+ defer port .mu .Unlock ()
293
317
if err := windows .SetCommTimeouts (port .handle , commTimeouts ); err != nil {
294
318
return & PortError {code : InvalidTimeoutValue , causedBy : err }
295
319
}
320
+ port .hasTimeout = (timeout != NoTimeout )
296
321
297
322
return nil
298
323
}
0 commit comments