diff --git a/uncanny/can.go b/uncanny/can.go index 3daab44..8d70298 100644 --- a/uncanny/can.go +++ b/uncanny/can.go @@ -13,7 +13,7 @@ type Can struct { bus *can.Bus queue chan func() - swstate FeedbackMessage + swstate FeedbackStatus dispstate int } @@ -72,27 +72,23 @@ func (c *Can) Handle(frame can.Frame) { } } else { switch typ { - case MessageTypeFeedback: - log.Printf("Got feedback message: %+v", obj.(FeedbackMessage)) + case MessageTypeFeedbackStatus: + log.Printf("Got feedback status message: %+v", obj.(FeedbackStatus)) log.Printf("Data: 0x%02x 0x%02x", frame.Data[0], frame.Data[1]) - c.swstate = obj.(FeedbackMessage) + c.swstate = obj.(FeedbackStatus) // when all end switches are open (i.e. true): send stop command if c.swstate.EndD && c.swstate.EndE && c.swstate.EndF && c.swstate.EndG && c.swstate.EndH { log.Printf("All end switches off, stopping dispenser") c.Cancel() } - case MessageTypeFeedbackRequest: - // ignore - case MessageTypePower: - log.Printf("Got power message: %+v", obj.(PowerMessage)) - // ignore - case MessageTypePowerRequest: - // ignore - case MessageTypeDispense: - log.Printf("Got dispense message: %+v", obj.(DispenseMessage)) - c.dispstate = obj.(DispenseMessage).Slot - case MessageTypeAuto: + case MessageTypePowerStatus: + log.Printf("Got power status message: %+v", obj.(PowerStatus)) // ignore + case MessageTypeDispenseCommand: + log.Printf("Got dispense command message: %+v", obj.(DispenseCommand)) + c.dispstate = obj.(DispenseCommand).Slot + case MessageTypeDisplayStatus: + log.Printf("Got display status message: %+v", obj.(DisplayStatus)) } } } @@ -149,7 +145,7 @@ func (c *Can) ActiveDispenser() int { func (c *Can) Dispense(slot int) { c.queue <- func() { log.Printf("Starting dispense on slot %d", slot) - err := c.bus.Publish(DispenseMessage{slot}.Encode()) + err := c.bus.Publish(DispenseCommand{slot}.Encode()) if err != nil { log.Printf("Error sending dispense command: %v", err) } @@ -159,7 +155,7 @@ func (c *Can) Dispense(slot int) { func (c *Can) Cancel() { c.queue <- func() { log.Printf("Stopping dispense") - err := c.bus.Publish(DispenseMessage{DispenseSlotOff}.Encode()) + err := c.bus.Publish(DispenseCommand{DispenseSlotOff}.Encode()) if err != nil { log.Printf("Error sending stop command: %v", err) } @@ -170,8 +166,9 @@ func (c *Can) Initialize() { c.queue <- func() { log.Printf("Initializing devices") // enable automatic status updates - c.bus.Publish(AutoMessage{true}.Encode()) - c.bus.Publish(RequestFeedbackMessage()) - c.bus.Publish(RequestPowerMessage()) + c.bus.Publish(AutoCommand{true}.Encode()) + c.bus.Publish(EncodeFeedbackRequest()) + c.bus.Publish(EncodePowerRequest()) + c.bus.Publish(EncodeDisplayRequest()) } } diff --git a/uncanny/message.go b/uncanny/message.go index 6fb3e3d..31a20f4 100644 --- a/uncanny/message.go +++ b/uncanny/message.go @@ -44,6 +44,9 @@ const uint8_t can_msg_power_dispense_slot3 = CAN_MSG_POWER_DISPENSE_SLOT3; const uint8_t can_msg_power_dispense_slot4 = CAN_MSG_POWER_DISPENSE_SLOT4; const uint8_t can_msg_power_dispense_slot5 = CAN_MSG_POWER_DISPENSE_SLOT5; +const uint8_t can_msg_display_status = CAN_MSG_DISPLAY_STATUS; +const uint8_t can_msg_display_cmd = CAN_MSG_DISPLAY_CMD; + const uint16_t can_msg_auto_status = CAN_MSG_AUTO_STATUS; const uint8_t can_msg_auto_status_disable = CAN_MSG_AUTO_STATUS_DISABLE; const uint8_t can_msg_auto_status_enable = CAN_MSG_AUTO_STATUS_ENABLE; @@ -64,12 +67,15 @@ var ( type MessageType int const ( MessageTypeInvalid MessageType = iota - MessageTypeFeedback + MessageTypeFeedbackStatus MessageTypeFeedbackRequest - MessageTypePower + MessageTypePowerStatus MessageTypePowerRequest - MessageTypeDispense - MessageTypeAuto + MessageTypeDispenseCommand + MessageTypeDisplayStatus + MessageTypeDisplayRequest + MessageTypeDisplayCommand + MessageTypeAutoCommand ) // DecodeMessage decodes a CAN frame and returns an appropriate message @@ -83,26 +89,34 @@ const ( func DecodeMessage(frame can.Frame) (MessageType, interface{}, error) { switch frame.ID { case uint32(C.can_msg_feedback_status): - msg, err := DecodeFeedbackMessage(frame) - return MessageTypeFeedback, msg, err + msg, err := DecodeFeedbackStatus(frame) + return MessageTypeFeedbackStatus, msg, err case uint32(C.can_msg_feedback_status) | can.MaskRtr: return MessageTypeFeedbackRequest, nil, nil case uint32(C.can_msg_power_status): - msg, err := DecodePowerMessage(frame) - return MessageTypePower, msg, err + msg, err := DecodePowerStatus(frame) + return MessageTypePowerStatus, msg, err case uint32(C.can_msg_power_status) | can.MaskRtr: return MessageTypePowerRequest, nil, nil case uint32(C.can_msg_power_dispense): - msg, err := DecodeDispenseMessage(frame) - return MessageTypeDispense, msg, err + msg, err := DecodeDispenseCommand(frame) + return MessageTypeDispenseCommand, msg, err + case uint32(C.can_msg_display_status): + msg, err := DecodeDisplayStatus(frame) + return MessageTypeDisplayStatus, msg, err + case uint32(C.can_msg_display_status) | can.MaskRtr: + return MessageTypeDisplayRequest, nil, nil + case uint32(C.can_msg_display_cmd): + msg, err := DecodeDisplayCommand(frame) + return MessageTypeDisplayCommand, msg, err case uint32(C.can_msg_auto_status): - msg, err := DecodeAutoMessage(frame) - return MessageTypeAuto, msg, err + msg, err := DecodeAutoCommand(frame) + return MessageTypeAutoCommand, msg, err } return MessageTypeInvalid, nil, UnsupportedMessageType } -type FeedbackMessage struct { +type FeedbackStatus struct { EndD bool EndE bool EndF bool @@ -116,14 +130,14 @@ type FeedbackMessage struct { ResetSw bool } -func RequestFeedbackMessage() can.Frame { +func EncodeFeedbackRequest() can.Frame { return can.Frame{ ID: uint32(C.can_msg_feedback_status) | can.MaskRtr, } } -func DecodeFeedbackMessage(frame can.Frame) (FeedbackMessage, error) { - var ret FeedbackMessage +func DecodeFeedbackStatus(frame can.Frame) (FeedbackStatus, error) { + var ret FeedbackStatus if frame.ID != uint32(C.can_msg_feedback_status) { return ret, InvalidMessageID } @@ -144,8 +158,8 @@ func DecodeFeedbackMessage(frame can.Frame) (FeedbackMessage, error) { return ret, nil } -func (f FeedbackMessage) Encode() can.Frame { - data := [8]uint8{} +func (f FeedbackStatus) Encode() can.Frame { + var data [8]uint8 if f.EndD { data[int(C.can_msg_feedback_status_field_end_d)] |= uint8(C.can_msg_feedback_status_bit_end_d) } @@ -186,18 +200,18 @@ func (f FeedbackMessage) Encode() can.Frame { } } -type PowerMessage struct { +type PowerStatus struct { Bits int } -func RequestPowerMessage() can.Frame { +func EncodePowerRequest() can.Frame { return can.Frame{ ID: uint32(C.can_msg_power_status) | can.MaskRtr, } } -func DecodePowerMessage(frame can.Frame) (PowerMessage, error) { - var ret PowerMessage +func DecodePowerStatus(frame can.Frame) (PowerStatus, error) { + var ret PowerStatus if frame.ID != uint32(C.can_msg_power_status) { return ret, InvalidMessageID } @@ -208,8 +222,8 @@ func DecodePowerMessage(frame can.Frame) (PowerMessage, error) { return ret, nil } -func (f PowerMessage) Encode() can.Frame { - data := [8]uint8{} +func (f PowerStatus) Encode() can.Frame { + var data [8]uint8 data[0] = uint8(f.Bits >> 8) data[1] = uint8(f.Bits) return can.Frame{ @@ -221,12 +235,12 @@ func (f PowerMessage) Encode() can.Frame { const DispenseSlotOff int = -1 -type DispenseMessage struct { +type DispenseCommand struct { Slot int } -func DecodeDispenseMessage(frame can.Frame) (DispenseMessage, error) { - var ret DispenseMessage +func DecodeDispenseCommand(frame can.Frame) (DispenseCommand, error) { + var ret DispenseCommand if frame.ID != uint32(C.can_msg_power_dispense) { return ret, InvalidMessageID } @@ -250,8 +264,8 @@ func DecodeDispenseMessage(frame can.Frame) (DispenseMessage, error) { return ret, nil } -func (f DispenseMessage) Encode() can.Frame { - data := [8]uint8{} +func (f DispenseCommand) Encode() can.Frame { + var data [8]uint8 switch f.Slot { case DispenseSlotOff: data[0] = uint8(C.can_msg_power_dispense_off) @@ -273,12 +287,85 @@ func (f DispenseMessage) Encode() can.Frame { } } -type AutoMessage struct { +type DisplayStatus struct { + Buttons []bool +} + +func EncodeDisplayRequest() can.Frame { + return can.Frame{ + ID: uint32(C.can_msg_display_status) | can.MaskRtr, + } +} + +func DecodeDisplayStatus(frame can.Frame) (DisplayStatus, error) { + var ret DisplayStatus + if frame.ID != uint32(C.can_msg_display_status) { + return ret, InvalidMessageID + } + if frame.Length != 1 { + return ret, InvalidMessageLength + } + ret.Buttons = make([]bool, 8) + for i := uint(0); i < 8; i++ { + ret.Buttons[i] = frame.Data[0] & (1 << i) != 0; + } + return ret, nil +} + +func (f DisplayStatus) Encode() can.Frame { + var data [8]uint8 + for i := uint(0); i < 8; i++ { + if f.Buttons[i] { + data[0] |= (1 << i) + } + } + return can.Frame{ + ID: uint32(C.can_msg_display_status), + Length: 1, + Data: data, + } +} + +type DisplayCommand struct { + Command int + Data []byte +} + +func DecodeDisplayCommand(frame can.Frame) (DisplayCommand, error) { + var ret DisplayCommand + if frame.ID != uint32(C.can_msg_display_cmd) { + return ret, InvalidMessageID + } + if frame.Length < 1 { + return ret, InvalidMessageLength + } + ret.Command = int(frame.Data[0]) + ret.Data = make([]byte, frame.Length - 1) + copy(ret.Data, frame.Data[1:frame.Length-1]) + return ret, nil +} + +func (f DisplayCommand) Encode() can.Frame { + data := [8]uint8{} + data[0] = uint8(f.Command) + length := len(f.Data) + if length > 7 { + length = 7 + } + copy(data[1:], f.Data[:length]) + return can.Frame{ + ID: uint32(C.can_msg_display_cmd), + Length: 1, + Data: data, + } +} + +type AutoCommand struct { AutoUpdate bool } -func DecodeAutoMessage(frame can.Frame) (AutoMessage, error) { - var ret AutoMessage +func DecodeAutoCommand(frame can.Frame) (AutoCommand, error) { + var ret AutoCommand if frame.ID != uint32(C.can_msg_auto_status) { return ret, InvalidMessageID } @@ -292,7 +379,7 @@ func DecodeAutoMessage(frame can.Frame) (AutoMessage, error) { return ret, nil } -func (f AutoMessage) Encode() can.Frame { +func (f AutoCommand) Encode() can.Frame { data := [8]uint8{} if f.AutoUpdate { data[0] = uint8(C.can_msg_auto_status_enable)