diff --git a/cmd/main.go b/cmd/main.go index be793d1..c1ca9fa 100755 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,4 +1,4 @@ -/* +/* MIT License Copyright (c) 2021 Justin Hammond @@ -26,26 +26,55 @@ package main import ( "context" - "log" + "flag" + "fmt" + "os" "time" "github.com/Fishwaldo/go-dcdc200" + "github.com/Fishwaldo/go-dcdc200/internal/sim" + "github.com/Fishwaldo/go-logadapter/loggers/std" ) func main() { + var simulation = flag.Bool("s", false, "Enable Simulation Mode") + var capture = flag.Bool("c", false, "Enable Packet Capture") + var help = flag.Bool("h", false, "Help") + flag.Parse() + if *help { + flag.PrintDefaults() + os.Exit(0) + } + dc := dcdcusb.DcDcUSB{} - dc.Init() + if *simulation { + if err := sim.SetCaptureFile("dcdcusb.txt"); err != nil { + fmt.Printf("Can't open Capture File dcdcusb.txt: %s\n", err) + os.Exit(-1) + } + } + dc.Init(stdlogger.DefaultLogger(), *simulation) + + if *capture { + if *simulation { + fmt.Printf("Can't Enable Capture in Simulation Mode\n") + os.Exit(-1) + } + dc.SetCapture(*capture) + } + + if ok, err := dc.Scan(); !ok { - log.Fatalf("Scan Failed: %v", err) - return + fmt.Printf("Scan Failed: %v\n", err) + os.Exit(-1) } defer dc.Close() - for i := 0; i < 100; i++ { + for i := 0; i < 1000000; i++ { ctx, cancel := context.WithTimeout(context.Background(), (1 * time.Second)) dc.GetAllParam(ctx) cancel() time.Sleep(1 * time.Second) } - dc.Close() + os.Exit(0) } diff --git a/dcdcusb.go b/dcdcusb.go index eaaf6f1..3c49d53 100755 --- a/dcdcusb.go +++ b/dcdcusb.go @@ -1,4 +1,4 @@ -/* +/* MIT License Copyright (c) 2021 Justin Hammond @@ -28,22 +28,29 @@ import ( "context" "errors" "fmt" - "sync" + "os" "time" + "github.com/Fishwaldo/go-dcdc200/internal" + "github.com/Fishwaldo/go-dcdc200/internal/realusb" + "github.com/Fishwaldo/go-dcdc200/internal/sim" "github.com/Fishwaldo/go-logadapter" - "github.com/Fishwaldo/go-logadapter/loggers/std" - "github.com/google/gousb" ) + +type usbifI interface { + SetUSBDebug(level int) + Scan() (bool, error) + Close() + GetAllParam(ctx context.Context) ([]byte, int, error) +} + // Main Structure for the DCDCUSB Communications type DcDcUSB struct { - ctx *gousb.Context - dev *gousb.Device - intf *gousb.Interface - done func() - log logadapter.Logger - initOnce sync.Once - connected bool + log logadapter.Logger + connected bool + captureData bool + simulation bool + usbif usbifI } // Represents the Settings for Off and Hardoff Delays when power is lost @@ -51,190 +58,143 @@ type TimerConfigt struct { // After Ignition Lost, this the time waiting till we toggle the Power Switch I/F OffDelay time.Duration `json:"off_delay"` // After the Power Switch I/F is toggled, this is the delay before we cut power - HardOff time.Duration `json:"hard_off"` + HardOff time.Duration `json:"hard_off"` } // Status of Various Peripherals type Peripheralst struct { // ?? - OutSwVin bool `json:"out_sw_vin"` + OutSwVin bool `json:"out_sw_vin"` // ?? - OutPsw bool `json:"out_psw"` + OutPsw bool `json:"out_psw"` // ?? OutStartOutput bool `json:"out_start_output"` // Status of the Onboard Led - OutLed bool `json:"out_led"` - // If the VOut is within range. + OutLed bool `json:"out_led"` + // If the VOut is within range. InVoutGood bool `json:"in_vout_good"` } // Overall Status of the DCDCUSB Power Supply type Params struct { // What the Vout Setting is configured for - VoutSet float32 `json:"vout_set"` + VoutSet float32 `json:"vout_set"` // What Voltage the Config Jumpers are set for VOut - VoutConfig float32 `json:"vout_config"` + VoutConfig float32 `json:"vout_config"` // The Input Voltage - Vin float32 `json:"vin"` + Vin float32 `json:"vin"` // The Ignition Voltage - Vign float32 `json:"vign"` + Vign float32 `json:"vign"` // What the Actual VOut Voltage is - VoutActual float32 `json:"vout_actual"` + VoutActual float32 `json:"vout_actual"` // Status of Various Peripherals - Peripherals Peripheralst `json:"peripherals"` + Peripherals Peripheralst `json:"peripherals"` // ?? (Not Output Enabled?) - Output bool `json:"output"` + Output bool `json:"output"` // ?? - AuxVIn bool `json:"aux_v_in"` + AuxVIn bool `json:"aux_v_in"` // Firmware Version? - Version string `json:"version"` + Version string `json:"version"` // State of the Power Supply - State DcdcStatet `json:"state"` + State DcdcStatet `json:"state"` // Config Registers (unknown) - CfgRegisters byte `json:"cfg_registers"` + CfgRegisters byte `json:"cfg_registers"` // Voltage Flags (Unknown) - VoltFlags byte `json:"volt_flags"` + VoltFlags byte `json:"volt_flags"` // Timer Flags (Unknown) - TimerFlags byte `json:"timer_flags"` + TimerFlags byte `json:"timer_flags"` // The configured countdown times for the Timer upon Power Loss TimerConfig TimerConfigt `json:"timer_config"` // Current Power Loss Debounce Timer - TimerWait time.Duration `json:"timer_wait"` + TimerWait time.Duration `json:"timer_wait"` // Current VOut Countdown Timer - TimerVOut time.Duration `json:"timer_v_out"` + TimerVOut time.Duration `json:"timer_v_out"` // Current VAux Countdown timer - TimerVAux time.Duration `json:"timer_v_aux"` + TimerVAux time.Duration `json:"timer_v_aux"` // Current Power Switch Toggle Count Down Timer - TimerPRWSW time.Duration `json:"timer_prwsw"` + TimerPRWSW time.Duration `json:"timer_prwsw"` // Current Soft Off Countdown Timer - TimerSoftOff time.Duration `json:"timer_soft_off"` + TimerSoftOff time.Duration `json:"timer_soft_off"` // Current Hard Off Countdown Timer - TimerHardOff time.Duration `json:"timer_hard_off"` - // Current Script Position - ScriptPointer byte `json:"script_pointer"` + TimerHardOff time.Duration `json:"timer_hard_off"` + // Current Script Position + ScriptPointer byte `json:"script_pointer"` // Current Operating Mode - Mode DcdcModet `json:"mode"` -} -// Initialize the DCDCUSB Communications. Should be first function called before any other methods are called -func (dc *DcDcUSB) Init() { - dc.initOnce.Do(func() { - if dc.log == nil { - templogger := stdlogger.DefaultLogger() - templogger.Log.SetPrefix("DCDCUSB") - dc.log = templogger - } - }) - dc.connected = false - dc.ctx = gousb.NewContext() + Mode DcdcModet `json:"mode"` } -// Set a Custom Logger based on https://github.com/Fishwaldo/go-logadapter -// If not set, then the Library will use the Std Library Logger -func (dc *DcDcUSB) SetLogger(log logadapter.Logger) { +// Initialize the DCDCUSB Communications. Should be first function called before any other methods are called +// Pass a logadapter.Logger as the logger for this package and set simulation to true if you wish to reply a Captured Session instead of +// live data. +func (dc *DcDcUSB) Init(log logadapter.Logger, simulation bool) { dc.log = log + dc.connected = false + dc.simulation = simulation + if !simulation { + dc.usbif = realusb.Init(dc.log) + } else { + dc.usbif = sim.Init(dc.log) + } +} + +// Capture Data from the Power Supply and save it to dcdcusb.txt for replay via the simulator later +func (dc *DcDcUSB) SetCapture(enabled bool) { + dc.captureData = true } // Set the debug level for the GoUSB Library func (dc *DcDcUSB) SetUSBDebug(level int) { - if dc.ctx != nil { - dc.ctx.Debug(level) - } + dc.usbif.SetUSBDebug(level) } + // Returns if we are connected to the Power Supply -func (dc *DcDcUSB) IsConnected() (bool) { +func (dc *DcDcUSB) IsConnected() bool { return dc.connected } // Scan for a DCDCUSB connection, returns true if found, or false (and optional error) if there -// was a failure setting up communications with it. +// was a failure setting up communications with it. func (dc *DcDcUSB) Scan() (bool, error) { var err error - dc.dev, err = dc.ctx.OpenDeviceWithVIDPID(dcdc200_vid, dcdc200_pid) - if err != nil { - dc.log.Warn("Could Not Open Device: %v", err) - dc.Close() - return false, err - } - if dc.dev == nil { - dc.log.Warn("Can't Find Device") - dc.Close() - return false, nil - } - err = dc.dev.SetAutoDetach(true) - if err != nil { - dc.log.Error("%s.SetAutoDetach(true): %v", dc.dev, err) - } - - confignum, _ := dc.dev.ActiveConfigNum() - dc.log.Trace("Device Config: %s %d", dc.dev.String(), confignum) - // desc, _ := dc.dev.GetStringDescriptor(1) - // manu, _ := dc.dev.Manufacturer() - // prod, _ := dc.dev.Product() - // serial, _ := dc.dev.SerialNumber() - dc.intf, dc.done, err = dc.dev.DefaultInterface() - if err != nil { - dc.log.Error("%s.Interface(): %v", dc.dev, err) - dc.Close() - return false, err - } - dc.log.Trace("Interface: %s", dc.intf.String()) - dc.log = dc.log.With("Device", dc.intf.String()) - dc.connected = true - return true, nil + dc.connected, err = dc.usbif.Scan() + return dc.connected, err } func (dc *DcDcUSB) Close() { - if dc.intf != nil { - dc.done() - dc.intf.Close() - } - if dc.dev != nil { - dc.dev.Close() - } - if dc.ctx != nil { - dc.ctx.Close() - } - dc.connected = false; + dc.usbif.Close() + dc.connected = false } -// Gets All current Params from the DCDCUSB power Supply. +// Gets All current Params from the DCDCUSB power Supply. // Set a Timeout/Deadline Context to cancel slow calls func (dc *DcDcUSB) GetAllParam(ctx context.Context) (Params, error) { - if dc.intf == nil { - dc.log.Warn("Interface Not Opened") - return Params{}, fmt.Errorf("Interface Not Opened") - } - outp, err := dc.intf.OutEndpoint(0x01) + recv, len, err := dc.usbif.GetAllParam(ctx) if err != nil { - dc.log.Warn("Can't Get OutEndPoint: %s", err) + dc.log.Warn("GetAllParams Call Failed: %s", err) return Params{}, err } - //log.Printf("OutEndpoint: %v", outp) - var send = make([]byte, 24) - send[0] = cmdGetAllValues - //send = append(send, 0) - //log.Printf("About to Send %v", send) - len, err := outp.WriteContext(ctx, send) - if err != nil { - dc.log.Warn("Cant Send GetAllValues Command: %s (%v) - %d", err, send, len) - return Params{}, err + if len != 24 { + dc.log.Warn("Got Short Read From USB") + return Params{}, fmt.Errorf("got Short Read from USB") } - //log.Printf("Sent %d Bytes", len) - inp, err := dc.intf.InEndpoint(0x81) - if err != nil { - dc.log.Warn("Can't Get OutPoint: %s", err) - return Params{}, err - } - //log.Printf("InEndpoint: %v", inp) - var recv = make([]byte, 24) - len, err = inp.ReadContext(ctx, recv) - if err != nil { - dc.log.Warn("Can't Read GetAllValues Command: %s", err) - return Params{}, err + if dc.captureData { + if dc.simulation { + dc.log.Warn("Running in Simulation Mode, Can't Capture") + } else { + f, err := os.OpenFile("dcdcusb.txt", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) + if err != nil { + dc.log.Fatal("Can't open File for Capture: %s", err) + } + + if _, err := f.Write(recv); err != nil { + dc.log.Fatal("Can't write Text to File: %s", err) + } + f.Close() + } } - //log.Printf("Got %d Bytes", len) + dc.log.Trace("Got %v", recv) - params, err := dc.parseAllValues(recv, len) + params, err := dc.parseAllValues(recv) return params, err } @@ -245,9 +205,9 @@ func (dc *DcDcUSB) GetAllParam(ctx context.Context) (Params, error) { // 2021/09/20 16:12:54 Got [130 133 8 76 0 44 25 133 205 251 1 0 0 0 0 0 0 0 0 0 0 0 0 167] // 2021/09/20 16:12:56 Got [130 133 16 76 0 44 27 133 205 247 1 0 0 0 0 0 0 0 0 0 0 0 59 167] // 2021/09/20 16:13:54 Got [130 133 16 76 0 44 9 133 205 247 1 0 0 0 0 0 0 0 0 0 0 0 0 167] -func (dc *DcDcUSB) parseAllValues(buf []byte, len int) (Params, error) { +func (dc *DcDcUSB) parseAllValues(buf []byte) (Params, error) { switch buf[0] { - case cmdRecvAllValues: + case internal.CmdRecvAllValues: param := Params{} param.Mode = dc.modeToConst((buf[1] >> 6) & 0x7) param.VoutConfig = dc.voutConfigtoFloat((buf[1] >> 2) & 0x07) @@ -351,8 +311,8 @@ func (dc DcDcUSB) stateToConst(state byte) DcdcStatet { func (dc DcDcUSB) peripheralsState(state byte) Peripheralst { p := Peripheralst{ InVoutGood: ((state & 0x01) != 0), - OutLed: ((state & 0x02) != 0), - OutPsw: ((state & 0x04) != 0), + OutLed: ((state & 0x02) != 0), + OutPsw: ((state & 0x04) != 0), OutStartOutput: ((state & 0x08) != 0), OutSwVin: ((state & 0x10) != 0), } diff --git a/dcdcusb_test.go b/dcdcusb_test.go index 24291cf..407316c 100644 --- a/dcdcusb_test.go +++ b/dcdcusb_test.go @@ -27,13 +27,14 @@ package dcdcusb import ( "testing" "time" + "github.com/Fishwaldo/go-logadapter/loggers/std" ) func TestParseAllValues(t *testing.T) { var test1 = []byte{130, 133, 7, 76, 75, 43, 27, 133, 215, 251, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 68, 0, 0, 167} dc := DcDcUSB{} - dc.Init() - result, err := dc.parseAllValues(test1, 24) + dc.Init(stdlogger.DefaultLogger(), false) + result, err := dc.parseAllValues(test1) if err != nil { t.Fatalf("Error Returned from parseAllValues: %v", err) } @@ -108,8 +109,8 @@ func TestParseAllValues(t *testing.T) { func TestParseAllValues2(t *testing.T) { var test1 = []byte{130, 133, 8, 76, 0, 43, 27, 133, 205, 251, 1, 0, 0, 0, 0, 0, 0, 0, 0, 3, 127, 0, 0, 167} dc := DcDcUSB{} - dc.Init() - result, err := dc.parseAllValues(test1, 24) + dc.Init(stdlogger.DefaultLogger(), false) + result, err := dc.parseAllValues(test1) if err != nil { t.Fatalf("Error Returned from parseAllValues: %v", err) } @@ -184,8 +185,8 @@ func TestParseAllValues2(t *testing.T) { func TestParseAllValues3(t *testing.T) { var test1 = []byte{130, 133, 8, 76, 0, 44, 25, 133, 205, 251, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167} dc := DcDcUSB{} - dc.Init() - result, err := dc.parseAllValues(test1, 24) + dc.Init(stdlogger.DefaultLogger(), false) + result, err := dc.parseAllValues(test1) if err != nil { t.Fatalf("Error Returned from parseAllValues: %v", err) } @@ -259,8 +260,8 @@ func TestParseAllValues3(t *testing.T) { func TestParseAllValues4(t *testing.T) { var test1 = []byte{130, 133, 16, 76, 0, 44, 27, 133, 205, 247, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 167} dc := DcDcUSB{} - dc.Init() - result, err := dc.parseAllValues(test1, 24) + dc.Init(stdlogger.DefaultLogger(),false) + result, err := dc.parseAllValues(test1) if err != nil { t.Fatalf("Error Returned from parseAllValues: %v", err) } @@ -335,8 +336,8 @@ func TestParseAllValues4(t *testing.T) { func TestParseAllValues5(t *testing.T) { var test1 = []byte{130, 133, 16, 76, 0, 44, 9, 133, 205, 247, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167} dc := DcDcUSB{} - dc.Init() - result, err := dc.parseAllValues(test1, 24) + dc.Init(stdlogger.DefaultLogger(), false) + result, err := dc.parseAllValues(test1) if err != nil { t.Fatalf("Error Returned from parseAllValues: %v", err) } diff --git a/dcdcusbexample_test.go b/dcdcusbexample_test.go index efb9ccc..4afa1f0 100644 --- a/dcdcusbexample_test.go +++ b/dcdcusbexample_test.go @@ -6,11 +6,12 @@ import ( "time" "github.com/Fishwaldo/go-dcdc200" + "github.com/Fishwaldo/go-logadapter/loggers/std" ) func Example() { dc := dcdcusb.DcDcUSB{} - dc.Init() + dc.Init(stdlogger.DefaultLogger(), false) if ok, err := dc.Scan(); !ok { log.Fatalf("Scan Failed: %v", err) return diff --git a/definitions.go b/definitions.go index ea496c3..ee9ea54 100755 --- a/definitions.go +++ b/definitions.go @@ -24,89 +24,9 @@ SOFTWARE. package dcdcusb -const ( - dcdc200_vid = 0x04d8 - dcdc200_pid = 0xd003 -) -const ( - statusOK = 0x00 - statusErase = 0x01 - statusWrite = 0x02 - statusRead = 0x03 - statusError = 0xFF -) -const ( - cmdGetAllValues = 0x81 - cmdRecvAllValues = 0x82 - cmdOut = 0xB1 - cmdIn = 0xB2 - cmdReadOut = 0xA1 - cmdReadIn = 0xA2 - cmdWriteOut = 0xA3 - cmdWriteIn = 0xA4 - cmdErase = 0xA5 -) -const ( - msgInternal = 0xFF - msgInternalDisconnected = 0x01 -) - -const ( - cmdSetAuxWin = 0x01 - cmdSetPwSwitch = 0x02 - cmdSetOutput = 0x03 - cmdWriteVout = 0x06 - cmdReadVout = 0x07 - cmdIncVout = 0x0C - cmdDecVout = 0x0D - cmdLoadDefaults = 0x0E - cmdScriptStart = 0x10 - cmdScriptStop = 0x11 - cmdSleep = 0x12 - cmdReadRegulatorStep = 0x13 -) - -const ( - typeCodeMemory = 0x00 - typeEepromExternal = 0x01 - typeEepromInternal = 0x02 - typeCodeSplash = 0x03 -) - -const ( - flashReportEraseMemory = 0xF2 /* AddressLo : AddressHi : AddressUp (anywhere inside the 64 byte-block to be erased) */ - flashReportReadMemory = 0xF3 /* AddressLo : AddressHi : AddressUp : Data Length (1...32) */ - flashReportWriteMemory = 0xF4 /* AddressLo : AddressHi : AddressUp : Data Length (1...32) : Data.... */ - keyBdReportEraseMemory = 0xB2 /* same as F2 but in keyboard mode */ - keybdReportReadMemory = 0xB3 /* same as F3 but in keyboard mode */ - keybdReportWriteMemory = 0xB4 /* same as F4 but in keyboard mode */ - keybdReportMemory = 0x41 /* response to b3,b4 */ -) - -const ( - inReportExtEEData = 0x31 - outReportExtEERead = 0xA1 - outReportExtEEWrite = 0xA2 - inReportIntEEData = 0x32 - outReportIntEERead = 0xA3 - outReportIntEEWrite = 0xA4 -) - -/* MEASUREMENT CONSTANTS */ - -const ( - ct_RW = 75 - ct_R1 = 49900 - ct_R2 = 1500 - ct_RP = 10000 -) - -const check_char = 0xAA /* used for line/write check */ - -const max_message_cnt = 64 //go:generate stringer -type=DcdcModet type DcdcModet int diff --git a/doc.go b/doc.go index dfc1a25..a6010ac 100644 --- a/doc.go +++ b/doc.go @@ -30,5 +30,10 @@ it depends upon GoUSB which in turn depends upon the libusb C library, thus CGO Please see the GoUSB pages for hints on compiling for platforms other than linux +Building + +Compile with the tag nogousb to disable compiling with USB Support. Then the only option available +is a Simulator Mode that replays a previously captured session. + */ package dcdcusb diff --git a/internal/definitions.go b/internal/definitions.go new file mode 100644 index 0000000..c4d7aa3 --- /dev/null +++ b/internal/definitions.go @@ -0,0 +1,80 @@ +package internal + +const ( + statusOK = 0x00 + statusErase = 0x01 + statusWrite = 0x02 + statusRead = 0x03 + statusError = 0xFF +) + +const ( + CmdGetAllValues = 0x81 + CmdRecvAllValues = 0x82 + CmdOut = 0xB1 + CmdIn = 0xB2 + CmdReadOut = 0xA1 + CmdReadIn = 0xA2 + CmdWriteOut = 0xA3 + CmdWriteIn = 0xA4 + CmdErase = 0xA5 +) + +const ( + msgInternal = 0xFF + msgInternalDisconnected = 0x01 +) + +const ( + cmdSetAuxWin = 0x01 + cmdSetPwSwitch = 0x02 + cmdSetOutput = 0x03 + cmdWriteVout = 0x06 + cmdReadVout = 0x07 + cmdIncVout = 0x0C + cmdDecVout = 0x0D + cmdLoadDefaults = 0x0E + cmdScriptStart = 0x10 + cmdScriptStop = 0x11 + cmdSleep = 0x12 + cmdReadRegulatorStep = 0x13 +) + +const ( + typeCodeMemory = 0x00 + typeEepromExternal = 0x01 + typeEepromInternal = 0x02 + typeCodeSplash = 0x03 +) + +const ( + flashReportEraseMemory = 0xF2 /* AddressLo : AddressHi : AddressUp (anywhere inside the 64 byte-block to be erased) */ + flashReportReadMemory = 0xF3 /* AddressLo : AddressHi : AddressUp : Data Length (1...32) */ + flashReportWriteMemory = 0xF4 /* AddressLo : AddressHi : AddressUp : Data Length (1...32) : Data.... */ + keyBdReportEraseMemory = 0xB2 /* same as F2 but in keyboard mode */ + keybdReportReadMemory = 0xB3 /* same as F3 but in keyboard mode */ + keybdReportWriteMemory = 0xB4 /* same as F4 but in keyboard mode */ + keybdReportMemory = 0x41 /* response to b3,b4 */ +) + +const ( + inReportExtEEData = 0x31 + outReportExtEERead = 0xA1 + outReportExtEEWrite = 0xA2 + inReportIntEEData = 0x32 + outReportIntEERead = 0xA3 + outReportIntEEWrite = 0xA4 +) + +/* MEASUREMENT CONSTANTS */ + +const ( + ct_RW = 75 + ct_R1 = 49900 + ct_R2 = 1500 + ct_RP = 10000 +) + +const check_char = 0xAA /* used for line/write check */ + +const max_message_cnt = 64 diff --git a/internal/realusb/realusb.go b/internal/realusb/realusb.go new file mode 100644 index 0000000..7c33afc --- /dev/null +++ b/internal/realusb/realusb.go @@ -0,0 +1,122 @@ +// +build !nogousb + +package realusb + +import ( + "context" + "fmt" + + "github.com/Fishwaldo/go-dcdc200/internal" + "github.com/Fishwaldo/go-logadapter" + "github.com/google/gousb" +) + +const ( + dcdc200_vid = 0x04d8 + dcdc200_pid = 0xd003 +) + + +type UsbIF struct { + ctx *gousb.Context + dev *gousb.Device + intf *gousb.Interface + done func() + log logadapter.Logger +} + +func Init(log logadapter.Logger) (*UsbIF) { + usbif := UsbIF{log: log, ctx: gousb.NewContext()} + return &usbif +} + +func (usbif *UsbIF) SetUSBDebug(level int) { + if usbif.ctx != nil { + usbif.ctx.Debug(level) + } +} + +func (usbif *UsbIF) Scan() (bool, error) { + var err error + usbif.dev, err = usbif.ctx.OpenDeviceWithVIDPID(dcdc200_vid, dcdc200_pid) + if err != nil { + usbif.log.Warn("Could Not Open Device: %v", err) + usbif.Close() + return false, err + } + if usbif.dev == nil { + usbif.log.Warn("Can't Find Device") + usbif.Close() + return false, nil + } + err = usbif.dev.SetAutoDetach(true) + if err != nil { + usbif.log.Error("%s.SetAutoDetach(true): %v", usbif.dev, err) + } + + confignum, _ := usbif.dev.ActiveConfigNum() + usbif.log.Trace("Device Config: %s %d", usbif.dev.String(), confignum) + // desc, _ := dc.dev.GetStringDescriptor(1) + // manu, _ := dc.dev.Manufacturer() + // prod, _ := dc.dev.Product() + // serial, _ := dc.dev.SerialNumber() + usbif.intf, usbif.done, err = usbif.dev.DefaultInterface() + if err != nil { + usbif.log.Error("%s.Interface(): %v", usbif.dev, err) + usbif.Close() + return false, err + } + usbif.log.Trace("Interface: %s", usbif.intf.String()) + usbif.log = usbif.log.With("Device", usbif.intf.String()) + return true, nil +} + +func (usbif *UsbIF) Close() { + if usbif.intf != nil { + usbif.done() + usbif.intf.Close() + } + if usbif.dev != nil { + usbif.dev.Close() + } + if usbif.ctx != nil { + usbif.ctx.Close() + } +} + +func (usbif *UsbIF) GetAllParam(ctx context.Context) ([]byte, int, error) { + if usbif.intf == nil { + usbif.log.Warn("Interface Not Opened") + return nil, 0, fmt.Errorf("interface Not Opened") + } + outp, err := usbif.intf.OutEndpoint(0x01) + if err != nil { + usbif.log.Warn("Can't Get OutEndPoint: %s", err) + return nil, 0, err + } + //log.Printf("OutEndpoint: %v", outp) + var send = make([]byte, 24) + send[0] = internal.CmdGetAllValues + //send = append(send, 0) + //log.Printf("About to Send %v", send) + len, err := outp.WriteContext(ctx, send) + if err != nil { + usbif.log.Warn("Cant Send GetAllValues Command: %s (%v) - %d", err, send, len) + return nil, 0, err + } + //log.Printf("Sent %d Bytes", len) + inp, err := usbif.intf.InEndpoint(0x81) + if err != nil { + usbif.log.Warn("Can't Get OutPoint: %s", err) + return nil, 0, err + } + //log.Printf("InEndpoint: %v", inp) + + var recv = make([]byte, 24) + len, err = inp.ReadContext(ctx, recv) + if err != nil { + usbif.log.Warn("Can't Read GetAllValues Command: %s", err) + return nil, 0, err + } + return recv, len, nil +} \ No newline at end of file diff --git a/internal/realusb/realusb_nogousb.go b/internal/realusb/realusb_nogousb.go new file mode 100644 index 0000000..d0f1868 --- /dev/null +++ b/internal/realusb/realusb_nogousb.go @@ -0,0 +1,35 @@ +// +build nogousb + +package realusb + +import ( + "context" + "fmt" + "github.com/Fishwaldo/go-logadapter" +) + +type UsbIF struct { + log logadapter.Logger +} + +func Init(log logadapter.Logger) (*UsbIF) { + usbif := UsbIF{log: log} + log.Panic("Not Compiled with USB Support!") + return &usbif +} + +func (usbif *UsbIF) SetUSBDebug(level int) { + usbif.log.Panic("Not Compiled with USB Support!") +} + +func (usbif *UsbIF) Scan() (bool, error) { + usbif.log.Panic("Not Compiled with USB Support") + return false, fmt.Errorf("Not Compiled with USB Support") +} +func (usbif *UsbIF) Close() { + usbif.log.Panic("Not Compiled with USB Support") +} +func (usbif *UsbIF) GetAllParam(ctx context.Context) ([]byte, int, error) { + usbif.log.Panic("Not Compiled with USB Support") + return nil, 0, fmt.Errorf("not compiled with USB Support") +} \ No newline at end of file diff --git a/internal/sim/sim.go b/internal/sim/sim.go new file mode 100644 index 0000000..0f361de --- /dev/null +++ b/internal/sim/sim.go @@ -0,0 +1,82 @@ +package sim + +import ( + "context" + "fmt" + "io" + "os" + + "github.com/Fishwaldo/go-logadapter" +) + +type SimIF struct { + log logadapter.Logger + file *os.File +} + +var captureFile string + +func SetCaptureFile(name string) error { + file, err := os.Open(name) + if err != nil { + return err + } + defer file.Close() + captureFile = name + return nil +} + +func Init(log logadapter.Logger) *SimIF { + usbif := SimIF{log: log} + usbif.log.Info("Enabling Simulation Replay") + var err error + usbif.file, err = os.Open(captureFile) + if err != nil { + usbif.log.Panic("cannot open USB Capture File %s: %s", captureFile, err) + } + return &usbif +} + +func (usbif *SimIF) SetUSBDebug(level int) { +} + +func (usbif *SimIF) Scan() (bool, error) { + if usbif.file != nil { + return true, nil + } else { + return false, fmt.Errorf("capture File Not Specified") + } +} +func (usbif *SimIF) Close() { + if usbif.file != nil { + usbif.file.Close() + } +} +func (usbif *SimIF) GetAllParam(ctx context.Context) ([]byte, int, error) { + if usbif.file == nil { + usbif.log.Panic("usb Capture File Not Opened") + return nil, 0, fmt.Errorf("usb Capture File Not Opened") + } + cap := make([]byte, 24) + var len int + var err error + len, err = usbif.file.Read(cap) + if err != nil { + if err == io.EOF { + usbif.file.Seek(0, 0) + _, err = usbif.file.Read(cap) + if err != nil { + usbif.log.Warn("Seek to start of file Failed: %s", err) + return nil, 0, fmt.Errorf("seek to Start of File Failed: %s", err) + } + } else { + usbif.log.Warn("Read From Capture File Returned Error: %s", err) + return nil, 0, fmt.Errorf("read from Capture FIle Returned %s", err) + } + } + if len != 24 { + usbif.log.Warn("Short Read from USB Capture File: %d", len) + return nil, 0, fmt.Errorf("short Read from USB Capture File: %d", len) + } + return cap, len, nil +} diff --git a/running.cap b/running.cap new file mode 100644 index 0000000..60a817a Binary files /dev/null and b/running.cap differ diff --git a/shutdown.cap b/shutdown.cap new file mode 100644 index 0000000..50d4f03 Binary files /dev/null and b/shutdown.cap differ