Prechádzať zdrojové kódy

Initial working revision

blackwine 4 týždňov pred
commit
4dbf91764d
7 zmenil súbory, kde vykonal 250 pridanie a 0 odobranie
  1. 9 0
      .gitignore
  2. 15 0
      Makefile
  3. 83 0
      README.md
  4. 8 0
      go.mod
  5. 4 0
      go.sum
  6. BIN
      rid
  7. 131 0
      rid.go

+ 9 - 0
.gitignore

@@ -0,0 +1,9 @@
+# compiled artifacts
+build/*
+
+# vim temporaries
+*.sw[p|o|n]
+
+# system metadata
+.zfs
+.DS_Store

+ 15 - 0
Makefile

@@ -0,0 +1,15 @@
+dir_guard=@mkdir -p $(@D)
+
+all: rid 
+
+rid: $(wildcard **.go)
+	go build .
+
+put: build/rid.linux_arm
+
+build/rid.linux_arm: $(wildcard **.go)
+	$(dir_guard)
+	GOOS=linux GOARCH=arm go build -o build/rid.linux_arm .
+	ssh 3bees.local '[ -f /usr/local/bin/rid ] && mv /usr/local/bin/rid /usr/local/bin/rid.retired || true'
+	scp $@ 3bees.local:/usr/local/bin/rid
+	osc-utility message --host 3bees.local --port 9137 --address /8bus/amp/halt

+ 83 - 0
README.md

@@ -0,0 +1,83 @@
+RId
+===
+
+Onkyo RI (Remote Interactive) interface control daemon.
+
+The Interface
+-------------
+
+The Onkyo RI (Remote Interactive) interface has been designed for wired remote control communication between various Onkyo devices, such as AV receivers, CD and DVD players, HDD's and other home entertainment appliances. Devices use simple protocol to communicate directly over the wire without relying on infrared (IR) signals. Although set of commands is very limited it can be still very useful for switching inputs.
+
+Protocol has been reverse engineered and [documented](http://lirc.sourceforge.net/remotes/onkyo/Remote_Interactive). Some information found on the internet can be imprecise, incomplete and details can differ between different hardware.
+
+This little daemon is intended to run on Raspberry PI. You need to connect PIN 26 on RPi's GPIO header to RI jack tip and ground to the RI jack sleeve. It is OK to use stereo jack.
+
+Daemon runs OSC server on port UDP port 9137 and listens for incoming [OSC](https://opensoundcontrol.stanford.edu) messages on port 9137. Recognized addresses triggers sending commands via Onkyo's RI proprietary interface.
+
+Example
+-------
+
+Raw codes cand be send using `@osc` tool like this:
+
+```sh
+athost=$RI_CONTROLLER @osc /8bus/amp/code 0x20
+```
+
+Give me the Codes
+-----------------
+
+These are tested on Onkyo TX-SR504e and TX-SR674e. 
+
+action                 | code    | OSC address             | OSC arguments
+---------------------- | ------- | ----------------------- | -----------------
+Select Input CD        | `0x020` | `/8bus/amp/input/cd`    |
+Select Input MD        | `0x030` | `/8bus/amp/input/md`    |
+Select Input TAPE      | `0x070` | `/8bus/amp/input/tape`  |
+Select Input DVD       | `0x120` | `/8bus/amp/input/dvd`   |
+Select Input CDR       | `0x130` | `/8bus/amp/input/cdr`   |
+Select Input HDD       | `0x170` | `/8bus/amp/input/hdd`   |
+Select Input Video*    | `0x1a0` | `/8bus/amp/input/video` |
+Volume `+`             | `0x1a2` | `/8bus/amp/vol/up`      |
+Volume `-`             | `0x1a3` | `/8bus/amp/vol/down`    |
+Volume mute            | `0x1a4` | `/8bus/amp/vol/mute`    |
+Volume unmute          | `0x1a5` | `/8bus/amp/vol/unmute`  |
+AMP Standby            | `0x1ae` | `/8bus/amp/power/off`   |
+Input Video + wake up  | `0x1ae` | `/8bus/amp/power/on`    |
+Dimmer brightness Hi   | `0x2b0` |                         |
+Dimmer brightness Mid  | `0x2b1` |                         |
+Dimmer brightness Lo   | `0x2b2` |                         |
+Dimmer brightness Hi   | `0x2b8` |                         |
+Dimmer brightness Lo   | `0x2bf` |                         |
+Test mode 1            | `0x421` |                         |
+Test mode 2            | `0x422` |                         |
+Test mode 3            | `0x423` |                         |
+Test mode 4            | `0x424` |                         |
+
+* Please refer to the manual on which video port input will be selected
+
+These hasn't been confirmed yet
+
+Radio search next      | `0x430` | Tune next radio station when radio is selected.
+Radio search previous  | `0x431` | Tune previous radio station when radio is selected.
+Radio Stereo/Mono      | `0x432` | Switch between Stereo and Mono when FM radio is selected.
+Radio station next     | `0x433` | Jump to next stored radio station when radio is selected.
+Radio station previous | `0x434` | Jump to previous stored radio station when radio is selected.
+
+### Sending code
+
+You will need tool that sends OSC messages
+
+### Limitations
+
+As you can see is number of commands is quite limited. It was designed to allow some other Onkyo hardware to control. 
+On tested amplituners you can only switch between two video (DVD and one of video inputs marked in manual) and two audio inputs. Additionally you can switch input to HDD, CDR or MD, but this can be done only by assigning switchable video input and there is no way around that.
+
+### Useful links
+
+ - http://lirc.sourceforge.net/remotes/onkyo/Remote_Interactive
+ - http://fredboboss.free.fr/articles/onkyo_ri.php
+ - http://www.intl.onkyo.com/downloads/manuals/pdf/tx-sr504_manual_e.pdf
+ - https://github.com/mkulesh/onkyoUsbRi
+
+Some information found online has been tested and corrected here.
+

+ 8 - 0
go.mod

@@ -0,0 +1,8 @@
+module decrunch.org/8bus/rid
+
+go 1.22.4
+
+require (
+	github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5 // indirect
+	github.com/stianeikeland/go-rpio/v4 v4.6.0 // indirect
+)

+ 4 - 0
go.sum

@@ -0,0 +1,4 @@
+github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5 h1:fqwINudmUrvGCuw+e3tedZ2UJ0hklSw6t8UPomctKyQ=
+github.com/hypebeast/go-osc v0.0.0-20220308234300-cec5a8a1e5f5/go.mod h1:lqMjoCs0y0GoRRujSPZRBaGb4c5ER6TfkFKSClxkMbY=
+github.com/stianeikeland/go-rpio/v4 v4.6.0 h1:eAJgtw3jTtvn/CqwbC82ntcS+dtzUTgo5qlZKe677EY=
+github.com/stianeikeland/go-rpio/v4 v4.6.0/go.mod h1:A3GvHxC1Om5zaId+HqB3HKqx4K/AqeckxB7qRjxMK7o=


+ 131 - 0
rid.go

@@ -0,0 +1,131 @@
+package main
+
+import "time"
+import "log"
+import "fmt"
+import "os"
+import "os/signal"
+import "syscall"
+import "github.com/stianeikeland/go-rpio/v4"
+import "github.com/hypebeast/go-osc/osc"
+
+const (
+	// TX series codes
+	AMP_Input_CD    = 0x020 // ATEM
+	AMP_Input_MD    = 0x030
+	AMP_Input_Tape  = 0x070
+	AMP_Input_DVD   = 0x120
+	AMP_Input_CDR   = 0x130 // Assigned to tape by holding button for 3 secs
+	AMP_Input_HDD   = 0x170 // Assigned to video or tape by holding button for 3 secs
+	AMP_Input_Video = 0x1a0
+
+	AMP_PowerOn_OrMask = 0x0f
+
+	// These work only when video input is selected
+	AMP_Vol_up     = 0x1a2
+	AMP_Vol_down   = 0x1a3
+	AMP_Vol_mute   = 0x1a4
+	AMP_Vol_unmute = 0x1a5
+	AMP_Off        = 0x1ae
+	AMP_On         = 0x1af
+
+	// Dimmer
+	AMP_DimmerHi  = 0x2b0
+	AMP_DimmerMid = 0x2b1
+	AMP_DimmerLo  = 0x2b2
+
+	// Test modes
+	Test_mode = 0x421
+)
+
+type IR struct {
+	pin rpio.Pin
+}
+
+func NewIR() *IR {
+	if err := rpio.Open(); err != nil {
+		log.Fatal(err)
+	}
+	//defer rpio.Close()
+
+	pin := rpio.Pin(26)
+	pin.Output() // Output mode
+	return &IR{pin}
+}
+
+// Encode a bit of IR information
+func (ir *IR) sendHiLo(hi time.Duration, lo time.Duration) {
+	ir.pin.High()
+	time.Sleep(hi * time.Millisecond)
+
+	ir.pin.Low()
+	time.Sleep(lo * time.Millisecond)
+}
+
+func (ir *IR) sendCode(code int) {
+	// Send header
+	ir.sendHiLo(3, 1)
+
+	// Send 12 bits of command
+	for mask := 0x800; mask != 0; mask >>= 1 {
+		if code&mask != 0 {
+			ir.sendHiLo(1, 2) // 1
+		} else {
+			ir.sendHiLo(1, 1) // 0
+		}
+	}
+
+	// Send end gap
+	ir.sendHiLo(1, 21)
+	fmt.Printf("Sent code: %03x\n", code)
+}
+
+func getOSCInt(msg *osc.Message) int32 {
+	for _, arg := range msg.Arguments {
+		switch arg.(type) {
+		case int32:
+			return arg.(int32)
+		}
+	}
+	return 0
+}
+
+func main() {
+	ir := NewIR()
+
+	// Setup and spawn the OSC server
+	addr := "0.0.0.0:9137"
+	d := osc.NewStandardDispatcher()
+
+	d.AddMsgHandler("/8bus/amp/input/tape", func(msg *osc.Message) { ir.sendCode(AMP_Input_Tape) })
+	d.AddMsgHandler("/8bus/amp/input/md", func(msg *osc.Message) { ir.sendCode(AMP_Input_MD) })
+	d.AddMsgHandler("/8bus/amp/input/cd", func(msg *osc.Message) { ir.sendCode(AMP_Input_CD) })
+	d.AddMsgHandler("/8bus/amp/input/cdr", func(msg *osc.Message) { ir.sendCode(AMP_Input_CDR) })
+	d.AddMsgHandler("/8bus/amp/input/dvd", func(msg *osc.Message) { ir.sendCode(AMP_Input_DVD) })
+	d.AddMsgHandler("/8bus/amp/input/hdd", func(msg *osc.Message) { ir.sendCode(AMP_Input_HDD) })
+	d.AddMsgHandler("/8bus/amp/input/video", func(msg *osc.Message) { ir.sendCode(AMP_Input_Video) })
+	d.AddMsgHandler("/8bus/amp/vol/up", func(msg *osc.Message) { ir.sendCode(AMP_Vol_up) })
+	d.AddMsgHandler("/8bus/amp/vol/down", func(msg *osc.Message) { ir.sendCode(AMP_Vol_down) })
+	d.AddMsgHandler("/8bus/amp/vol/mute", func(msg *osc.Message) { ir.sendCode(AMP_Vol_mute) })
+	d.AddMsgHandler("/8bus/amp/vol/unmute", func(msg *osc.Message) { ir.sendCode(AMP_Vol_unmute) })
+	d.AddMsgHandler("/8bus/amp/power/on", func(msg *osc.Message) { ir.sendCode(AMP_On) })
+	d.AddMsgHandler("/8bus/amp/power/off", func(msg *osc.Message) { ir.sendCode(AMP_Off) })
+	d.AddMsgHandler("/8bus/amp/code", func(msg *osc.Message) { ir.sendCode(int(getOSCInt(msg))) })
+
+	// Set up and start OSC server
+	go func() {
+		server := &osc.Server{Addr: addr, Dispatcher: d}
+		if err := server.ListenAndServe(); err != nil {
+			log.Fatal("error: ", err.Error())
+		}
+	}()
+
+	// Wait for signal
+	ch := make(chan os.Signal, 1)
+	signal.Notify(ch, syscall.SIGHUP, syscall.SIGINT, syscall.SIGQUIT)
+
+	d.AddMsgHandler("/8bus/amp/halt", func(msg *osc.Message) { ch <- syscall.SIGINT })
+	<-ch
+
+	fmt.Println("sent")
+}