matemat/uncanny/can.go
2021-01-31 16:56:33 +01:00

116 lines
2.1 KiB
Go

package uncanny
import (
"errors"
"fmt"
"log"
"github.com/brutella/can"
)
type Can struct {
bus *can.Bus
swstate FeedbackMessage
dispstate int
}
func NewCan(intf string) (*Can, error) {
bus, err := can.NewBusForInterfaceWithName(intf)
if err != nil {
return nil, errors.New(fmt.Sprintf("Can't open %s: %v", intf, err))
}
can := &Can{
bus: bus,
dispstate: -1,
}
bus.Subscribe(can)
return can, nil
}
func (c *Can) Start() {
go func() {
// send the init sequence
c.initialize()
// ConnectAndPublish will block, so we'll just leave the Printf hanging here
log.Printf("CAN bus shut down: %v", c.bus.ConnectAndPublish())
}()
}
func (c *Can) Stop() {
c.bus.Disconnect()
}
func (c *Can) Handle(frame can.Frame) {
typ, obj, err := DecodeMessage(frame)
if err != nil {
if err == UnsupportedMessageType {
log.Printf("Unsupported message type: 0x%08x", frame.ID)
} else {
log.Printf("Cannot decode message: %v", err)
}
} else {
switch typ {
case MessageTypeFeedback:
c.swstate = obj.(FeedbackMessage)
case MessageTypeFeedbackRequest:
// ignore
case MessageTypePower:
// ignore
case MessageTypePowerRequest:
// ignore
case MessageTypeDispense:
c.dispstate = obj.(DispenseMessage).Slot
case MessageTypeAuto:
// ignore
}
}
}
func (c *Can) IsEmpty(slot int) bool {
switch (slot) {
case 0:
return c.swstate.EmptyD
case 1:
return c.swstate.EmptyE
case 2:
return c.swstate.EmptyF
case 3:
return c.swstate.EmptyG
case 4:
return c.swstate.EmptyH
}
return false
}
func (c *Can) IsDispensing(slot int) bool {
switch (slot) {
case 0:
return c.swstate.EndD
case 1:
return c.swstate.EndE
case 2:
return c.swstate.EndF
case 3:
return c.swstate.EndG
case 4:
return c.swstate.EndH
}
return false
}
func (c *Can) ActiveDispenser() int {
return c.dispstate
}
func (c *Can) Dispense(slot int) error {
return c.bus.Publish(DispenseMessage{slot}.Encode())
}
func (c *Can) Cancel() error {
return c.bus.Publish(DispenseMessage{DispenseSlotOff}.Encode())
}
func (c *Can) initialize() error {
// enable automatic status updates
return c.bus.Publish(AutoMessage{true}.Encode())
}