// // 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" "strconv" "strings" ) const ( SwitchUnitIDMax SwitchUnitID = 3 SwitchInputNumMax SwitchInputNum = 8 SwitchOutputNumMax SwitchOutputNum = 2 SwitchGPINumMax SwitchGPINum = 16 SwitchRelayNumMax SwitchRelayNum = 8 SwitchOCNumMax SwitchOCNum = 8 ) type SwitchUnitID uint func (u SwitchUnitID) String() string { return strconv.FormatUint(uint64(u), 10) } func (u *SwitchUnitID) FromString(str string) error { vuint, err := strconv.ParseUint(str, 10, 32) if err != nil { return err } if vuint > uint64(SwitchUnitIDMax) { return fmt.Errorf("switch unit ID is out of range") } *u = SwitchUnitID(vuint) return nil } func (u *SwitchUnitID) UnmarshalTOML(data []byte) error { return u.FromString(string(data)) } type SwitchInputNum uint func (i SwitchInputNum) String() string { return strconv.FormatUint(uint64(i), 10) } func (i *SwitchInputNum) FromString(str string) error { vuint, err := strconv.ParseUint(str, 10, 32) if err != nil { return err } if vuint < 1 || vuint > uint64(SwitchInputNumMax) { return fmt.Errorf("switch input number is out of range") } *i = SwitchInputNum(vuint) return nil } func (i *SwitchInputNum) UnmarshalTOML(data []byte) error { return i.FromString(string(data)) } type SwitchOutputNum uint func (o SwitchOutputNum) String() string { return strconv.FormatUint(uint64(o), 10) } func (o *SwitchOutputNum) FromString(str string) error { vuint, err := strconv.ParseUint(str, 10, 32) if err != nil { return err } if vuint < 1 || vuint > uint64(SwitchOutputNumMax) { return fmt.Errorf("switch output number is out of range") } *o = SwitchOutputNum(vuint) return nil } type SwitchGPINum uint func (g SwitchGPINum) String() string { return strconv.FormatUint(uint64(g), 10) } func (g *SwitchGPINum) FromString(str string) error { vuint, err := strconv.ParseUint(str, 10, 32) if err != nil { return err } if vuint < 1 || vuint > uint64(SwitchGPINumMax) { return fmt.Errorf("switch GPI number is out of range") } *g = SwitchGPINum(vuint) return nil } type SwitchRelayNum uint func (r SwitchRelayNum) String() string { return strconv.FormatUint(uint64(r), 10) } func (r *SwitchRelayNum) FromString(str string) error { vuint, err := strconv.ParseUint(str, 10, 32) if err != nil { return err } if vuint < 1 || vuint > uint64(SwitchRelayNumMax) { return fmt.Errorf("switch relay number is out of range") } *r = SwitchRelayNum(vuint) return nil } type SwitchOCNum uint func (o SwitchOCNum) String() string { return strconv.FormatUint(uint64(o), 10) } func (o *SwitchOCNum) FromString(str string) error { vuint, err := strconv.ParseUint(str, 10, 32) if err != nil { return err } if vuint < 1 || vuint > uint64(SwitchOCNumMax) { return fmt.Errorf("switch OC number is out of range") } *o = SwitchOCNum(vuint) return nil } type SwitchCmdString string const ( SwitchCmdStateAudio SwitchCmdString = "*uSL" SwitchCmdStateSilence SwitchCmdString = "*uSS" SwitchCmdStateGPI SwitchCmdString = "*uSPgg" SwitchCmdStateGPIAll SwitchCmdString = "*uSPA" SwitchCmdStateRelay SwitchCmdString = "*uSR" SwitchCmdStateOC SwitchCmdString = "*uSO" SwitchCmdAudioApplyInput SwitchCmdString = "*uiio" SwitchCmdAudioApplyInputAll SwitchCmdString = "*uiiA" SwitchCmdAudioAddInputTo1 SwitchCmdString = "*uii3" SwitchCmdAudioAddInputTo2 SwitchCmdString = "*uii4" SwitchCmdAudioRemoveInputFrom1 SwitchCmdString = "*uii5" SwitchCmdAudioRemoveInputFrom2 SwitchCmdString = "*uii6" SwitchCmdAudioMuteInput SwitchCmdString = "*uiiMo" SwitchCmdAudioMuteInputAll SwitchCmdString = "*uiiMA" SwitchCmdAudioMuteOutput SwitchCmdString = "*uMo" SwitchCmdAudioMuteOutputAll SwitchCmdString = "*uMA" SwitchCmdAudioFadeUpInput SwitchCmdString = "*uFUii" SwitchCmdAudioFadeDownInput SwitchCmdString = "*uFDii" SwitchCmdOCUnlatch SwitchCmdString = "*uOOcF" SwitchCmdOCLatch SwitchCmdString = "*uOOcL" SwitchCmdOCPulse SwitchCmdString = "*uOOcP" SwitchCmdRelayUnlatch SwitchCmdString = "*uORrF" SwitchCmdRelayLatch SwitchCmdString = "*uORrL" SwitchCmdRelayPulse SwitchCmdString = "*uORrP" ) func (c SwitchCmdString) Generate(args ...interface{}) (string, error) { s := string(c) for _, arg := range args { switch arg.(type) { case SwitchUnitID: if arg.(SwitchUnitID) > SwitchUnitIDMax { return "", fmt.Errorf("switch unit ID is out of range") } s = strings.Replace(s, "u", fmt.Sprintf("%1d", arg.(SwitchUnitID)), -1) case SwitchInputNum: if arg.(SwitchInputNum) < 1 || arg.(SwitchInputNum) > SwitchInputNumMax { return "", fmt.Errorf("switch input number is out of range") } s = strings.Replace(s, "ii", fmt.Sprintf("%02d", arg.(SwitchInputNum)), -1) case SwitchOutputNum: if arg.(SwitchOutputNum) < 1 || arg.(SwitchOutputNum) > SwitchOutputNumMax { return "", fmt.Errorf("switch input number is out of range") } s = strings.Replace(s, "o", fmt.Sprintf("%1d", arg.(SwitchOutputNum)), -1) case SwitchGPINum: if arg.(SwitchGPINum) < 1 || arg.(SwitchGPINum) > SwitchGPINumMax { return "", fmt.Errorf("switch GPI number is out of range") } s = strings.Replace(s, "gg", fmt.Sprintf("%02d", arg.(SwitchGPINum)), -1) case SwitchRelayNum: if arg.(SwitchRelayNum) < 1 || arg.(SwitchRelayNum) > SwitchRelayNumMax { return "", fmt.Errorf("switch relay number is out of range") } s = strings.Replace(s, "r", fmt.Sprintf("%1d", arg.(SwitchRelayNum)), -1) case SwitchOCNum: if arg.(SwitchOCNum) < 1 || arg.(SwitchOCNum) > SwitchOCNumMax { return "", fmt.Errorf("switch OC number is out of range") } s = strings.Replace(s, "c", fmt.Sprintf("%1d", arg.(SwitchOCNum)), -1) } } return s, nil } type SwitchCommand struct { Cmd SwitchCmdString Args []interface{} Response chan<- interface{} } func SwitchCommandParseState(args []string) (cmdstr SwitchCmdString, cmdargs []interface{}, err error) { if len(args) == 0 { err = fmt.Errorf("missing argument ") return } switch strings.ToLower(args[0]) { case "audio": cmdstr = SwitchCmdStateAudio case "silence": cmdstr = SwitchCmdStateSilence case "gpi": cmdstr = SwitchCmdStateGPIAll case "relay": cmdstr = SwitchCmdStateRelay case "oc": cmdstr = SwitchCmdStateOC default: err = fmt.Errorf("unknown state-type: '%s'", args[0]) return } return } func SwitchCommandParseAudio(args []string) (cmdstr SwitchCmdString, cmdargs []interface{}, err error) { if len(args) < 2 || len(args) > 3 { err = fmt.Errorf("wrong number of arguments") return } onum := SwitchOutputNum(0) if strings.ToLower(args[0]) != "all" { if err = onum.FromString(args[0]); err != nil { return } cmdargs = append(cmdargs, onum) } inum := SwitchInputNum(0) if len(args) == 3 { if err = inum.FromString(args[2]); err != nil { return } cmdargs = append(cmdargs, inum) } switch strings.ToLower(args[1]) { case "apply": if len(args) != 3 { err = fmt.Errorf("wrong number of arguments") return } if onum == 0 { cmdstr = SwitchCmdAudioApplyInputAll } else { cmdstr = SwitchCmdAudioApplyInput } case "add": if len(args) != 3 { err = fmt.Errorf("wrong number of arguments") return } switch onum { case 1: cmdstr = SwitchCmdAudioAddInputTo1 case 2: cmdstr = SwitchCmdAudioAddInputTo2 default: err = fmt.Errorf("this operation cannot be applied to all outputs") return } case "remove": if len(args) != 3 { err = fmt.Errorf("wrong number of arguments") return } switch onum { case 1: cmdstr = SwitchCmdAudioRemoveInputFrom1 case 2: cmdstr = SwitchCmdAudioRemoveInputFrom2 default: err = fmt.Errorf("this operation cannot be applied to all outputs") return } case "up": if len(args) != 3 { err = fmt.Errorf("wrong number of arguments") return } if onum != 1 { err = fmt.Errorf("this operation is only allowed on output 1") return } cmdstr = SwitchCmdAudioFadeUpInput case "down": if len(args) != 3 { err = fmt.Errorf("wrong number of arguments") return } if onum != 1 { err = fmt.Errorf("this operation is only allowed on output 1") return } cmdstr = SwitchCmdAudioFadeDownInput case "mute": if len(args) == 3 { if onum == 0 { cmdstr = SwitchCmdAudioMuteInputAll } else { cmdstr = SwitchCmdAudioMuteInput } } else { if onum == 0 { cmdstr = SwitchCmdAudioMuteOutputAll } else { cmdstr = SwitchCmdAudioMuteOutput } } default: err = fmt.Errorf("unknown operation: '%s', must be one of latch, unlatch, pulse", args[1]) return } return } func SwitchCommandParseRelay(args []string) (cmdstr SwitchCmdString, cmdargs []interface{}, err error) { if len(args) != 2 { err = fmt.Errorf("wrong number of arguments, expecting: (latch|unlatch|pulse)") return } var num SwitchRelayNum if err = num.FromString(args[0]); err != nil { return } cmdargs = append(cmdargs, num) switch strings.ToLower(args[1]) { case "latch": cmdstr = SwitchCmdRelayLatch case "unlatch": cmdstr = SwitchCmdRelayUnlatch case "pulse": cmdstr = SwitchCmdRelayPulse default: err = fmt.Errorf("unknown operation: '%s', must be one of latch, unlatch, pulse", args[1]) return } return } func SwitchCommandParseOC(args []string) (cmdstr SwitchCmdString, cmdargs []interface{}, err error) { if len(args) != 2 { err = fmt.Errorf("wrong number of arguments, expecting: (latch|unlatch|pulse)") return } var num SwitchOCNum if err = num.FromString(args[0]); err != nil { return } cmdargs = append(cmdargs, num) switch strings.ToLower(args[1]) { case "latch": cmdstr = SwitchCmdOCLatch case "unlatch": cmdstr = SwitchCmdOCUnlatch case "pulse": cmdstr = SwitchCmdOCPulse default: err = fmt.Errorf("unknown operation: '%s', must be one of latch, unlatch, pulse", args[1]) return } return } func SwitchCommandHelp() []string { return []string{ "state ", " request status update. The following types are allowed:", " - audio audio input/ouput routings", " - gpi state of general purpose inputs", " - oc state of open-collector outputs", " - relay state of relay outputs", " - silence output silence monitor state", "", "out [ ]", " change audio input/output routings.", " specifies the audio output: one of 1, 2, all ", " Commands:", " - apply simulate select button press", " - add add to output routing", " - remove remove from output routing", " - up fade up (only allowed for output 1)", " - down fade down (only allowed for output 1)", " - mute [ ] mute or whole ", "", "relay (latch|unlatch|pulse)", " Control open-collector outputs.", "", "oc (latch|unlatch|pulse)", " Control relay outputs.", "", } } func NewSwitchCommandFromStrings(cmd string, args ...string) (c *SwitchCommand, err error) { c = &SwitchCommand{} switch strings.ToLower(cmd) { case "state": c.Cmd, c.Args, err = SwitchCommandParseState(args) case "out": c.Cmd, c.Args, err = SwitchCommandParseAudio(args) case "relay": c.Cmd, c.Args, err = SwitchCommandParseRelay(args) case "oc": c.Cmd, c.Args, err = SwitchCommandParseOC(args) default: return nil, fmt.Errorf("unknown command '%s'", cmd) } return }