Temperature Measurement & MODBUS Integration #17
|
@ -48,12 +48,6 @@ func main() {
|
|||
if flagFake {
|
||||
klog.Infof("Starting with fake peripherals")
|
||||
d.adcPirani = &fakeADC{}
|
||||
d.gpioRoughingPump = &fakeGPIO{desc: "rp"}
|
||||
d.gpioDiffusionPump = &fakeGPIO{desc: "~dp"}
|
||||
d.gpioBtnPumpDown = &fakeGPIO{desc: "~pd"}
|
||||
d.gpioBtnVent = &fakeGPIO{desc: "~vent"}
|
||||
d.gpioBelowRough = &fakeGPIO{desc: "~rough"}
|
||||
d.gpioBelowHigh = &fakeGPIO{desc: "~high"}
|
||||
} else {
|
||||
adc, err := newBBADC(0)
|
||||
if err != nil {
|
||||
|
@ -65,23 +59,6 @@ func main() {
|
|||
if err != nil {
|
||||
klog.Exitf("Failed to connect to modbus %v", err)
|
||||
}
|
||||
|
||||
for _, c := range []struct {
|
||||
out *gpio
|
||||
num int
|
||||
}{
|
||||
{&d.gpioRoughingPump, 115},
|
||||
{&d.gpioDiffusionPump, 49},
|
||||
{&d.gpioBtnPumpDown, 48},
|
||||
{&d.gpioBtnVent, 60},
|
||||
{&d.gpioBelowRough, 30},
|
||||
{&d.gpioBelowHigh, 7},
|
||||
} {
|
||||
*c.out, err = newBBGPIO(c.num, true)
|
||||
if err != nil {
|
||||
klog.Exitf("Failed to setup GPIO: %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
web := webServer{
|
||||
|
|
|
@ -63,7 +63,7 @@ func (d *daemon) modbusUpdate() error {
|
|||
d.daemonState.tempSEM = modbusValuesToFloat(registers[0])
|
||||
d.daemonState.humiditySEM = modbusValuesToFloat(registers[1])
|
||||
|
||||
// Switch to slave 2
|
||||
// Switch to slave 2 (KEC2)
|
||||
d.modbusClient.SetUnitId(2)
|
||||
|
||||
// PT100 mapping
|
||||
|
@ -76,18 +76,74 @@ func (d *daemon) modbusUpdate() error {
|
|||
}
|
||||
|
||||
if len(registers) != 3 {
|
||||
msg := fmt.Sprintf("Expected three registers from modbus slave 2, but got %d", len(registers))
|
||||
return errors.New(msg)
|
||||
return fmt.Errorf("expected three registers from modbus slave 2, but got %d", len(registers))
|
||||
}
|
||||
|
||||
d.daemonState.tempDPBottom = modbusValuesToFloat(registers[0])
|
||||
d.daemonState.tempDPInlet = modbusValuesToFloat(registers[1])
|
||||
d.daemonState.tempDPTop = modbusValuesToFloat(registers[2])
|
||||
|
||||
// Switch to slave 3 (KEC1)
|
||||
d.modbusClient.SetUnitId(3)
|
||||
|
||||
// Do a read first to avoid side-effects from the subsequent write to the relay states
|
||||
var digitalInputs [8]bool
|
||||
var digitalInputRegisters []uint16
|
||||
|
||||
digitalInputRegisters, err = d.modbusClient.ReadRegisters(0x81, 8, modbus.HOLDING_REGISTER)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Convert MODBUS words into bools
|
||||
for idx, value := range digitalInputRegisters {
|
||||
if value != 0 {
|
||||
digitalInputs[idx] = true
|
||||
} else {
|
||||
digitalInputs[idx] = false
|
||||
}
|
||||
}
|
||||
// TODO: Input mapping goes here
|
||||
|
||||
// KFA1-KFA8
|
||||
var relayState [8]bool
|
||||
|
||||
// -KFA1 Roughing Pump
|
||||
relayState[0] = d.daemonState.rpOn
|
||||
// -KFA2 Diffusion Pump
|
||||
relayState[1] = d.daemonState.dpOn
|
||||
// -KFA4 Button Vent
|
||||
relayState[3] = d.daemonState.vent.output
|
||||
// -KFA5 Button Pump-Down
|
||||
relayState[4] = d.daemonState.pumpdown.output
|
||||
// -KFA6 Fake-Pirani Rough
|
||||
relayState[5] = d.aboveRough.output
|
||||
// -KFA7 Fake-Pirani High
|
||||
relayState[6] = d.aboveHigh.output
|
||||
|
||||
// The KEC1 module uses a non-standard MODBUS interface
|
||||
// instead of coils
|
||||
// 0x0100 is the open command
|
||||
// 0x0200 is the close command
|
||||
// We write 8 words (16-bit) to address 0x01 to update the relays
|
||||
var registerValues [8]uint16
|
||||
// Convert the boolean values to the commands
|
||||
for idx, state := range relayState {
|
||||
if state {
|
||||
registerValues[idx] = 0x0100
|
||||
} else {
|
||||
registerValues[idx] = 0x0200
|
||||
}
|
||||
}
|
||||
|
||||
err = d.modbusClient.WriteRegisters(0x01, registerValues[:])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Call modbusUpdate every second
|
||||
// Call modbusUpdate every 100 milliseconds
|
||||
func (d *daemon) modbusProcess(ctx context.Context) {
|
||||
for {
|
||||
select {
|
||||
|
@ -95,7 +151,7 @@ func (d *daemon) modbusProcess(ctx context.Context) {
|
|||
return
|
||||
default:
|
||||
d.modbusUpdate()
|
||||
time.Sleep(time.Second * 1)
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,13 +19,6 @@ type daemon struct {
|
|||
// Pirani gauge.
|
||||
adcPirani adc
|
||||
|
||||
gpioDiffusionPump gpio
|
||||
gpioRoughingPump gpio
|
||||
gpioBtnPumpDown gpio
|
||||
gpioBtnVent gpio
|
||||
gpioBelowRough gpio
|
||||
gpioBelowHigh gpio
|
||||
|
||||
load atomic.Int64
|
||||
|
||||
// mu guards the state below.
|
||||
|
@ -171,33 +164,5 @@ func (d *daemon) processOnce(_ context.Context) error {
|
|||
d.dpOn = false
|
||||
}
|
||||
|
||||
// Update relay outputs.
|
||||
for _, rel := range []struct {
|
||||
name string
|
||||
gpio gpio
|
||||
// activeHigh means the relay is active high, ie. a true source will
|
||||
// mean that NO/COM get connected, and a false source means that NC/COM
|
||||
// get connected.
|
||||
activeHigh bool
|
||||
source bool
|
||||
}{
|
||||
{"rp", d.gpioRoughingPump, false, d.rpOn},
|
||||
{"dp", d.gpioDiffusionPump, true, d.dpOn},
|
||||
{"pumpdown", d.gpioBtnPumpDown, true, d.pumpdown.output},
|
||||
{"vent", d.gpioBtnVent, true, d.vent.output},
|
||||
{"rough", d.gpioBelowRough, false, d.aboveRough.output},
|
||||
{"high", d.gpioBelowHigh, false, d.aboveHigh.output},
|
||||
} {
|
||||
val := rel.source
|
||||
if rel.activeHigh {
|
||||
// Invert because the relays go through logical inversion (ie. a
|
||||
// GPIO false is a relay trigger).
|
||||
val = !val
|
||||
}
|
||||
if err := rel.gpio.set(val); err != nil {
|
||||
return fmt.Errorf("when outputting %s: %w", rel.name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue