Skip to content

Commit b7d3527

Browse files
committed
Flash procedure for Arduino boards
Former-commit-id: c740af8e5e4bc73ac56c8f0504af9cbe28f83e14 [formerly 8a51ea2ebaaf2bb826227d90fb414ac704068a49] Former-commit-id: 8046bbbeaed4c454403cb625d8ea11cd484cb634
1 parent 8653e47 commit b7d3527

6 files changed

+1601
-3
lines changed

hub.go

+355
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"github.com/kardianos/osext"
6+
"log"
7+
//"os"
8+
"os/exec"
9+
//"path"
10+
//"path/filepath"
11+
//"runtime"
12+
//"debug"
13+
"encoding/json"
14+
"runtime"
15+
"runtime/debug"
16+
"strconv"
17+
"strings"
18+
)
19+
20+
type hub struct {
21+
// Registered connections.
22+
connections map[*connection]bool
23+
24+
// Inbound messages from the connections.
25+
broadcast chan []byte
26+
27+
// Inbound messages from the system
28+
broadcastSys chan []byte
29+
30+
// Register requests from the connections.
31+
register chan *connection
32+
33+
// Unregister requests from connections.
34+
unregister chan *connection
35+
}
36+
37+
var h = hub{
38+
// buffered. go with 1000 cuz should never surpass that
39+
broadcast: make(chan []byte, 1000),
40+
broadcastSys: make(chan []byte, 1000),
41+
// non-buffered
42+
//broadcast: make(chan []byte),
43+
//broadcastSys: make(chan []byte),
44+
register: make(chan *connection),
45+
unregister: make(chan *connection),
46+
connections: make(map[*connection]bool),
47+
}
48+
49+
func (h *hub) run() {
50+
for {
51+
select {
52+
case c := <-h.register:
53+
h.connections[c] = true
54+
// send supported commands
55+
c.send <- []byte("{\"Version\" : \"" + version + "\"} ")
56+
c.send <- []byte("{\"Commands\" : [\"list\", \"open [portName] [baud] [bufferAlgorithm (optional)]\", \"send [portName] [cmd]\", \"sendnobuf [portName] [cmd]\", \"close [portName]\", \"bufferalgorithms\", \"baudrates\", \"restart\", \"exit\"]} ")
57+
c.send <- []byte("{\"Hostname\" : \"" + *hostname + "\"} ")
58+
case c := <-h.unregister:
59+
delete(h.connections, c)
60+
// put close in func cuz it was creating panics and want
61+
// to isolate
62+
func() {
63+
// this method can panic if websocket gets disconnected
64+
// from users browser and we see we need to unregister a couple
65+
// of times, i.e. perhaps from incoming data from serial triggering
66+
// an unregister. (NOT 100% sure why seeing c.send be closed twice here)
67+
defer func() {
68+
if e := recover(); e != nil {
69+
log.Println("Got panic: ", e)
70+
}
71+
}()
72+
close(c.send)
73+
}()
74+
case m := <-h.broadcast:
75+
//log.Print("Got a broadcast")
76+
//log.Print(m)
77+
//log.Print(len(m))
78+
if len(m) > 0 {
79+
//log.Print(string(m))
80+
//log.Print(h.broadcast)
81+
checkCmd(m)
82+
//log.Print("-----")
83+
84+
for c := range h.connections {
85+
select {
86+
case c.send <- m:
87+
//log.Print("did broadcast to ")
88+
//log.Print(c.ws.RemoteAddr())
89+
//c.send <- []byte("hello world")
90+
default:
91+
delete(h.connections, c)
92+
close(c.send)
93+
go c.ws.Close()
94+
}
95+
}
96+
}
97+
case m := <-h.broadcastSys:
98+
//log.Printf("Got a system broadcast: %v\n", string(m))
99+
//log.Print(string(m))
100+
//log.Print("-----")
101+
102+
for c := range h.connections {
103+
select {
104+
case c.send <- m:
105+
//log.Print("did broadcast to ")
106+
//log.Print(c.ws.RemoteAddr())
107+
//c.send <- []byte("hello world")
108+
default:
109+
delete(h.connections, c)
110+
close(c.send)
111+
go c.ws.Close()
112+
}
113+
}
114+
}
115+
}
116+
}
117+
118+
func checkCmd(m []byte) {
119+
//log.Print("Inside checkCmd")
120+
s := string(m[:])
121+
log.Print(s)
122+
123+
sl := strings.ToLower(s)
124+
125+
if strings.HasPrefix(sl, "open") {
126+
127+
// check if user wants to open this port as a secondary port
128+
// this doesn't mean much other than allowing the UI to show
129+
// a port as primary and make other ports sort of act less important
130+
isSecondary := false
131+
if strings.HasPrefix(s, "open secondary") {
132+
isSecondary = true
133+
// swap out the word secondary
134+
s = strings.Replace(s, "open secondary", "open", 1)
135+
}
136+
137+
args := strings.Split(s, " ")
138+
if len(args) < 3 {
139+
go spErr("You did not specify a port and baud rate in your open cmd")
140+
return
141+
}
142+
if len(args[1]) < 1 {
143+
go spErr("You did not specify a serial port")
144+
return
145+
}
146+
147+
baudStr := strings.Replace(args[2], "\n", "", -1)
148+
baud, err := strconv.Atoi(baudStr)
149+
if err != nil {
150+
go spErr("Problem converting baud rate " + args[2])
151+
return
152+
}
153+
// pass in buffer type now as string. if user does not
154+
// ask for a buffer type pass in empty string
155+
bufferAlgorithm := ""
156+
if len(args) > 3 {
157+
// cool. we got a buffer type request
158+
buftype := strings.Replace(args[3], "\n", "", -1)
159+
bufferAlgorithm = buftype
160+
}
161+
go spHandlerOpen(args[1], baud, bufferAlgorithm, isSecondary)
162+
163+
} else if strings.HasPrefix(sl, "close") {
164+
165+
args := strings.Split(s, " ")
166+
if len(args) > 1 {
167+
go spClose(args[1])
168+
} else {
169+
go spErr("You did not specify a port to close")
170+
}
171+
172+
} else if strings.HasPrefix(sl, "program") {
173+
174+
args := strings.Split(s, " ")
175+
if len(args) > 3 {
176+
go spProgram(args[1], args[2], args[3])
177+
} else {
178+
go spErr("You did not specify a port, a board to program and a filename")
179+
}
180+
181+
} else if strings.HasPrefix(sl, "sendjson") {
182+
// will catch sendjson
183+
184+
go spWriteJson(s)
185+
186+
} else if strings.HasPrefix(sl, "send") {
187+
// will catch send and sendnobuf
188+
189+
//args := strings.Split(s, "send ")
190+
go spWrite(s)
191+
192+
} else if strings.HasPrefix(sl, "list") {
193+
go spList()
194+
//go getListViaWmiPnpEntity()
195+
} else if strings.HasPrefix(sl, "bufferalgorithm") {
196+
go spBufferAlgorithms()
197+
} else if strings.HasPrefix(sl, "baudrate") {
198+
go spBaudRates()
199+
} else if strings.HasPrefix(sl, "broadcast") {
200+
go broadcast(s)
201+
} else if strings.HasPrefix(sl, "restart") {
202+
restart()
203+
} else if strings.HasPrefix(sl, "exit") {
204+
exit()
205+
} else if strings.HasPrefix(sl, "memstats") {
206+
memoryStats()
207+
} else if strings.HasPrefix(sl, "gc") {
208+
garbageCollection()
209+
} else if strings.HasPrefix(sl, "bufflowdebug") {
210+
bufflowdebug(sl)
211+
} else if strings.HasPrefix(sl, "hostname") {
212+
getHostname()
213+
} else if strings.HasPrefix(sl, "version") {
214+
getVersion()
215+
} else {
216+
go spErr("Could not understand command.")
217+
}
218+
219+
//log.Print("Done with checkCmd")
220+
}
221+
222+
func bufflowdebug(sl string) {
223+
log.Println("bufflowdebug start")
224+
if strings.HasPrefix(sl, "bufflowdebug on") {
225+
*bufFlowDebugType = "on"
226+
} else if strings.HasPrefix(sl, "bufflowdebug off") {
227+
*bufFlowDebugType = "off"
228+
}
229+
h.broadcastSys <- []byte("{\"BufFlowDebug\" : \"" + *bufFlowDebugType + "\"}")
230+
log.Println("bufflowdebug end")
231+
}
232+
233+
func memoryStats() {
234+
var memStats runtime.MemStats
235+
runtime.ReadMemStats(&memStats)
236+
json, _ := json.Marshal(memStats)
237+
log.Printf("memStats:%v\n", string(json))
238+
h.broadcastSys <- json
239+
}
240+
241+
func getHostname() {
242+
h.broadcastSys <- []byte("{\"Hostname\" : \"" + *hostname + "\"}")
243+
}
244+
245+
func getVersion() {
246+
h.broadcastSys <- []byte("{\"Version\" : \"" + version + "\"}")
247+
}
248+
249+
func garbageCollection() {
250+
log.Printf("Starting garbageCollection()\n")
251+
h.broadcastSys <- []byte("{\"gc\":\"starting\"}")
252+
memoryStats()
253+
debug.SetGCPercent(100)
254+
debug.FreeOSMemory()
255+
debug.SetGCPercent(-1)
256+
log.Printf("Done with garbageCollection()\n")
257+
h.broadcastSys <- []byte("{\"gc\":\"done\"}")
258+
memoryStats()
259+
}
260+
261+
func exit() {
262+
log.Println("Starting new spjs process")
263+
h.broadcastSys <- []byte("{\"Exiting\" : true}")
264+
log.Fatal("Exited current spjs cuz asked to")
265+
266+
}
267+
268+
func restart() {
269+
// relaunch ourself and exit
270+
// the relaunch works because we pass a cmdline in
271+
// that has serial-port-json-server only initialize 5 seconds later
272+
// which gives us time to exit and unbind from serial ports and TCP/IP
273+
// sockets like :8989
274+
log.Println("Starting new spjs process")
275+
h.broadcastSys <- []byte("{\"Restarting\" : true}")
276+
277+
// figure out current path of executable so we know how to restart
278+
// this process
279+
/*
280+
dir, err2 := filepath.Abs(filepath.Dir(os.Args[0]))
281+
if err2 != nil {
282+
//log.Fatal(err2)
283+
fmt.Printf("Error getting executable file path. err: %v\n", err2)
284+
}
285+
fmt.Printf("The path to this exe is: %v\n", dir)
286+
287+
// alternate approach
288+
_, filename, _, _ := runtime.Caller(1)
289+
f, _ := os.Open(path.Join(path.Dir(filename), "serial-port-json-server"))
290+
fmt.Println(f)
291+
*/
292+
293+
// using osext
294+
exePath, err3 := osext.Executable()
295+
if err3 != nil {
296+
fmt.Printf("Error getting exe path using osext lib. err: %v\n", err3)
297+
}
298+
fmt.Printf("exePath using osext: %v\n", exePath)
299+
300+
// figure out garbageCollection flag
301+
//isGcFlag := "false"
302+
303+
var cmd *exec.Cmd
304+
/*if *isGC {
305+
//isGcFlag = "true"
306+
cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter, "-gc")
307+
} else {
308+
cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter)
309+
310+
}*/
311+
cmd = exec.Command(exePath, "-ls", "-addr", *addr, "-regex", *regExpFilter, "-gc", *gcType)
312+
313+
//cmd := exec.Command("./serial-port-json-server", "ls")
314+
err := cmd.Start()
315+
if err != nil {
316+
log.Printf("Got err restarting spjs: %v\n", err)
317+
h.broadcastSys <- []byte("{\"Error\" : \"" + fmt.Sprintf("%v", err) + "\"}")
318+
} else {
319+
h.broadcastSys <- []byte("{\"Restarted\" : true}")
320+
}
321+
log.Fatal("Exited current spjs for restart")
322+
//log.Printf("Waiting for command to finish...")
323+
//err = cmd.Wait()
324+
//log.Printf("Command finished with error: %v", err)
325+
}
326+
327+
type CmdBroadcast struct {
328+
Cmd string
329+
Msg string
330+
}
331+
332+
func broadcast(arg string) {
333+
// we will get a string of broadcast asdf asdf asdf
334+
log.Println("Inside broadcast arg: " + arg)
335+
arg = strings.TrimPrefix(arg, " ")
336+
//log.Println("arg after trim: " + arg)
337+
args := strings.SplitN(arg, " ", 2)
338+
if len(args) != 2 {
339+
errstr := "Could not parse broadcast command: " + arg
340+
log.Println(errstr)
341+
spErr(errstr)
342+
return
343+
}
344+
broadcastcmd := strings.Trim(args[1], " ")
345+
log.Println("The broadcast cmd is:" + broadcastcmd + "---")
346+
347+
bcmd := CmdBroadcast{
348+
Cmd: "Broadcast",
349+
Msg: broadcastcmd,
350+
}
351+
json, _ := json.Marshal(bcmd)
352+
log.Printf("bcmd:%v\n", string(json))
353+
h.broadcastSys <- json
354+
355+
}

hub.go.REMOVED.git-id

-1
This file was deleted.

0 commit comments

Comments
 (0)