commit
1270f0cbc9
12 changed files with 1050 additions and 0 deletions
Unified View
Diff Options
-
55cfg/config.go
-
62cmd/gamepad/gamepad.go
-
45cmd/plotter/plotter.go
-
22cmd/setup/setup.go
-
97drawing.svg
-
96font-default.xml
-
7go.mod
-
6go.sum
-
38main.go
-
250pkg/comm/main.go
-
78pkg/plotter/font.go
-
294pkg/plotter/svg.go
@ -0,0 +1,55 @@ |
|||||
|
package cfg |
||||
|
|
||||
|
import "math" |
||||
|
|
||||
|
// CFG returns the configuration
|
||||
|
func CFG() Config { |
||||
|
cfg := Config{ |
||||
|
CircleResolution: 30, |
||||
|
MachineWidth: 1225, |
||||
|
MachineHeight: 800, |
||||
|
MachineMmPerRev: 37.7, |
||||
|
MachineStepsPerRev: 200, |
||||
|
MachineMotorAccel: 400, |
||||
|
MachineMotorSpeed: 800, |
||||
|
MachineStepMultiplier: 1, |
||||
|
DrawingArea: Area{ |
||||
|
TopLeft: Point{X: 400, Y: 250}, |
||||
|
BottomRight: Point{X: 800, Y: 500}, |
||||
|
Home: Point{X: 612.44, Y: 217.61}, |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
cfg.DrawingArea.Width = math.Abs(cfg.DrawingArea.BottomRight.X - cfg.DrawingArea.TopLeft.X) |
||||
|
cfg.DrawingArea.Height = math.Abs(cfg.DrawingArea.BottomRight.Y - cfg.DrawingArea.TopLeft.Y) |
||||
|
|
||||
|
return cfg |
||||
|
} |
||||
|
|
||||
|
// Point ...
|
||||
|
type Point struct { |
||||
|
X float64 |
||||
|
Y float64 |
||||
|
} |
||||
|
|
||||
|
// Area ...
|
||||
|
type Area struct { |
||||
|
Home Point |
||||
|
TopLeft Point |
||||
|
BottomRight Point |
||||
|
Width float64 |
||||
|
Height float64 |
||||
|
} |
||||
|
|
||||
|
// Config ...
|
||||
|
type Config struct { |
||||
|
DrawingArea Area |
||||
|
MachineWidth float64 |
||||
|
MachineHeight float64 |
||||
|
MachineMmPerRev float64 |
||||
|
MachineStepsPerRev float64 |
||||
|
MachineMotorSpeed float64 |
||||
|
MachineMotorAccel float64 |
||||
|
MachineStepMultiplier float64 |
||||
|
CircleResolution float64 |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
package gamepad |
||||
|
|
||||
|
import ( |
||||
|
"codeisalie/gono/pkg/comm" |
||||
|
"log" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/splace/joysticks" |
||||
|
) |
||||
|
|
||||
|
// Run initializes the plotter
|
||||
|
func Run(c *comm.Comm) { |
||||
|
motorsState := false |
||||
|
|
||||
|
device := joysticks.Connect(1) |
||||
|
|
||||
|
if device == nil { |
||||
|
panic("no HIDs") |
||||
|
} |
||||
|
|
||||
|
// using Connect allows a device to be interrogated
|
||||
|
log.Printf("HID#1:- Buttons:%d, Hats:%d\n", len(device.Buttons), len(device.HatAxes)/2) |
||||
|
|
||||
|
// get/assign channels for specific events
|
||||
|
b1press := device.OnClose(1) |
||||
|
b7press := device.OnClose(7) |
||||
|
b8press := device.OnClose(8) |
||||
|
b10press := device.OnClose(10) |
||||
|
h1move := device.OnMove(3) |
||||
|
|
||||
|
// start feeding OS events onto the event channels.
|
||||
|
go device.ParcelOutEvents() |
||||
|
|
||||
|
// handle event channels
|
||||
|
go func() { |
||||
|
for { |
||||
|
select { |
||||
|
case <-b1press: |
||||
|
log.Println("button #1 pressed") |
||||
|
case <-b7press: |
||||
|
log.Println("button #7 pressed") |
||||
|
case <-b8press: |
||||
|
log.Println("button #8 pressed") |
||||
|
case <-b10press: |
||||
|
log.Println("button #10 pressed", motorsState) |
||||
|
if motorsState == false { |
||||
|
// c.Send(comm.EnableMotors)
|
||||
|
motorsState = true |
||||
|
} else { |
||||
|
// c.Send(comm.DisableMotors)
|
||||
|
motorsState = false |
||||
|
} |
||||
|
case h := <-h1move: |
||||
|
hpos := h.(joysticks.CoordsEvent) |
||||
|
log.Println(".hat #1 moved too:", hpos) |
||||
|
} |
||||
|
} |
||||
|
}() |
||||
|
|
||||
|
time.Sleep(time.Second * 60) |
||||
|
log.Println("Shutting down due to timeout.") |
||||
|
} |
||||
@ -0,0 +1,45 @@ |
|||||
|
package plotter |
||||
|
|
||||
|
import ( |
||||
|
"codeisalie/gono/pkg/comm" |
||||
|
"codeisalie/gono/pkg/plotter" |
||||
|
"fmt" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
// Run ...
|
||||
|
func Run(c *comm.Comm) { |
||||
|
|
||||
|
svg := plotter.SvgParser{} |
||||
|
svg.Parse("drawing.svg", c.Cfg) |
||||
|
|
||||
|
// for _, path := range svg.Paths {
|
||||
|
// fmt.Printf("%+v\n", path)
|
||||
|
// for _, point := range path.List {
|
||||
|
// fmt.Printf("-- %+v\n", point)
|
||||
|
// }
|
||||
|
// }
|
||||
|
|
||||
|
// svg.Paths
|
||||
|
fmt.Println(svg.Root.ViewBox) |
||||
|
c.Send(comm.EnableMotors) |
||||
|
c.Send(comm.GetReportPosition) |
||||
|
for _, path := range svg.Paths { |
||||
|
fmt.Printf("%+v\n", path) |
||||
|
// if len(path.List) <= 1 {
|
||||
|
// continue
|
||||
|
// }
|
||||
|
c.Send(comm.SetPenUp) |
||||
|
for idx, point := range path.List { |
||||
|
c.Send(comm.DrawLine, point.X, point.Y, 1) |
||||
|
if idx == 0 && len(path.List) > 1 { |
||||
|
c.Send(comm.SetPenDown) |
||||
|
} |
||||
|
} |
||||
|
c.Send(comm.SetPenUp) |
||||
|
} |
||||
|
c.Send(comm.DrawLine, c.Cfg.DrawingArea.Home.X, c.Cfg.DrawingArea.Home.Y, 1) |
||||
|
c.Send(comm.DisableMotors) |
||||
|
|
||||
|
time.Sleep(2 * time.Second) |
||||
|
} |
||||
@ -0,0 +1,22 @@ |
|||||
|
package setup |
||||
|
|
||||
|
import ( |
||||
|
"codeisalie/gono/pkg/comm" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
// List ...
|
||||
|
type List []comm.SetCMD |
||||
|
|
||||
|
// Run initializes the plotter
|
||||
|
func Run(c *comm.Comm) { |
||||
|
|
||||
|
c.Send(comm.SetMachineSize, c.Cfg.MachineWidth, c.Cfg.MachineHeight) |
||||
|
c.Send(comm.SetMachineMmPerRev, c.Cfg.MachineMmPerRev) |
||||
|
c.Send(comm.SetMachineStepsPerRev, c.Cfg.MachineStepsPerRev) |
||||
|
c.Send(comm.SetMachineMotorSpeed, c.Cfg.MachineMotorSpeed) |
||||
|
c.Send(comm.SetMachineMotorAccel, c.Cfg.MachineMotorAccel) |
||||
|
c.Send(comm.SetMachineStepMultiplier, c.Cfg.MachineStepMultiplier) |
||||
|
|
||||
|
time.Sleep(5 * time.Second) |
||||
|
} |
||||
@ -0,0 +1,97 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
|
<!-- Created with Inkscape (http://www.inkscape.org/) --> |
||||
|
|
||||
|
<svg |
||||
|
xmlns:dc="http://purl.org/dc/elements/1.1/" |
||||
|
xmlns:cc="http://creativecommons.org/ns#" |
||||
|
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" |
||||
|
xmlns:svg="http://www.w3.org/2000/svg" |
||||
|
xmlns="http://www.w3.org/2000/svg" |
||||
|
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" |
||||
|
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" |
||||
|
width="200cm" |
||||
|
height="120cm" |
||||
|
viewBox="0 0 7086.614 4251.9685" |
||||
|
id="svg2" |
||||
|
version="1.1" |
||||
|
inkscape:version="0.91 r" |
||||
|
sodipodi:docname="drawing.svg"> |
||||
|
<defs |
||||
|
id="defs4" /> |
||||
|
<sodipodi:namedview |
||||
|
id="base" |
||||
|
pagecolor="#ffffff" |
||||
|
bordercolor="#666666" |
||||
|
borderopacity="1.0" |
||||
|
inkscape:pageopacity="0.0" |
||||
|
inkscape:pageshadow="2" |
||||
|
inkscape:zoom="0.175" |
||||
|
inkscape:cx="3198.9842" |
||||
|
inkscape:cy="2091.4294" |
||||
|
inkscape:document-units="px" |
||||
|
inkscape:current-layer="svg2" |
||||
|
showgrid="false" |
||||
|
units="cm" |
||||
|
inkscape:window-width="1920" |
||||
|
inkscape:window-height="1023" |
||||
|
inkscape:window-x="0" |
||||
|
inkscape:window-y="0" |
||||
|
inkscape:window-maximized="1" /> |
||||
|
<metadata |
||||
|
id="metadata7"> |
||||
|
<rdf:RDF> |
||||
|
<cc:Work |
||||
|
rdf:about=""> |
||||
|
<dc:format>image/svg+xml</dc:format> |
||||
|
<dc:type |
||||
|
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> |
||||
|
<dc:title /> |
||||
|
</cc:Work> |
||||
|
</rdf:RDF> |
||||
|
</metadata> |
||||
|
<path |
||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
||||
|
d="M 199.99976,4080.5397 6554.2855,337.68255" |
||||
|
id="path3370" |
||||
|
inkscape:connector-curvature="0" /> |
||||
|
<path |
||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
||||
|
d="m 4319.9998,2566.254 1291.4286,-11.4286 11.4285,-1080 1051.4286,62.8572" |
||||
|
id="path3372" |
||||
|
inkscape:connector-curvature="0" /> |
||||
|
<circle |
||||
|
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1" |
||||
|
id="path3368-3" |
||||
|
cx="3805.7141" |
||||
|
cy="1806.2543" |
||||
|
r="1005.7143" /> |
||||
|
<path |
||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
||||
|
d="M 565.71405,1131.9685 1262.8569,343.39708 1759.9998,1183.3971 542.8569,3086.2542" |
||||
|
id="path3384" |
||||
|
inkscape:connector-curvature="0" /> |
||||
|
<path |
||||
|
style="fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
||||
|
d="m 2845.7141,320.53993 -17.1429,331.42857 1880,-177.14285 z" |
||||
|
id="path3386" |
||||
|
inkscape:connector-curvature="0" /> |
||||
|
<flowRoot |
||||
|
xml:space="preserve" |
||||
|
id="flowRoot3483" |
||||
|
style="font-style:normal;font-weight:normal;font-size:40px;line-height:112.99999952%;font-family:sans-serif;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" |
||||
|
transform="translate(-2.4414063e-4,0)"><flowRegion |
||||
|
id="flowRegion3485"><rect |
||||
|
id="rect3487" |
||||
|
width="1011.4288" |
||||
|
height="148.57152" |
||||
|
x="217.14285" |
||||
|
y="360.53995" |
||||
|
style="line-height:112.99999952%" /></flowRegion><flowPara |
||||
|
id="flowPara3489" |
||||
|
style="font-size:125px;line-height:112.99999952%">HALLO WORLD</flowPara></flowRoot> <circle |
||||
|
style="fill:none;fill-opacity:1;stroke:#000000;stroke-opacity:1" |
||||
|
id="path3368-3-6" |
||||
|
cx="2588.5713" |
||||
|
cy="2686.2542" |
||||
|
r="1005.7143" /> |
||||
|
</svg> |
||||
@ -0,0 +1,96 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
|
|
||||
|
<root name="default" width="10" height="20" space="2"> |
||||
|
<letter id=" "> |
||||
|
<path>0,0</path> |
||||
|
</letter> |
||||
|
<letter id="A"> |
||||
|
<path>0,20 5,0 10,20</path> |
||||
|
<path>3,10 7,10</path> |
||||
|
</letter> |
||||
|
<letter id="B"> |
||||
|
<path>0,0 0,20 10,20 10,10 0,10</path> |
||||
|
<path>0,0 6,0 6,10</path> |
||||
|
</letter> |
||||
|
<letter id="C"> |
||||
|
<path>10,0 0,0 0,20 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="D"> |
||||
|
<path>0,0 7,0 10,3 10,17 8,20 0,20 0,0</path> |
||||
|
</letter> |
||||
|
<letter id="E"> |
||||
|
<path>10,0 0,0 0,10 10,10 0,10 0,20 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="F"> |
||||
|
<path>10,0 0,0 0,10 10,10 0,10 0,20</path> |
||||
|
</letter> |
||||
|
<letter id="G"> |
||||
|
<path>10,0 0,0 0,20 10,20 10,10 5,10</path> |
||||
|
</letter> |
||||
|
<letter id="H"> |
||||
|
<path>0,0 0,20 0,10 10,10 10,0 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="I"> |
||||
|
<path>2,0 8,0 5,0 5,20 2,20 8,20</path> |
||||
|
</letter> |
||||
|
<letter id="J"> |
||||
|
<path>0,10 0,20 10,20 10,0</path> |
||||
|
</letter> |
||||
|
<letter id="K"> |
||||
|
<path>0,0 0,20</path> |
||||
|
<path>10,0 0,10 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="L"> |
||||
|
<path>0,0 0,20 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="M"> |
||||
|
<path>0,20 0,0 5,10 10,0 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="N"> |
||||
|
<path>0,20 0,0 10,20 10,0</path> |
||||
|
</letter> |
||||
|
<letter id="O"> |
||||
|
<path>0,2 2,0 8,0 10,2 10,18 8,20 2,20 0,18 0,2</path> |
||||
|
</letter> |
||||
|
<letter id="P"> |
||||
|
<path>0,20 0,0 8,0 10,2 10,8 8,10 0,10</path> |
||||
|
</letter> |
||||
|
<letter id="Q"> |
||||
|
<path>0,2 2,0 8,0 10,2 10,18 8,20 2,20 0,18 0,2</path> |
||||
|
<path>7,17 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="R"> |
||||
|
<path>0,20 0,0 8,0 10,2 10,8 8,10 0,10</path> |
||||
|
<path>8,10 10,12 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="S"> |
||||
|
<path>10,0 2,0 0,2 0,8 2,10 8,10 10,12 10,18 8,20 0,20</path> |
||||
|
</letter> |
||||
|
<letter id="T"> |
||||
|
<path>0,0 10,0</path> |
||||
|
<path>5,0 5,20</path> |
||||
|
</letter> |
||||
|
<letter id="U"> |
||||
|
<path>0,2 0,18 2,20 8,20 10,18 10,2</path> |
||||
|
</letter> |
||||
|
<letter id="V"> |
||||
|
<path>0,0 5,20 10,0</path> |
||||
|
</letter> |
||||
|
<letter id="W"> |
||||
|
<path>0,0 3,20 5,10 7,20 10,0</path> |
||||
|
</letter> |
||||
|
<letter id="X"> |
||||
|
<path>0,0 10,20</path> |
||||
|
<path>10,0 0,20</path> |
||||
|
</letter> |
||||
|
<letter id="Y"> |
||||
|
<path>0,0 5,10 10,0</path> |
||||
|
<path>5,10 5,20</path> |
||||
|
</letter> |
||||
|
<letter id="Z"> |
||||
|
<path>0,0 10,0 0,20 10,20</path> |
||||
|
</letter> |
||||
|
<letter id="b"> |
||||
|
<path>0,0 0,7 10,12 10,18 8,20 0,20 0,0</path> |
||||
|
</letter> |
||||
|
</root> |
||||
@ -0,0 +1,7 @@ |
|||||
|
module codeisalie/gono |
||||
|
|
||||
|
require ( |
||||
|
github.com/splace/joysticks v0.0.0-20180907185707-7416f8bb58bd |
||||
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 |
||||
|
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 // indirect |
||||
|
) |
||||
@ -0,0 +1,6 @@ |
|||||
|
github.com/splace/joysticks v0.0.0-20180907185707-7416f8bb58bd h1:WO95lkUpx1EbYOnppBa8i/fEY6t2itFxK5LCCRcgzKQ= |
||||
|
github.com/splace/joysticks v0.0.0-20180907185707-7416f8bb58bd/go.mod h1:PQPCtmjcD4hfFT4yHSY7zomN8fvov8fFvQWYSth8L34= |
||||
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07 h1:UyzmZLoiDWMRywV4DUYb9Fbt8uiOSooupjTq10vpvnU= |
||||
|
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= |
||||
|
golang.org/x/sys v0.0.0-20190209173611-3b5209105503 h1:5SvYFrOM3W8Mexn9/oA44Ji7vhXAZQ9hiP+1Q/DMrWg= |
||||
|
golang.org/x/sys v0.0.0-20190209173611-3b5209105503/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
||||
@ -0,0 +1,38 @@ |
|||||
|
package main |
||||
|
|
||||
|
import ( |
||||
|
"codeisalie/gono/cfg" |
||||
|
"codeisalie/gono/cmd/gamepad" |
||||
|
"codeisalie/gono/cmd/plotter" |
||||
|
"codeisalie/gono/cmd/setup" |
||||
|
"codeisalie/gono/pkg/comm" |
||||
|
"flag" |
||||
|
"log" |
||||
|
) |
||||
|
|
||||
|
func main() { |
||||
|
var setupMode, gameMode bool |
||||
|
flag.BoolVar(&setupMode, "setup", false, "Setup plotter machine") |
||||
|
flag.BoolVar(&gameMode, "game", false, "Gamepad mode") |
||||
|
flag.Parse() |
||||
|
|
||||
|
CFG := cfg.CFG() |
||||
|
|
||||
|
if setupMode { |
||||
|
log.Println("[>] Running mode: gamepad") |
||||
|
} else if gameMode { |
||||
|
log.Println("[>] Running mode: setup") |
||||
|
} else { |
||||
|
log.Println("[>] Running mode: plotter") |
||||
|
} |
||||
|
|
||||
|
c := comm.Init("", CFG) |
||||
|
|
||||
|
if gameMode { |
||||
|
gamepad.Run(c) |
||||
|
} else if setupMode { |
||||
|
setup.Run(c) |
||||
|
} else { |
||||
|
plotter.Run(c) |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,250 @@ |
|||||
|
package comm |
||||
|
|
||||
|
import ( |
||||
|
"codeisalie/gono/cfg" |
||||
|
"fmt" |
||||
|
"log" |
||||
|
"math" |
||||
|
"regexp" |
||||
|
"sync" |
||||
|
"time" |
||||
|
|
||||
|
"github.com/tarm/serial" |
||||
|
) |
||||
|
|
||||
|
const ( |
||||
|
// SetPenDown ...
|
||||
|
SetPenDown string = "C13" |
||||
|
// SetPenUp ... - args = 0
|
||||
|
SetPenUp string = "C14" |
||||
|
// SetMachineSize saves machine width and height - args = 2
|
||||
|
SetMachineSize string = "C24" |
||||
|
// SetMachineMmPerRev ... - args = 1
|
||||
|
SetMachineMmPerRev string = "C29" |
||||
|
// SetMachineStepsPerRev ... - args = 1
|
||||
|
SetMachineStepsPerRev string = "C30" |
||||
|
// SetMachineMotorSpeed ... - args = 1
|
||||
|
SetMachineMotorSpeed string = "C31" |
||||
|
// SetMachineMotorAccel ... - args = 1
|
||||
|
SetMachineMotorAccel string = "C32" |
||||
|
// SetMachineStepMultiplier ... - args = 1
|
||||
|
SetMachineStepMultiplier string = "C37" |
||||
|
// GetMachineDetails ... - args = 0
|
||||
|
GetMachineDetails string = "C26" |
||||
|
// DisableMotors ...
|
||||
|
DisableMotors string = "CA0" |
||||
|
// EnableMotors ...
|
||||
|
EnableMotors string = "CA1" |
||||
|
// DrawLine ... - args = 0
|
||||
|
DrawLine string = "C17" |
||||
|
// DrawCircle ... - args = 0
|
||||
|
DrawCircle string = "CB0" |
||||
|
// GetReportPosition ...
|
||||
|
GetReportPosition string = "CC0" |
||||
|
) |
||||
|
|
||||
|
// SetCMD saves one EEPROM command
|
||||
|
type SetCMD struct { |
||||
|
Cmd string |
||||
|
Args []float64 |
||||
|
} |
||||
|
|
||||
|
// Comm context
|
||||
|
type Comm struct { |
||||
|
isReady bool |
||||
|
mutex sync.Mutex |
||||
|
sync chan int |
||||
|
list chan string |
||||
|
com string |
||||
|
Cfg cfg.Config |
||||
|
serialCfg *serial.Config |
||||
|
handler *serial.Port |
||||
|
} |
||||
|
|
||||
|
// Init returns an initialized serial handler
|
||||
|
// Def: /dev/ttyACM0
|
||||
|
func Init(com string, cfg cfg.Config) *Comm { |
||||
|
|
||||
|
c := Comm{} |
||||
|
c.list = make(chan string) |
||||
|
c.sync = make(chan int) |
||||
|
c.Cfg = cfg |
||||
|
|
||||
|
if com == "" { |
||||
|
com = "/dev/ttyACM0" |
||||
|
} |
||||
|
|
||||
|
c.com = com |
||||
|
|
||||
|
c.serialCfg = &serial.Config{Name: c.com, Baud: 57600} |
||||
|
handler, err := serial.OpenPort(c.serialCfg) |
||||
|
if err != nil { |
||||
|
log.Println(err) |
||||
|
return &c |
||||
|
} |
||||
|
|
||||
|
log.Printf("[-] comm | %v opened\n", c.com) |
||||
|
|
||||
|
c.handler = handler |
||||
|
|
||||
|
go c.readSerial() |
||||
|
log.Printf("[-] comm | Waiting plotter stating\n") |
||||
|
<-c.sync |
||||
|
log.Printf("[-] comm | Plotter ready\n") |
||||
|
go c.sendMsg() |
||||
|
|
||||
|
// q := make(chan os.Signal, 1)
|
||||
|
// signal.Notify(q, os.Interrupt)
|
||||
|
// go func() {
|
||||
|
// for sig := range q {
|
||||
|
// fmt.Println(sig)
|
||||
|
// close(c.list)
|
||||
|
// close(c.sync)
|
||||
|
// }
|
||||
|
// }()
|
||||
|
|
||||
|
return &c |
||||
|
} |
||||
|
|
||||
|
// Queue one new message to send to serial interface
|
||||
|
func (c *Comm) Queue(msg string) { |
||||
|
c.list <- msg |
||||
|
} |
||||
|
|
||||
|
// Send ...
|
||||
|
func (c *Comm) Send(cmd string, args ...float64) { |
||||
|
msg := cmd |
||||
|
switch cmd { |
||||
|
case DrawLine: |
||||
|
r1, r2 := c.convertCartToPolar(args[0], args[1]) |
||||
|
args[0] = math.Floor(r1*100) / 100 |
||||
|
args[1] = math.Floor(r2*100) / 100 |
||||
|
} |
||||
|
for _, arg := range args { |
||||
|
msg += fmt.Sprintf(",%v", arg) |
||||
|
} |
||||
|
msg += ",END;" |
||||
|
// fmt.Println(msg)
|
||||
|
c.Queue(msg) |
||||
|
} |
||||
|
|
||||
|
// SendPPP one message to machine
|
||||
|
func (c *Comm) SendPPP(cmd SetCMD) { |
||||
|
msg := cmd.Cmd |
||||
|
switch cmd.Cmd { |
||||
|
case DrawLine: |
||||
|
r1, r2 := c.convertCartToPolar(cmd.Args[0], cmd.Args[1]) |
||||
|
cmd.Args[0] = r1 |
||||
|
cmd.Args[1] = r2 |
||||
|
} |
||||
|
for _, arg := range cmd.Args { |
||||
|
msg += fmt.Sprintf(",%v", arg) |
||||
|
} |
||||
|
msg += ",END;" |
||||
|
// fmt.Println(msg)
|
||||
|
c.Queue(msg) |
||||
|
} |
||||
|
|
||||
|
func (c *Comm) convertCartToPolar(x, y float64) (float64, float64) { |
||||
|
r1 := math.Sqrt(math.Pow(x, 2) + math.Pow(y, 2)) |
||||
|
r2 := math.Sqrt(math.Pow(c.Cfg.MachineWidth-x, 2) + math.Pow(y, 2)) |
||||
|
return r1, r2 |
||||
|
} |
||||
|
|
||||
|
// Send a message when it's serial com is ready
|
||||
|
func (c *Comm) sendMsg() { |
||||
|
log.Printf("[-] comm | routine sendMsg started\n") |
||||
|
for { |
||||
|
<-c.sync |
||||
|
c.mutex.Lock() |
||||
|
c.isReady = true |
||||
|
c.mutex.Unlock() |
||||
|
time.Sleep(100 * time.Millisecond) |
||||
|
msg := <-c.list |
||||
|
log.Printf("[-] comm | Sending: %v\n", msg) |
||||
|
_, err := c.handler.Write([]byte(msg)) |
||||
|
if err != nil { |
||||
|
log.Fatal(err) |
||||
|
} else { |
||||
|
// log.Println("written", n)
|
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Comm) GetIsReady() { |
||||
|
isReady := false |
||||
|
c.mutex.Lock() |
||||
|
isReady = c.isReady |
||||
|
c.mutex.Unlock() |
||||
|
|
||||
|
return isReady |
||||
|
} |
||||
|
|
||||
|
func (c *Comm) processSerialMsg(msg string) { |
||||
|
reReady := regexp.MustCompile("READY") |
||||
|
if reReady.MatchString(msg) { |
||||
|
c.sync <- 0 |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (c *Comm) readSerial() { |
||||
|
log.Printf("[-] comm | routine readSerial started\n") |
||||
|
|
||||
|
var char byte |
||||
|
var msg string |
||||
|
cr := byte('\r') |
||||
|
eol := byte('\n') |
||||
|
baf := make([]byte, 1) |
||||
|
buf := make([]byte, 128) |
||||
|
ptr := 0 |
||||
|
for { |
||||
|
n, err := c.handler.Read(baf) |
||||
|
if err != nil { |
||||
|
log.Fatal(err) |
||||
|
} |
||||
|
|
||||
|
if n != 1 { |
||||
|
continue |
||||
|
} |
||||
|
|
||||
|
char = baf[0] |
||||
|
|
||||
|
if char == cr || char == eol { |
||||
|
if ptr > 0 { |
||||
|
msg = string(buf[:ptr]) |
||||
|
fmt.Println(msg) |
||||
|
c.processSerialMsg(msg) |
||||
|
} |
||||
|
ptr = 0 |
||||
|
} else { |
||||
|
buf[ptr] = char |
||||
|
ptr++ |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// codeReady := []byte("READY")
|
||||
|
// reReady := regexp.MustCompile("READY")
|
||||
|
// reSync := regexp.MustCompile("SYNC,(.*),(.*),END")
|
||||
|
|
||||
|
// n, err := s.Read(buf)
|
||||
|
// if err != nil {
|
||||
|
// log.Fatal(err)
|
||||
|
// }
|
||||
|
// msg := string(buf[:n])
|
||||
|
// fmt.Printf("%v", msg)
|
||||
|
|
||||
|
// if reReady.Match(buf) {
|
||||
|
// // fmt.Print("READY FROM RE")
|
||||
|
// sync <- 0
|
||||
|
// } else {
|
||||
|
// // match := reSync.FindAllSubmatch(buf, -1)
|
||||
|
// // if len(match) > 0 {
|
||||
|
// // r1 := string(match[0][1])
|
||||
|
// // r2 := string(match[0][2])
|
||||
|
// // r1i, _ := strconv.Atoi(r1)
|
||||
|
// // r2i, _ := strconv.Atoi(r2)
|
||||
|
// // x, y := getXY(float64(r1i), float64(r2i))
|
||||
|
// // fmt.Printf("R1: %v, R2:%v - X:%v - Y:%v\n", r1i, r2i, x, y)
|
||||
|
// // }
|
||||
|
// }
|
||||
@ -0,0 +1,78 @@ |
|||||
|
package plotter |
||||
|
|
||||
|
import ( |
||||
|
"encoding/xml" |
||||
|
"fmt" |
||||
|
"io/ioutil" |
||||
|
"os" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
type OneChar struct { |
||||
|
Letter rune |
||||
|
Root XMLFont |
||||
|
Path []*Point |
||||
|
} |
||||
|
|
||||
|
// XMLChar ...
|
||||
|
type XMLChar struct { |
||||
|
XMLName xml.Name `xml:"letter"` |
||||
|
ID string `xml:"id,attr"` |
||||
|
Paths []string `xml:"path"` |
||||
|
// XMLName xml.Name `xml:"bite"`
|
||||
|
// ID rune `xml:"id,attr"`
|
||||
|
// Paths []XMLPath `xml:"path"`
|
||||
|
} |
||||
|
|
||||
|
// XMLFont ...
|
||||
|
type XMLFont struct { |
||||
|
XMLName xml.Name `xml:"root"` |
||||
|
Name string `xml:"name,attr"` |
||||
|
Width float64 `xml:"width,attr"` |
||||
|
Height float64 `xml:"height,attr"` |
||||
|
Space float64 `xml:"space,attr"` |
||||
|
Letters []XMLChar `xml:"letter"` |
||||
|
} |
||||
|
|
||||
|
type FontParser struct { |
||||
|
Root XMLFont |
||||
|
ByLetter map[rune][]*OnePath |
||||
|
} |
||||
|
|
||||
|
// Parse one font file
|
||||
|
func (f *FontParser) Parse(fontPath string) { |
||||
|
// Open our xmlFile
|
||||
|
xmlFile, err := os.Open(fontPath) |
||||
|
// if we os.Open returns an error then handle it
|
||||
|
if err != nil { |
||||
|
fmt.Println(err) |
||||
|
} |
||||
|
|
||||
|
fmt.Println("Successfully Opened " + fontPath) |
||||
|
// defer the closing of our xmlFile so that we can parse it later on
|
||||
|
defer xmlFile.Close() |
||||
|
|
||||
|
// read our opened xmlFile as a byte array.
|
||||
|
byteValue, _ := ioutil.ReadAll(xmlFile) |
||||
|
|
||||
|
xml.Unmarshal(byteValue, &f.Root) |
||||
|
|
||||
|
f.ByLetter = make(map[rune][]*OnePath) |
||||
|
|
||||
|
for _, letter := range f.Root.Letters { |
||||
|
for _, path := range letter.Paths { |
||||
|
onePath := OnePath{} |
||||
|
onePath.Type = TypeText |
||||
|
for _, pt := range strings.Split(path, " ") { |
||||
|
ptSt := strings.Split(pt, ",") |
||||
|
point := Point{} |
||||
|
point.X, _ = strconv.ParseFloat(ptSt[0], 64) |
||||
|
point.Y, _ = strconv.ParseFloat(ptSt[1], 64) |
||||
|
onePath.List = append(onePath.List, &point) |
||||
|
} |
||||
|
letterID := []rune(letter.ID)[0] |
||||
|
f.ByLetter[letterID] = append(f.ByLetter[letterID], &onePath) |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,294 @@ |
|||||
|
package plotter |
||||
|
|
||||
|
import ( |
||||
|
"codeisalie/gono/cfg" |
||||
|
"encoding/xml" |
||||
|
"fmt" |
||||
|
"io/ioutil" |
||||
|
"math" |
||||
|
"os" |
||||
|
"regexp" |
||||
|
"strconv" |
||||
|
"strings" |
||||
|
) |
||||
|
|
||||
|
// XMLSvg ...
|
||||
|
type XMLSvg struct { |
||||
|
XMLName xml.Name `xml:"svg"` |
||||
|
Width string `xml:"width,attr"` |
||||
|
Height string `xml:"height,attr"` |
||||
|
ViewBox string `xml:"viewBox,attr"` |
||||
|
Paths []XMLPath `xml:"path"` |
||||
|
Circles []XMLCircle `xml:"circle"` |
||||
|
Texts []XMLFlowRoot `xml:"flowRoot"` |
||||
|
} |
||||
|
|
||||
|
// XMLPath ...
|
||||
|
type XMLPath struct { |
||||
|
XMLName xml.Name `xml:"path"` |
||||
|
Style string `xml:"style,attr"` |
||||
|
Data string `xml:"d,attr"` |
||||
|
} |
||||
|
|
||||
|
// XMLCircle ...
|
||||
|
type XMLCircle struct { |
||||
|
XMLName xml.Name `xml:"circle"` |
||||
|
CenterX float64 `xml:"cx,attr"` |
||||
|
CenterY float64 `xml:"cy,attr"` |
||||
|
Radius float64 `xml:"r,attr"` |
||||
|
} |
||||
|
|
||||
|
// XMLFlowRoot ...
|
||||
|
type XMLFlowRoot struct { |
||||
|
XMLName xml.Name `xml:"flowRoot"` |
||||
|
Rec XMLFlowRec `xml:"flowRegion>rect"` |
||||
|
Text string `xml:"flowPara"` |
||||
|
Transform string `xml:"transform,attr"` |
||||
|
} |
||||
|
|
||||
|
type XMLFlowRec struct { |
||||
|
XMLName xml.Name `xml:"rect"` |
||||
|
X float64 `xml:"x,attr"` |
||||
|
Y float64 `xml:"y,attr"` |
||||
|
Width float64 `xml:"width,attr"` |
||||
|
Height float64 `xml:"height,attr"` |
||||
|
} |
||||
|
|
||||
|
// Svg ...
|
||||
|
type Svg struct { |
||||
|
OriginX float64 |
||||
|
OriginY float64 |
||||
|
Width float64 |
||||
|
Height float64 |
||||
|
} |
||||
|
|
||||
|
// Point ...
|
||||
|
type Point struct { |
||||
|
X float64 |
||||
|
Y float64 |
||||
|
} |
||||
|
|
||||
|
// OnePath ...
|
||||
|
type OnePath struct { |
||||
|
// StartAt Point
|
||||
|
Center Point |
||||
|
Type int |
||||
|
List []*Point |
||||
|
} |
||||
|
|
||||
|
// SvgParser struct
|
||||
|
type SvgParser struct { |
||||
|
Root XMLSvg |
||||
|
Svg Svg |
||||
|
Font FontParser |
||||
|
cfg cfg.Config |
||||
|
Paths []OnePath |
||||
|
} |
||||
|
|
||||
|
const ( |
||||
|
ModeAbsolute int = 100 + iota |
||||
|
ModeRelative |
||||
|
TypePath int = 200 + iota |
||||
|
TypeCircle |
||||
|
TypeText |
||||
|
) |
||||
|
|
||||
|
func rads(deg float64) float64 { |
||||
|
return deg * math.Pi / 180.0 |
||||
|
} |
||||
|
|
||||
|
// Parse on SVG file
|
||||
|
func (s *SvgParser) Parse(svgPath string, cfg cfg.Config) { |
||||
|
// Open our xmlFile
|
||||
|
xmlFile, err := os.Open(svgPath) |
||||
|
// if we os.Open returns an error then handle it
|
||||
|
if err != nil { |
||||
|
fmt.Println(err) |
||||
|
} |
||||
|
|
||||
|
fmt.Println("Successfully Opened " + svgPath) |
||||
|
// defer the closing of our xmlFile so that we can parse it later on
|
||||
|
defer xmlFile.Close() |
||||
|
|
||||
|
// read our opened xmlFile as a byte array.
|
||||
|
byteValue, _ := ioutil.ReadAll(xmlFile) |
||||
|
|
||||
|
// we unmarshal our byteArray which contains our
|
||||
|
// xmlFiles content into 'users' which we defined above
|
||||
|
xml.Unmarshal(byteValue, &s.Root) |
||||
|
|
||||
|
s.Font = FontParser{} |
||||
|
s.Font.Parse("font-default.xml") |
||||
|
|
||||
|
s.cfg = cfg |
||||
|
|
||||
|
s.Svg = Svg{} |
||||
|
reViewboxSrc := regexp.MustCompile("(.*) (.*) (.*) (.*)") |
||||
|
reViewboxRes := reViewboxSrc.FindAllStringSubmatch(s.Root.ViewBox, -1) |
||||
|
|
||||
|
s.Svg.OriginX, _ = strconv.ParseFloat(reViewboxRes[0][1], 64) |
||||
|
s.Svg.OriginY, _ = strconv.ParseFloat(reViewboxRes[0][2], 64) |
||||
|
s.Svg.Width, _ = strconv.ParseFloat(reViewboxRes[0][3], 64) |
||||
|
s.Svg.Height, _ = strconv.ParseFloat(reViewboxRes[0][4], 64) |
||||
|
|
||||
|
// fmt.Println(s.Root.Texts)
|
||||
|
|
||||
|
s.ProcessPaths() |
||||
|
s.ProcessCircles() |
||||
|
s.ProcessTexts() |
||||
|
|
||||
|
for _, path := range s.Paths { |
||||
|
for _, point := range path.List { |
||||
|
point.X = point.X*s.cfg.DrawingArea.Width/s.Svg.Width + s.cfg.DrawingArea.TopLeft.X |
||||
|
point.Y = -point.Y*s.cfg.DrawingArea.Height/s.Svg.Height + s.cfg.DrawingArea.BottomRight.Y |
||||
|
path.Center.X += point.X |
||||
|
path.Center.Y += point.Y |
||||
|
} |
||||
|
|
||||
|
path.Center.X /= float64(len(path.List)) |
||||
|
path.Center.Y /= float64(len(path.List)) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *SvgParser) ProcessTexts() { |
||||
|
reTranslate := regexp.MustCompile(`translate\((.*),(.*)\)`) |
||||
|
for _, text := range s.Root.Texts { |
||||
|
msg := text.Text |
||||
|
zoomH := text.Rec.Height / s.Font.Root.Height |
||||
|
zoomW := zoomH * s.Font.Root.Width / s.Font.Root.Width |
||||
|
origin := Point{ |
||||
|
X: text.Rec.X, |
||||
|
Y: s.Svg.Height - (text.Rec.Y - s.Font.Root.Height), |
||||
|
} |
||||
|
posX := 0.0 |
||||
|
posY := 0.0 |
||||
|
|
||||
|
values := reTranslate.FindAllStringSubmatch(text.Transform, -1) |
||||
|
if values != nil { |
||||
|
tPoint := Point{} |
||||
|
tPoint.X, _ = strconv.ParseFloat(values[0][1], 64) |
||||
|
tPoint.Y, _ = strconv.ParseFloat(values[0][2], 64) |
||||
|
origin.X += tPoint.X |
||||
|
origin.Y += tPoint.Y |
||||
|
} |
||||
|
|
||||
|
// fmt.Println("ORIGIN", origin)
|
||||
|
|
||||
|
for _, char := range msg { |
||||
|
seq, ok := s.Font.ByLetter[char] |
||||
|
if !ok { |
||||
|
fmt.Println("Unknown char", char) |
||||
|
seq = s.Font.ByLetter[' '] |
||||
|
} |
||||
|
|
||||
|
for _, path := range seq { |
||||
|
fmt.Println(path) |
||||
|
onePath := OnePath{ |
||||
|
Type: TypeText, |
||||
|
} |
||||
|
for _, pt := range path.List { |
||||
|
point := Point{ |
||||
|
X: pt.X*zoomW + posX + origin.X, |
||||
|
Y: (s.Font.Root.Height-pt.Y)*zoomH + posY + origin.Y, |
||||
|
} |
||||
|
// fmt.Println("POINT", point)
|
||||
|
onePath.List = append(onePath.List, &point) |
||||
|
} |
||||
|
s.Paths = append(s.Paths, onePath) |
||||
|
} |
||||
|
posX += (s.Font.Root.Width + s.Font.Root.Space) * zoomW |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *SvgParser) ProcessCircles() { |
||||
|
for _, circle := range s.Root.Circles { |
||||
|
var angle float64 |
||||
|
onePath := OnePath{} |
||||
|
onePath.Type = TypeCircle |
||||
|
segments := s.cfg.CircleResolution |
||||
|
for angle = 360 / segments; angle <= 360; angle += 360 / segments { |
||||
|
point := Point{} |
||||
|
point.X = circle.CenterX + circle.Radius*math.Cos(rads(angle)) |
||||
|
point.Y = s.Svg.Height - circle.CenterY + circle.Radius*math.Sin(rads(angle)) |
||||
|
// s.Scale(&point)
|
||||
|
onePath.List = append(onePath.List, &point) |
||||
|
} |
||||
|
pointEnd := Point{ |
||||
|
X: onePath.List[0].X, |
||||
|
Y: onePath.List[0].Y, |
||||
|
} |
||||
|
onePath.List = append(onePath.List, &pointEnd) |
||||
|
s.Paths = append(s.Paths, onePath) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *SvgParser) ProcessPaths() { |
||||
|
rePosSrc := regexp.MustCompile("(.*),(.*)") |
||||
|
for _, path := range s.Root.Paths { |
||||
|
var mode int |
||||
|
var size int |
||||
|
onePath := OnePath{} |
||||
|
onePath.Type = TypePath |
||||
|
segs := strings.Split(path.Data, " ") |
||||
|
for _, seg := range segs { |
||||
|
switch { |
||||
|
case seg == "M": |
||||
|
// fmt.Println("Absolute")
|
||||
|
mode = ModeAbsolute |
||||
|
case seg == "m": |
||||
|
// fmt.Println("Relative")
|
||||
|
mode = ModeRelative |
||||
|
case seg == "z": |
||||
|
// fmt.Println("Zero")
|
||||
|
point := Point{ |
||||
|
X: onePath.List[0].X, |
||||
|
Y: onePath.List[0].Y, |
||||
|
} |
||||
|
onePath.List = append(onePath.List, &point) |
||||
|
default: |
||||
|
point := Point{} |
||||
|
seqRes := rePosSrc.FindAllStringSubmatch(seg, -1) |
||||
|
if seqRes == nil { |
||||
|
fmt.Printf("Unknown seg: %v\n", seg) |
||||
|
continue |
||||
|
} |
||||
|
point.X, _ = strconv.ParseFloat(seqRes[0][1], 64) |
||||
|
point.Y, _ = strconv.ParseFloat(seqRes[0][2], 64) |
||||
|
size = len(onePath.List) |
||||
|
|
||||
|
if mode == ModeRelative && size > 0 { |
||||
|
prevPoint := onePath.List[size-1] |
||||
|
// fmt.Println(prevPoint, point)
|
||||
|
point.X = point.X + prevPoint.X |
||||
|
point.Y = prevPoint.Y - point.Y |
||||
|
} else { |
||||
|
point.Y = s.Svg.Height - point.Y |
||||
|
} |
||||
|
|
||||
|
onePath.List = append(onePath.List, &point) |
||||
|
} |
||||
|
} |
||||
|
s.Paths = append(s.Paths, onePath) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *SvgParser) ScalePath(path *OnePath) { |
||||
|
// var point *Point
|
||||
|
// for idx := range path.List {
|
||||
|
// pX := (*path).List[idx]
|
||||
|
// pointCell := path.List[idx]
|
||||
|
// fmt.Printf(">%v %p\n", idx, point)
|
||||
|
// path.List[idx].X = path.List[idx].X*s.cfg.DrawingArea.Width/s.Svg.Width + s.cfg.DrawingArea.TopLeft.X
|
||||
|
// path.List[idx].Y = -path.List[idx].Y*s.cfg.DrawingArea.Height/s.Svg.Height + s.cfg.DrawingArea.BottomRight.Y
|
||||
|
// }
|
||||
|
} |
||||
|
|
||||
|
func (s *SvgParser) Scale(point *Point) { |
||||
|
(*point).X = point.X*s.cfg.DrawingArea.Width/s.Svg.Width + s.cfg.DrawingArea.TopLeft.X |
||||
|
(*point).Y = -point.Y*s.cfg.DrawingArea.Height/s.Svg.Height + s.cfg.DrawingArea.BottomRight.Y |
||||
|
} |
||||
|
|
||||
|
func (path *OnePath) process(cfg cfg.Config) { |
||||
|
|
||||
|
} |
||||
Write
Preview
Loading…
Cancel
Save