github.com/martinohmann/rfoutlet@v1.2.1-0.20220707195255-8a66aa411105/cmd/transmit.go (about) 1 package cmd 2 3 import ( 4 "context" 5 "fmt" 6 "strconv" 7 "time" 8 9 "github.com/martinohmann/rfoutlet/internal/config" 10 "github.com/martinohmann/rfoutlet/pkg/gpio" 11 log "github.com/sirupsen/logrus" 12 "github.com/spf13/cobra" 13 ) 14 15 func NewTransmitCommand() *cobra.Command { 16 options := &TransmitOptions{ 17 PulseLength: config.DefaultPulseLength, 18 Pin: config.DefaultTransmitPin, 19 Protocol: config.DefaultProtocol, 20 Count: gpio.DefaultTransmissionCount, 21 } 22 23 cmd := &cobra.Command{ 24 Use: "transmit [codes...]", 25 Short: "Send out codes to remote controlled outlets", 26 Long: "The transmit command can be used send out codes to remote controlled outlets.", 27 Args: cobra.MinimumNArgs(1), 28 RunE: func(cmd *cobra.Command, args []string) error { 29 return options.Run(cmd, args) 30 }, 31 } 32 33 options.AddFlags(cmd) 34 35 return cmd 36 } 37 38 type TransmitOptions struct { 39 config.Config 40 PulseLength uint 41 Pin uint 42 Protocol int 43 Count int 44 Delay time.Duration 45 Infinite bool 46 } 47 48 func (o *TransmitOptions) AddFlags(cmd *cobra.Command) { 49 cmd.Flags().UintVar(&o.PulseLength, "pulse-length", o.PulseLength, "pulse length") 50 cmd.Flags().UintVar(&o.Pin, "pin", o.Pin, "gpio pin to transmit on") 51 cmd.Flags().IntVar(&o.Protocol, "protocol", o.Protocol, "protocol to use for the transmission") 52 cmd.Flags().IntVar(&o.Count, "count", o.Count, "number of times a code should be transmitted in a row. The higher the value, the more likely it is that an outlet actually received the code") 53 cmd.Flags().DurationVar(&o.Delay, "delay", o.Delay, "delay between code transmissions") 54 cmd.Flags().BoolVar(&o.Infinite, "infinite", o.Infinite, "restart the transmission of codes after the last one was sent") 55 } 56 57 func (o *TransmitOptions) Run(cmd *cobra.Command, args []string) error { 58 if o.Protocol < 1 || o.Protocol > len(gpio.DefaultProtocols) { 59 return fmt.Errorf("protocol %d does not exist", o.Protocol) 60 } 61 62 proto := gpio.DefaultProtocols[o.Protocol-1] 63 64 codes := make([]uint64, len(args)) 65 66 for i, arg := range args { 67 var err error 68 codes[i], err = strconv.ParseUint(arg, 10, 64) 69 if err != nil { 70 return fmt.Errorf("failed to parse code: %v", err) 71 } 72 } 73 74 device, err := openGPIODevice(cmd) 75 if err != nil { 76 return err 77 } 78 defer device.Close() 79 80 transmitter, err := gpio.NewTransmitter(device.Chip, int(o.Pin), gpio.TransmissionCount(o.Count)) 81 if err != nil { 82 return fmt.Errorf("failed to create gpio transmitter: %v", err) 83 } 84 defer transmitter.Close() 85 86 ctx, cancel := context.WithCancel(context.Background()) 87 defer cancel() 88 89 go handleSignals(cancel) 90 91 log.WithFields(log.Fields{ 92 "pulseLength": o.PulseLength, 93 "protocol": o.Protocol, 94 "delay": o.Delay, 95 "count": o.Count, 96 }).Infof("starting transmission") 97 98 Loop: 99 for _, code := range codes { 100 log.Infof("transmitting code %d", code) 101 102 select { 103 case <-transmitter.Transmit(code, proto, o.PulseLength): 104 select { 105 case <-time.After(o.Delay): 106 case <-ctx.Done(): 107 return nil 108 } 109 110 case <-ctx.Done(): 111 return nil 112 } 113 } 114 115 if o.Infinite { 116 goto Loop 117 } 118 119 return nil 120 }