mirror of
https://github.com/Fishwaldo/go-dcdc200.git
synced 2025-03-15 19:41:23 +00:00
331 lines
11 KiB
Go
Executable file
331 lines
11 KiB
Go
Executable file
/*
|
|
MIT License
|
|
|
|
Copyright (c) 2021 Justin Hammond
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in all
|
|
copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
SOFTWARE.
|
|
*/
|
|
|
|
package dcdcusb
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"os"
|
|
"time"
|
|
|
|
"github.com/Fishwaldo/go-dcdc200/internal"
|
|
"github.com/Fishwaldo/go-dcdc200/internal/realusb"
|
|
"github.com/Fishwaldo/go-dcdc200/internal/sim"
|
|
"github.com/go-logr/logr"
|
|
)
|
|
|
|
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 {
|
|
log logr.Logger
|
|
connected bool
|
|
captureData bool
|
|
simulation bool
|
|
usbif usbifI
|
|
}
|
|
|
|
// Represents the Settings for Off and Hardoff Delays when power is lost
|
|
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"`
|
|
}
|
|
|
|
// Status of Various Peripherals
|
|
type Peripheralst struct {
|
|
// ??
|
|
OutSwVin bool `json:"out_sw_vin"`
|
|
// ??
|
|
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.
|
|
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"`
|
|
// What Voltage the Config Jumpers are set for VOut
|
|
VoutConfig float32 `json:"vout_config"`
|
|
// The Input Voltage
|
|
Vin float32 `json:"vin"`
|
|
// The Ignition Voltage
|
|
Vign float32 `json:"vign"`
|
|
// What the Actual VOut Voltage is
|
|
VoutActual float32 `json:"vout_actual"`
|
|
// Status of Various Peripherals
|
|
Peripherals Peripheralst `json:"peripherals"`
|
|
// ?? (Not Output Enabled?)
|
|
Output bool `json:"output"`
|
|
// ??
|
|
AuxVIn bool `json:"aux_v_in"`
|
|
// Firmware Version?
|
|
Version string `json:"version"`
|
|
// State of the Power Supply
|
|
State DcdcStatet `json:"state"`
|
|
// Config Registers (unknown)
|
|
CfgRegisters byte `json:"cfg_registers"`
|
|
// Voltage Flags (Unknown)
|
|
VoltFlags byte `json:"volt_flags"`
|
|
// Timer Flags (Unknown)
|
|
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"`
|
|
// Current VOut Countdown Timer
|
|
TimerVOut time.Duration `json:"timer_v_out"`
|
|
// Current VAux Countdown timer
|
|
TimerVAux time.Duration `json:"timer_v_aux"`
|
|
// Current Power Switch Toggle Count Down Timer
|
|
TimerPRWSW time.Duration `json:"timer_prwsw"`
|
|
// Current Soft Off Countdown Timer
|
|
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"`
|
|
// Current Operating Mode
|
|
Mode DcdcModet `json:"mode"`
|
|
}
|
|
|
|
// Initialize the DCDCUSB Communications. Should be first function called before any other methods are called
|
|
// Pass a logr.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 logr.Logger, simulation bool) {
|
|
dc.log = log
|
|
dc.connected = false
|
|
dc.simulation = simulation
|
|
if !simulation {
|
|
dc.log.Info("Enabling Real USB Mode")
|
|
dc.usbif = realusb.Init(dc.log)
|
|
} else {
|
|
dc.log.Info("Enabling Simulation USB Mode")
|
|
if err := sim.SetCaptureFile("dcdcusb.cap"); err != nil {
|
|
dc.log.Error(err, "SetCaptureFile Failed", "file", "dcdcusb.cap")
|
|
}
|
|
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) {
|
|
dc.usbif.SetUSBDebug(level)
|
|
}
|
|
|
|
// Returns if we are connected to the Power Supply
|
|
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.
|
|
func (dc *DcDcUSB) Scan() (bool, error) {
|
|
var err error
|
|
dc.connected, err = dc.usbif.Scan()
|
|
return dc.connected, err
|
|
}
|
|
func (dc *DcDcUSB) Close() {
|
|
dc.usbif.Close()
|
|
dc.connected = false
|
|
}
|
|
|
|
// 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) {
|
|
recv, len, err := dc.usbif.GetAllParam(ctx)
|
|
if err != nil {
|
|
dc.log.V(2).Info("GetAllParams Call Failed", "error", err)
|
|
return Params{}, err
|
|
}
|
|
if len != 24 {
|
|
dc.log.Info("Got Short Read From USB", "len", len)
|
|
return Params{}, fmt.Errorf("got Short Read from USB")
|
|
}
|
|
|
|
if dc.captureData {
|
|
if dc.simulation {
|
|
dc.log.Error(nil, "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.Error(err, "Can't open File for Capture")
|
|
}
|
|
|
|
if _, err := f.Write(recv); err != nil {
|
|
dc.log.Error(err, "Can't write Text to File")
|
|
}
|
|
f.Close()
|
|
}
|
|
}
|
|
|
|
dc.log.V(3).Info("Got Data", "data", recv)
|
|
params, err := dc.parseAllValues(recv)
|
|
return params, err
|
|
}
|
|
|
|
// 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
|
|
//ignition connect: 2021/09/20 15:51:38 Got [130 133 7 76 75 43 27 133 215 251 1 0 0 0 0 0 0 0 0 3 68 0 0 167]
|
|
//ignition connect2 2021/09/20 15:52:14 Got [130 133 7 76 75 44 27 133 215 251 1 0 0 0 0 0 0 0 0 3 32 0 0 167]
|
|
//ignition disconnect: 2021/09/20 15:50:39 Got [130 133 8 76 0 43 27 133 205 251 1 0 0 0 0 0 0 0 0 3 127 0 0 167]
|
|
// 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) (Params, error) {
|
|
switch buf[0] {
|
|
case internal.CmdRecvAllValues:
|
|
param := Params{}
|
|
param.Mode = dc.modeToConst((buf[1] >> 6) & 0x7)
|
|
param.VoutConfig = dc.voutConfigtoFloat((buf[1] >> 2) & 0x07)
|
|
param.TimerConfig = dc.timerConfigToDuration(buf[1] & 0x03)
|
|
param.State = dc.stateToConst(buf[2])
|
|
param.Vin = float32(buf[3]) * float32(0.1558)
|
|
param.Vign = float32(buf[4]) * float32(0.1558)
|
|
param.VoutActual = float32(buf[5]) * float32(0.1170)
|
|
param.Peripherals = dc.peripheralsState(buf[6])
|
|
param.CfgRegisters = buf[7]
|
|
param.VoltFlags = buf[8]
|
|
param.TimerFlags = buf[9]
|
|
param.ScriptPointer = buf[10]
|
|
param.Version = fmt.Sprintf("%d.%d", int((buf[23]>>5)&0x07), int(buf[23])&0x1F)
|
|
param.TimerWait = dc.convertTime(buf[11:13])
|
|
param.TimerVOut = dc.convertTime(buf[13:15])
|
|
param.TimerVAux = dc.convertTime(buf[15:17])
|
|
param.TimerPRWSW = dc.convertTime(buf[17:19])
|
|
param.TimerSoftOff = dc.convertTime(buf[19:21])
|
|
param.TimerHardOff = dc.convertTime(buf[21:23])
|
|
dc.log.V(3).Info("DCDC Params", "params", param)
|
|
return param, nil
|
|
}
|
|
return Params{}, errors.New("unknown command recieved")
|
|
}
|
|
|
|
func (dc *DcDcUSB) modeToConst(mode byte) DcdcModet {
|
|
switch mode {
|
|
case 0:
|
|
return Dumb
|
|
case 1:
|
|
return Script
|
|
case 2:
|
|
return Automotive
|
|
case 3:
|
|
return UPS
|
|
default:
|
|
return Unknown
|
|
}
|
|
}
|
|
|
|
func (dc *DcDcUSB) voutConfigtoFloat(config byte) float32 {
|
|
switch config {
|
|
case 0:
|
|
return float32(12.0)
|
|
case 1:
|
|
return float32(5.0)
|
|
case 2:
|
|
return float32(6.0)
|
|
case 3:
|
|
return float32(9.0)
|
|
case 4:
|
|
return float32(13.5)
|
|
case 5:
|
|
return float32(16.0)
|
|
case 6:
|
|
return float32(19.0)
|
|
case 7:
|
|
return float32(24.0)
|
|
default:
|
|
return float32(-1)
|
|
}
|
|
}
|
|
|
|
func (dc DcDcUSB) timerConfigToDuration(config byte) TimerConfigt {
|
|
switch config {
|
|
case 0:
|
|
return TimerConfigt{OffDelay: 0, HardOff: 0}
|
|
case 1:
|
|
return TimerConfigt{OffDelay: 15 * time.Minute, HardOff: 1 * time.Minute}
|
|
case 2:
|
|
return TimerConfigt{OffDelay: 5 * time.Second, HardOff: -1}
|
|
case 3:
|
|
return TimerConfigt{OffDelay: 30 * time.Minute, HardOff: 1 * time.Minute}
|
|
case 4:
|
|
return TimerConfigt{OffDelay: 5 * time.Second, HardOff: 1 * time.Minute}
|
|
case 5:
|
|
return TimerConfigt{OffDelay: 15 * time.Minute, HardOff: -1}
|
|
case 6:
|
|
return TimerConfigt{OffDelay: 1 * time.Minute, HardOff: 1 * time.Minute}
|
|
case 7:
|
|
return TimerConfigt{OffDelay: 1 * time.Hour, HardOff: -1}
|
|
default:
|
|
return TimerConfigt{OffDelay: -1, HardOff: -1}
|
|
}
|
|
}
|
|
|
|
func (dc DcDcUSB) stateToConst(state byte) DcdcStatet {
|
|
switch state {
|
|
case 7:
|
|
return StateOk
|
|
case 8:
|
|
return StateIgnOff
|
|
case 16:
|
|
return StateHardOffCountdown
|
|
default:
|
|
return StateUnknown
|
|
}
|
|
}
|
|
|
|
func (dc DcDcUSB) peripheralsState(state byte) Peripheralst {
|
|
p := Peripheralst{
|
|
InVoutGood: ((state & 0x01) != 0),
|
|
OutLed: ((state & 0x02) != 0),
|
|
OutPsw: ((state & 0x04) != 0),
|
|
OutStartOutput: ((state & 0x08) != 0),
|
|
OutSwVin: ((state & 0x10) != 0),
|
|
}
|
|
return p
|
|
}
|
|
|
|
func (dc DcDcUSB) convertTime(raw []byte) time.Duration {
|
|
duration := int64(raw[0]) << 8
|
|
duration += int64(raw[1])
|
|
return time.Duration(duration * int64(time.Second))
|
|
}
|