2013-07-11 17 views
6

Napisałem krótki program w Go do komunikacji z czujnikiem za pośrednictwem portu szeregowego:Odczyt z portu szeregowego z pętli while-

package main 

import (
    "fmt" 
    "github.com/tarm/goserial" 
    "time" 
) 

func main() { 
    c := &serial.Config{Name: "/dev/ttyUSB0", Baud: 9600} 
    s, err := serial.OpenPort(c) 

    if err != nil { 
      fmt.Println(err) 
    } 

    _, err = s.Write([]byte("\x16\x02N0C0 G A\x03\x0d\x0a")) 

    if err != nil { 
      fmt.Println(err) 
    } 

    time.Sleep(time.Second/2) 

    buf := make([]byte, 40) 
    n, err := s.Read(buf) 

    if err != nil { 
      fmt.Println(err) 
    } 

    fmt.Println(string(buf[:n])) 

    s.Close() 
} 

To działa dobrze, ale po napisaniu do portu muszę poczekaj około pół sekundy, zanim zacznę czytać. Chciałbym użyć pętli while zamiast time.Sleep, aby odczytać wszystkie przychodzące dane. Moja próba nie działa:

buf := make([]byte, 40) 
n := 0 

for { 
    n, _ := s.Read(buf) 

    if n > 0 { 
     break 
    } 
} 

fmt.Println(string(buf[:n])) 

Chyba buf pobiera nadpisywane po każdym przejściu pętli. Jakieś sugestie?

Odpowiedz

8

Twój problem polega na tym, że Read() powróci, gdy tylko ma jakieś dane - nie będzie czekać na wszystkie dane. Aby uzyskać więcej informacji, zobacz io.Reader specification.

Co chcesz zrobić, to przeczytać, aż dojdziesz do ogranicznika. Nie wiem dokładnie, jakiego formatu próbujesz użyć, ale wygląda na to, że być może ogranicznik końcowy to \x0a.

W takim przypadku byłoby użyć bufio.Reader jak ten

reader := bufio.NewReader(s) 
reply, err := reader.ReadBytes('\x0a') 
if err != nil { 
    panic(err) 
} 
fmt.Println(reply) 

Który będzie czytać dane aż do pierwszego \x0a.

+1

Dziękuję za sugestię. Do tej pory działa dobrze, ale nadal muszę używać 'time.Sleep', w przeciwnym razie dostanę' panikę: EOF', ponieważ bufor jest pusty w momencie odczytu. (Nawiasem mówiąc: ogranicznik końcowy to '\ x03', po którym następuje suma kontrolna dwóch bajtów szesnastkowych.) – laserbrain

+0

Dziwne - nie sądziłem, że urządzenie szeregowe powinno kiedykolwiek dawać EOF, a zdecydowanie nie powinno tak być ponieważ bufor jest pusty. Jedyną możliwością, o której mogę pomyśleć, jest odrzucenie DTR/DSR. Upewnij się, że używasz kabla z podłączonymi tylko pinami 2 i pin 3 (Rx i Tx), pozostawiając wszystkie inne linie uzgadniania odłączone. Być może będziesz musiał przywrócić DTR do DSR na urządzeniu, ale nie powinieneś tego robić na komputerze. –

+0

Możesz chcieć sprawdzić, czy pakiet, którego używasz, blokuje wywołanie Read lub może blokować wywołanie "WaitForData". Różnica między "brakiem danych" i "nigdy nie będzie więcej danych" (ten ostatni jest tym, co oznacza EOF), więc nie rozumiem, dlaczego dają ci EOF - nie powinni tego robić . W każdym razie połączenie blokujące może zrobić to, czego szukasz, jeśli jest zaimplementowane. – joshlf

1

Chyba buf zostaje nadpisany po każdym przejściu pętli. Jakieś sugestie?

Tak, buf zostanie nadpisane przy każdym połączeniu z numerem Read().

Limit czasu na uchwycie pliku byłby to podejście, które chciałbym podjąć.

s, _ := os.OpenFile("/dev/ttyS0", syscall.O_RDWR|syscall.O_NOCTTY|syscall.O_NONBLOCK, 0666) 

t := syscall.Termios{ 
    Iflag: syscall.IGNPAR, 
    Cflag: syscall.CS8 | syscall.CREAD | syscall.CLOCAL | syscall.B115200, 
    Cc:  [32]uint8{syscall.VMIN: 0, syscall.VTIME: uint8(20)}, //2.0s timeout 
    Ispeed: syscall.B115200, 
    Ospeed: syscall.B115200, 
} 

// syscall 
syscall.Syscall6(syscall.SYS_IOCTL, uintptr(s.Fd()), 
    uintptr(syscall.TCSETS), uintptr(unsafe.Pointer(&t)), 
    0, 0, 0) 

// Send message 
n, _ := s.Write([]byte("Test message")) 

// Receive reply 
for { 
    buf := make([]byte, 128) 
    n, err = s.Read(buf) 
    if err != nil { // err will equal io.EOF 
     break 
    } 
    fmt.Printf("%v\n", string(buf)) 
} 

Należy również pamiętać, jeśli nie ma więcej danych czytać i nie ma błędu, os.File.Read() zwróci błąd z io.EOF, as you can see here.

Powiązane problemy