It is fairly dumb, but it allows to make more sense of what is going on over the wires while using EIZO software.
This commit is contained in:
parent
781fd392fe
commit
be50fd4b8f
212
eizo-pcap-decode.go
Normal file
212
eizo-pcap-decode.go
Normal file
@ -0,0 +1,212 @@
|
||||
// Usage: tshark { -r FILE | -i INTERFACE } -l -T ek \
|
||||
// | go run eizo-pcap-decode.go [ | less -R]
|
||||
//
|
||||
// This cannot be done through -T json, because tshark doesn't immediately
|
||||
// flush the current object's trailing newline, but rather waits to decide
|
||||
// if it should follow it with a comma. Even with -l, it will flush it late.
|
||||
// It would be good if we could convince it not to wrap packets in a big array.
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Packet struct {
|
||||
Layers struct {
|
||||
USB struct {
|
||||
Source string `json:"usb_usb_src"`
|
||||
Destination string `json:"usb_usb_dst"`
|
||||
Direction string `json:"usb_usb_endpoint_address_direction"`
|
||||
MacEndpointType string `json:"usb_usb_darwin_endpoint_type"`
|
||||
TransferType string `json:"usb_usb_transfer_type"`
|
||||
} `json:"usb"`
|
||||
CapData string `json:"usb_usb_capdata"`
|
||||
ControlResponse string `json:"usb_usb_control_Response"`
|
||||
DataFragment string `json:"usb_usb_data_fragment"`
|
||||
} `json:"layers"`
|
||||
}
|
||||
|
||||
func (p *Packet) addr() string {
|
||||
if p.Layers.USB.Source == "host" {
|
||||
return p.Layers.USB.Destination
|
||||
} else {
|
||||
return p.Layers.USB.Source
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Packet) isInterrupt() bool {
|
||||
return p.Layers.USB.MacEndpointType == "3" ||
|
||||
p.Layers.USB.TransferType == "0x01"
|
||||
}
|
||||
|
||||
func (p *Packet) isControl() bool {
|
||||
return p.Layers.USB.MacEndpointType == "0" ||
|
||||
p.Layers.USB.TransferType == "0x02"
|
||||
}
|
||||
|
||||
func (p *Packet) isIncoming() bool {
|
||||
return p.Layers.USB.Direction == "1"
|
||||
}
|
||||
|
||||
func hexDecode(encoded string) []byte {
|
||||
decoded, err := hex.DecodeString(strings.ReplaceAll(encoded, ":", ""))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return decoded
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
||||
var (
|
||||
raw *bool
|
||||
le = binary.LittleEndian
|
||||
|
||||
fmtIn, fmtOut, fmtReset string
|
||||
)
|
||||
|
||||
func decodeSubreport(data []byte) string {
|
||||
if len(data) < 6 {
|
||||
return fmt.Sprintf("%x", data)
|
||||
}
|
||||
usage := uint32(le.Uint16(data[:2]))<<16 | uint32(le.Uint16(data[2:4]))
|
||||
filtered := make([]byte, len(data)-6)
|
||||
for i, b := range data[6:] {
|
||||
if b < 32 || b > 126 {
|
||||
filtered[i] = '.'
|
||||
} else {
|
||||
filtered[i] = b
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("<> %08x %04x %x %s", usage, le.Uint16(data[4:6]),
|
||||
data[6:], string(filtered))
|
||||
}
|
||||
|
||||
func decodeResult(data []byte) string {
|
||||
if len(data) < 7 {
|
||||
return fmt.Sprintf("%x", data)
|
||||
}
|
||||
usage := uint32(le.Uint16(data[:2]))<<16 | uint32(le.Uint16(data[2:4]))
|
||||
return fmt.Sprintf(">< %08x %04x %02x", usage, le.Uint16(data[4:6]),
|
||||
data[6])
|
||||
}
|
||||
|
||||
func decodeMP(data []byte) string {
|
||||
var out string
|
||||
for i := 0; i+1 < len(data); {
|
||||
sz := int(data[i+1])
|
||||
if data[i] == 0xff || i+sz > len(data) {
|
||||
break
|
||||
}
|
||||
if out != "" {
|
||||
out += " "
|
||||
}
|
||||
out += fmt.Sprintf("[%02x] %x", data[i], data[i+2:i+2+sz])
|
||||
i += 2 + sz
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func isSetSubreport(id byte) bool {
|
||||
switch id {
|
||||
case 2, 4, 11, 13:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isGetSubreport(id byte) bool {
|
||||
switch id {
|
||||
case 3, 5, 12, 14:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func isSubreport(id byte) bool {
|
||||
return isSetSubreport(id) || isGetSubreport(id)
|
||||
}
|
||||
|
||||
func processInterrupt(p *Packet) {
|
||||
data := hexDecode(p.Layers.CapData)
|
||||
if len(data) < 1 {
|
||||
return
|
||||
}
|
||||
if *raw {
|
||||
fmt.Printf("%s INT %02x %x\n", p.addr(), data[0], data[1:])
|
||||
} else if isSubreport(data[0]) {
|
||||
fmt.Printf("%s INT %s\n", p.addr(), decodeSubreport(data[1:]))
|
||||
}
|
||||
}
|
||||
|
||||
func processControl(p *Packet) {
|
||||
// macOS (Darwin) and Linux report Set_Feature differently.
|
||||
data := hexDecode(p.Layers.ControlResponse)
|
||||
if len(data) == 0 {
|
||||
data = hexDecode(p.Layers.DataFragment)
|
||||
}
|
||||
if len(data) < 1 {
|
||||
return
|
||||
}
|
||||
if p.isIncoming() {
|
||||
if *raw {
|
||||
fmt.Printf("%s IN %02x %x\n", p.addr(), data[0], data[1:])
|
||||
} else if data[0] == 1 {
|
||||
fmt.Printf("%s IN SR %x\n", p.addr(), data[5:])
|
||||
} else if isGetSubreport(data[0]) {
|
||||
fmt.Printf("%s IN %s%s%s\n", p.addr(),
|
||||
fmtIn, decodeSubreport(data[1:]), fmtReset)
|
||||
} else if data[0] == 6 {
|
||||
fmt.Printf("%s IN PC %04x\n", p.addr(), le.Uint16(data[1:]))
|
||||
} else if data[0] == 7 {
|
||||
fmt.Printf("%s IN %s\n", p.addr(), decodeResult(data[1:]))
|
||||
} else if data[0] == 8 {
|
||||
fmt.Printf("%s IN ID %s %s\n", p.addr(), data[1:9], data[9:])
|
||||
} else if data[0] == 9 {
|
||||
fmt.Printf("%s IN MP %s\n", p.addr(), decodeMP(data[1:]))
|
||||
} else {
|
||||
fmt.Printf("%s IN %02x %x\n", p.addr(), data[0], data[1:])
|
||||
}
|
||||
} else {
|
||||
if *raw {
|
||||
fmt.Printf("%s OUT %02x %x\n", p.addr(), data[0], data[1:])
|
||||
} else if isSetSubreport(data[0]) {
|
||||
fmt.Printf("%s OUT %s%s%s\n", p.addr(),
|
||||
fmtOut, decodeSubreport(data[1:]), fmtReset)
|
||||
} else if data[0] != 1 && !isGetSubreport(data[0]) {
|
||||
fmt.Printf("%s OUT %02x %x\n", p.addr(), data[0], data[1:])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
raw = flag.Bool("raw", false, "Do not decode EIZO packets")
|
||||
flag.Parse()
|
||||
|
||||
if _, ok := os.LookupEnv("NO_COLOR"); !ok {
|
||||
fmtIn, fmtOut, fmtReset = "\x1b[34m", "\x1b[31m", "\x1b[m"
|
||||
}
|
||||
|
||||
decoder := json.NewDecoder(os.Stdin)
|
||||
for {
|
||||
var p Packet
|
||||
if err := decoder.Decode(&p); err != nil {
|
||||
if errors.Is(err, io.EOF) {
|
||||
break
|
||||
}
|
||||
fmt.Fprintf(os.Stderr, "%v\n", err)
|
||||
} else if p.isInterrupt() {
|
||||
processInterrupt(&p)
|
||||
} else if p.isControl() {
|
||||
processControl(&p)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user