// vim: shiftwidth=4 tabstop=4 noexpandtab package main import ( "log" "time" ) type Machine struct { name string initial string current string states StateMap api chan string } type StateMap map[string]MachineState type MachineState struct { on TransitionMap } type TransitionMap map[string]MachineTransition type MachineTransition struct { to string } func (m Machine) GetState() string { if m.current == "" { return m.initial } return m.current } func (m *Machine) processEvent(event string) string { current := m.GetState() next := m.states[current].on[event].to if next != "" { log.Printf("State machine '%s' changes from '%s' to '%s'\n", m.name, current, next) m.current = next m.runHooks(current, next) return next } return current } func (m *Machine) SendEvent(event string) { m.api <- event // blocks until m.run() goroutine handles this event } func (m *Machine) run() { var event string for { event = <-m.api // read api (blocking) m.processEvent(event) } } func (m *Machine) runHooks(last string, next string) { if next == "single_picture" { // TODO implement launch of python subprocess here go func() { time.Sleep(1 * time.Second) m.SendEvent("single_picture_taken") }() } } func newCamStateMachine() Machine { return Machine{ name: "camera", initial: "idle", states: StateMap{ "idle": MachineState{ on: TransitionMap{ "take_single_picture": MachineTransition{ to: "single_picture", }, }, }, "single_picture": MachineState{ on: TransitionMap{ "single_picture_taken": MachineTransition{ to: "idle", }, }, }, }, api: make(chan string), } }