diff --git a/app/modbus-data-viewer/.gitignore b/app/modbus-data-viewer/.gitignore
new file mode 100644
index 0000000..9aca816
--- /dev/null
+++ b/app/modbus-data-viewer/.gitignore
@@ -0,0 +1,4 @@
+bin/
+pkg/
+src/github.com/
+release/
diff --git a/app/modbus-data-viewer/build.sh b/app/modbus-data-viewer/build.sh
new file mode 100755
index 0000000..bb730ca
--- /dev/null
+++ b/app/modbus-data-viewer/build.sh
@@ -0,0 +1,4 @@
+#!/bin/bash
+
+GOPATH=$PWD go get -v service-web
+GOPATH=$PWD GOARCH=arm GOOS=linux go install service-web
diff --git a/app/modbus-data-viewer/release.sh b/app/modbus-data-viewer/release.sh
new file mode 100755
index 0000000..4b430dd
--- /dev/null
+++ b/app/modbus-data-viewer/release.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+./build.sh
+
+if [ ! -d release ]; then
+ mkdir release
+else
+ rm -rf release/*
+fi
+
+cp bin/linux_arm/service-web release/service-web
+cp -rf src/service-web/templates release/
diff --git a/app/modbus-data-viewer/src/service-web/main.go b/app/modbus-data-viewer/src/service-web/main.go
new file mode 100644
index 0000000..6e27124
--- /dev/null
+++ b/app/modbus-data-viewer/src/service-web/main.go
@@ -0,0 +1,104 @@
+package main
+
+import (
+ "bytes"
+ "encoding/binary"
+ "fmt"
+ "html/template"
+ "log"
+ "net"
+ "sync"
+
+ "github.com/codegangsta/martini"
+ "github.com/codegangsta/martini-contrib/render"
+)
+
+type Header int32
+type Packet [50]uint16
+
+var mutex sync.Mutex
+var templateMap = make(map[string]interface{})
+var controlTable, stateTable string
+
+func main() {
+ go ListenUDP()
+
+ m := martini.Classic()
+
+ m.Use(render.Renderer())
+
+ m.Get("/", func(r render.Render) {
+ mutex.Lock()
+ defer mutex.Unlock()
+
+ r.HTML(200, "main", templateMap)
+ })
+
+ m.Run()
+}
+
+func ListenUDP() {
+ addr, err := net.ResolveUDPAddr("udp", ":40001")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ conn, err := net.ListenUDP("udp", addr)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer conn.Close()
+
+ for {
+ b := make([]byte, 1024)
+ _, _, err := conn.ReadFromUDP(b)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ buf := bytes.NewReader(b)
+
+ var header Header
+ err = binary.Read(buf, binary.LittleEndian, &header)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var packet Packet
+ err = binary.Read(buf, binary.LittleEndian, &packet)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ switch header {
+ case 0:
+ mapControl(packet)
+ case 1:
+ mapState(packet)
+ }
+ }
+}
+
+func mapControl(packet Packet) {
+ mutex.Lock()
+ defer mutex.Unlock()
+
+ controlTable = ""
+ for i, v := range packet {
+ controlTable += fmt.Sprintf("
%v | 0x%04X | 0x%04X | %d |
\n", 30001+i, i, v, v)
+ }
+
+ templateMap["Table_Control"] = template.HTML(controlTable)
+}
+
+func mapState(packet Packet) {
+ mutex.Lock()
+ defer mutex.Unlock()
+
+ stateTable = ""
+ for i, v := range packet {
+ stateTable += fmt.Sprintf("%v | 0x%04X | 0x%04X | %d |
\n", 40001+i, i, v, v)
+ }
+
+ templateMap["Table_State"] = template.HTML(stateTable)
+}
diff --git a/app/modbus-data-viewer/src/service-web/templates/main.tmpl b/app/modbus-data-viewer/src/service-web/templates/main.tmpl
new file mode 100644
index 0000000..6fafd4f
--- /dev/null
+++ b/app/modbus-data-viewer/src/service-web/templates/main.tmpl
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+ Address |
+ Address |
+ Value |
+ Value |
+
+
+ (Dec) |
+ (Hex) |
+ (Hex) |
+ (Dec) |
+
+{{.Table_Control}}
+
+
+
+ Address |
+ Address |
+ Value |
+ Value |
+
+
+ (Dec) |
+ (Hex) |
+ (Hex) |
+ (Dec) |
+
+{{.Table_State}}
+
+
+