// // rhctl // // Copyright (C) 2009-2016 Christian Pointner // // This file is part of rhctl. // // rhctl is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // any later version. // // rhctl is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with rhctl. If not, see . // package main import ( "fmt" "time" ) type SwitchResult uint8 const ( SwitchOK SwitchResult = iota SwitchError ) func (c SwitchResult) String() string { switch c { case SwitchOK: return "OK" case SwitchError: return "error" } return "unknown" } type SwitchResponse struct { Result SwitchResult Message string } type SwitchUpdateType uint8 const ( SwitchAudio SwitchUpdateType = iota SwitchGPI SwitchOC SwitchRelay SwitchSilence ) func (c SwitchUpdateType) String() string { switch c { case SwitchAudio: return "audio" case SwitchGPI: return "gpi" case SwitchOC: return "oc" case SwitchRelay: return "relay" case SwitchSilence: return "silence" } return "unknown" } type SwitchUpdate struct { Type SwitchUpdateType Data string } type AudioSwitch struct { port *SerialPort timeout time.Duration current *SwitchCommand timer *time.Timer unit SwitchUnitID Commands chan *SwitchCommand Updates chan SwitchUpdate } func (sw *AudioSwitch) handleData(data string) { if len(data) < 3 { rhl.Printf("Audioswitch: ignoring short line") return } rhdl.Printf("Audioswitch: got data: %q", data) switch data[0:3] { case "RRR": fallthrough case "EEE": if sw.current != nil { resp := SwitchResponse{Message: data} resp.Result = SwitchError if data[0] == 'R' { resp.Result = SwitchOK } sw.current.Response <- resp sw.current = nil sw.timer.Stop() sw.timer = nil } else { rhl.Printf("Audioswitch: ignoring unexpected response: %q", data) } case "S0L": sw.Updates <- SwitchUpdate{SwitchAudio, data} case "S0P": sw.Updates <- SwitchUpdate{SwitchGPI, data} case "S0O": sw.Updates <- SwitchUpdate{SwitchOC, data} case "S0R": sw.Updates <- SwitchUpdate{SwitchRelay, data} case "S0S": sw.Updates <- SwitchUpdate{SwitchSilence, data} default: rhl.Printf("Audioswitch: ignoring invalid data: %q", data) } } func (sw *AudioSwitch) Run() { stop := make(chan bool) sw.port.Run(stop) sw.current = nil sw.timer = nil rhdl.Printf("Audioswitch: handler running...") for { if sw.current != nil { select { case <-stop: return case <-sw.timer.C: resp := SwitchResponse{SwitchError, "EEE timeout"} sw.current.Response <- resp sw.current = nil sw.timer = nil case data := <-sw.port.rx: sw.handleData(data) } } else { select { case <-stop: return case cmd := <-sw.Commands: sw.current = cmd sw.port.tx <- cmd.Cmd.Generate(append(cmd.Args, sw.unit)...) sw.timer = time.NewTimer(sw.timeout) case data := <-sw.port.rx: sw.handleData(data) } } } } func SwitchInit(conf *Config) (sw *AudioSwitch, err error) { sw = &AudioSwitch{} sw.timeout = time.Second if conf.Audioswitch.Timeout.Duration > 0 { sw.timeout = conf.Audioswitch.Timeout.Duration } sw.unit = conf.Audioswitch.Unit sw.Commands = make(chan *SwitchCommand, 8) sw.Updates = make(chan SwitchUpdate, 32) if sw.port, err = SerialOpen(conf.Audioswitch.Device, conf.Audioswitch.Baudrate, ""); err != nil { err = fmt.Errorf("Audioswitch: error opening serial port: %s", err) return } return }