This repository has been archived by the owner on Oct 27, 2022. It is now read-only.
/
snub.go
140 lines (117 loc) · 3.71 KB
/
snub.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package main
import (
"log"
"strconv"
"sync"
"time"
)
// Possible states of a snub, value is ascii which
// represents its state
const (
cooldown = string(iota + '$') //'$'
acelerating //'%'
braking //'&'
aceleratingBraking //'''
cooldownWater //'('
aceleratingWater //')'
brakingWater //'*'
aceleratingBrakingWater //'+'
)
// Mapping current state to next state
var currentToNextState = map[string]string{
acelerating: braking,
braking: cooldown,
cooldown: acelerating,
aceleratingWater: brakingWater,
brakingWater: cooldownWater,
cooldownWater: aceleratingWater,
}
// Regular state to matching state but throwing water
var offToOnWater = map[string]string{
acelerating: aceleratingWater,
braking: brakingWater,
cooldown: cooldownWater,
aceleratingWater: aceleratingWater,
brakingWater: brakingWater,
cooldownWater: cooldownWater,
}
// From a throwing water state to a regular state
var onToOffWater = map[string]string{
aceleratingWater: acelerating,
brakingWater: braking,
cooldownWater: cooldown,
acelerating: acelerating,
braking: braking,
cooldown: cooldown,
}
// Ascii character which represents state to state name
var byteToStateName = map[string]string{
"$": "cooldown",
"%": "acelerating",
"&": "braking",
"\"": "aceleratingBraking",
"(": "cooldownWater",
")": "aceleratingWater",
"*": "brakingWater",
"+": "aceleratingBrakingWater",
}
// Snub is a cycle of aceleration, braking and cooldown,
// multiple snubs compose a test
type Snub struct {
counterCh chan int
state string
delayAcelerateToBrake int
delayBrakeToCooldown int
upperSpeedLimit float64
lowerSpeedLimit float64
isWaterOn bool
isStabilizing bool
timeCooldown int
mux sync.Mutex
}
// NextState change state of snub to next corresponding in duty cycle
func (snub *Snub) NextState() {
snub.mux.Lock()
defer snub.mux.Unlock()
switch snub.state {
case acelerating, aceleratingWater: // Next is Braking
snub.isStabilizing = true
log.Println("Stabilizing...")
time.Sleep(time.Second * time.Duration(snub.delayAcelerateToBrake))
snub.changeState() // Acelerate ---> braking
snub.isStabilizing = false
case braking, brakingWater: // Next is Cooldown
snub.isStabilizing = true
log.Println("Stabilizing...")
time.Sleep(time.Second * time.Duration(snub.delayBrakeToCooldown))
snub.changeState() // Brake ---> Cooldown
snub.isStabilizing = false
time.Sleep(time.Second * time.Duration(snub.timeCooldown))
case cooldown, cooldownWater: // Next is acelerate, end of a cycle
log.Println("---> End of snub <---")
snub.changeState()
counter, isOpen := <-snub.counterCh
if isOpen {
snub.counterCh <- counter + 1
publishData(strconv.Itoa(counter), mqttSubchannelCurrentSnub)
}
default:
log.Printf("Invalid state: %v", snub.state)
}
}
// SetState will set the state for the Snub, handling mutual exclusion
func (snub *Snub) SetState(state string) {
snub.mux.Lock()
defer snub.mux.Unlock()
snub.setStateNonExclusion(state)
}
func (snub *Snub) changeState() {
snub.setStateNonExclusion(currentToNextState[snub.state])
}
func (snub *Snub) setStateNonExclusion(state string) {
oldState := snub.state
snub.state = state
port.Write([]byte(snub.state))
publishData(byteToStateName[snub.state], mqttSubchannelSnubState)
log.Printf("Change state: %v ---> %v\n", byteToStateName[oldState], byteToStateName[snub.state])
}