diff options
author | xengineering <mail2xengineering@protonmail.com> | 2021-06-15 15:51:38 +0200 |
---|---|---|
committer | xengineering <mail2xengineering@protonmail.com> | 2021-06-15 15:58:23 +0200 |
commit | 4a01c8e94921d9ddcaf6d6dee0feca4d9c3655a2 (patch) | |
tree | 634a3d6e380079d0da5e8fafaf866a33a63fb4bc | |
parent | 2269cc653577dffc58dba4ad5534583f28f224de (diff) | |
download | birdscan-4a01c8e94921d9ddcaf6d6dee0feca4d9c3655a2.tar birdscan-4a01c8e94921d9ddcaf6d6dee0feca4d9c3655a2.tar.zst birdscan-4a01c8e94921d9ddcaf6d6dee0feca4d9c3655a2.zip |
Refactoring: Camera has Statemachine and not is Statemachine
-rw-r--r-- | src/camera.go | 38 | ||||
-rw-r--r-- | src/main.go | 4 | ||||
-rw-r--r-- | src/state.go | 69 | ||||
-rw-r--r-- | src/web.go | 4 |
4 files changed, 67 insertions, 48 deletions
diff --git a/src/camera.go b/src/camera.go new file mode 100644 index 0000000..12a9d54 --- /dev/null +++ b/src/camera.go @@ -0,0 +1,38 @@ +// vim: shiftwidth=4 tabstop=4 noexpandtab + +package main + +type Camera struct { + statemachine Machine +} + +func NewCamera() Camera { + return Camera{ + statemachine: 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), + state_listeners: make([]*(chan string), 0), + }, + } +} + +func (cam *Camera) run() { + cam.statemachine.Run() +} diff --git a/src/main.go b/src/main.go index af82e8f..768920a 100644 --- a/src/main.go +++ b/src/main.go @@ -11,7 +11,7 @@ import ( ) var ( - camera Machine + camera Camera ) type config struct { @@ -31,7 +31,7 @@ func main() { cfg := readConfig(configPath) // setup camera state machine - camera = newCamStateMachine() + camera = NewCamera() // start goroutines server := NewWebServer(&cfg.WebConfig) diff --git a/src/state.go b/src/state.go index 9a08738..5970ba8 100644 --- a/src/state.go +++ b/src/state.go @@ -7,6 +7,7 @@ import ( "time" ) +// This struct represents the statemachine. type Machine struct { name string initial string @@ -28,6 +29,16 @@ type MachineTransition struct { to string } +// This will run the statemachine (blocking). +func (m *Machine) Run() { + var event string + for { + event = <-m.api // read api (blocking) + m.processEvent(event) + } +} + +// A simple Getter to retrieve the current state. func (m Machine) GetState() string { if m.current == "" { return m.initial @@ -35,10 +46,14 @@ func (m Machine) GetState() string { return m.current } +// This function blocks until the current state differs +// from the 'known' state. It then returns the current +// state. func (m *Machine) GetStateOnChange(known string) string { listener := make(chan string) var current string - m.RegisterListener(&listener) + m.registerListener(&listener) + defer m.deregisterListener(&listener) for { if m.GetState() != known { current = m.GetState() @@ -49,15 +64,19 @@ func (m *Machine) GetStateOnChange(known string) string { break } } - m.DeregisterListener(&listener) return current } -func (m *Machine) RegisterListener(listener *(chan string)) { +// Use this function to send an event to the statemachine. +func (m *Machine) SendEvent(event string) { + m.api <- event // blocks until m.run() goroutine handles this event +} + +func (m *Machine) registerListener(listener *(chan string)) { m.state_listeners = append(m.state_listeners, listener) } -func (m *Machine) DeregisterListener(listener *(chan string)) { +func (m *Machine) deregisterListener(listener *(chan string)) { wasRemoved := false if len(m.state_listeners) == 0 { log.Println("Not able to unregister listener from empty state_listener slice") @@ -90,25 +109,13 @@ func (m *Machine) processEvent(event string) string { 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) - } -} - +// In this function one can implement callback functions +// which will be triggered on certain transitions. func (m *Machine) runHooks(last string, next string) { - log.Println("Send state to listeners ...") for _,listener := range(m.state_listeners) { *listener <- next } - log.Println("State sent to listeners") if last == "idle" && next == "single_picture" { // TODO implement launch of python subprocess here @@ -118,29 +125,3 @@ func (m *Machine) runHooks(last string, next string) { }() } } - -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), - state_listeners: make([]*(chan string), 0), - } -} - @@ -58,11 +58,11 @@ func jsHandler(w http.ResponseWriter, r *http.Request) { func stateHandler(w http.ResponseWriter, r *http.Request) { known_state := r.FormValue("known_state") - w.Write([]byte(fmt.Sprintf("%s", camera.GetStateOnChange(known_state)))) + w.Write([]byte(fmt.Sprintf("%s", camera.statemachine.GetStateOnChange(known_state)))) } func singlePictureHandler(w http.ResponseWriter, r *http.Request) { - camera.SendEvent("take_single_picture") + camera.statemachine.SendEvent("take_single_picture") fmt.Fprintf(w, http.StatusText(http.StatusOK)) } |