From 5b9c3d050d0441e6033dccb36b1f8c61862f2394 Mon Sep 17 00:00:00 2001 From: William Reid Date: Tue, 30 Apr 2019 15:36:31 -0400 Subject: [PATCH] Demo day with digital input readings mapped to displayed statuses --- .gitignore | 2 +- constants.go | 6 ++-- modbusManager.go | 78 ++++++++++++++++++++++++++++++++++++++++++------ server.go | 8 +++-- socketManager.go | 12 ++++---- 5 files changed, 85 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index f394ffe..5683ba1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,3 @@ *.exe .idea/* - +executable/* diff --git a/constants.go b/constants.go index 0058a5d..df6a02d 100644 --- a/constants.go +++ b/constants.go @@ -17,9 +17,9 @@ const ( messageReceived = "received" // Time (in seconds) to wait between performing read/send operations - dataReadPeriod = 300 + dataReadPeriod = 60 dataSendPeriod = 300 - statusReadPeriod = 300 + statusReadPeriod = 1 // Modbus data types WORD = "WORD" @@ -188,7 +188,7 @@ var metrics = [...]Metric{ { "fuel.pressure", 0, - 1000, + 100, }, { "fuel.temp", diff --git a/modbusManager.go b/modbusManager.go index 82b7a72..81b7ef8 100644 --- a/modbusManager.go +++ b/modbusManager.go @@ -70,12 +70,12 @@ func (m *_modbusClient) readAllRegisterData() map[string]StampedReading { intervals := m.readsForAllRegisters() // Modbus reading intervals var data []byte // Data from modbus - m.lock.Lock() // One reader at a time to be safe + m.lock.Lock() // One reader at a time to be safe for _, interval := range intervals { // Do readings for all intervals start := uint16(interval[0]) number := uint16(interval[1]) reading, err := m.conn.ReadHoldingRegisters(start, number) // Read the registers - if err != nil { // Make sure it worked + if err != nil { // Make sure it worked fmt.Printf("Error reading %v registers starting at %v: %v\n", number, start, err) continue } @@ -131,6 +131,48 @@ func reverse(s string) string { return string(runes) } +func (m *_modbusClient) getDigitalInputs() string { + data := m.readHoldingRegisters(uint16(76), uint16(2)) + binstr := make([]string, len(data)) + for i := 0; i < len(data); i += 2 { + binstr[i] = reverse(fmt.Sprintf("%08s", strconv.FormatInt(int64(data[i+1]), 2))) + binstr[i+1] = reverse(fmt.Sprintf("%08s", strconv.FormatInt(int64(data[i]), 2))) + } + return strings.Join(binstr, "") +} + +func (m *_modbusClient) getDigitalUpdates() map[string]int { + inputs := m.getDigitalInputs() + inputMap := make(map[string]int) + for k, v := range _inputs { + input := inputs[k] - 48 + inputMap[v] = int(input) + } + if len(_lastInput) == 0 { + _lastInput = inputMap + return inputMap + } else { + updateMap := inputMap + for k, newv := range inputMap { + oldv, found := _lastInput[k] + if found { + if newv == oldv { + delete(updateMap, k) + } + } + } + for k, v := range updateMap { + _lastInput[k] = v + } + + if len(updateMap) > 0 { + fmt.Printf("Digital Input Updates: %v\n", updateMap) + } + + return updateMap + } +} + func (m *_modbusClient) getStatusCodes() string { data := m.readHoldingRegisters(uint16(1499), uint16(16)) binstr := make([]string, len(data)) @@ -143,7 +185,6 @@ func (m *_modbusClient) getStatusCodes() string { func (m *_modbusClient) getStatusUpdates() map[string]int { statuses := m.getStatusCodes() - fmt.Printf("Statuses: %v\n", statuses) statusMap := make(map[string]int) for k, v := range _statuses { status := statuses[k] - 48 @@ -153,14 +194,23 @@ func (m *_modbusClient) getStatusUpdates() map[string]int { _lastStatus = statusMap return statusMap } else { - updateMap := make(map[string]int) - for k, v := range _lastStatus { - newv := statusMap[k] - if newv != v { - updateMap[k] = newv + updateMap := statusMap + for k, newv := range statusMap { + oldv, found := _lastStatus[k] + if found { + if newv == oldv { + delete(updateMap, k) + } } } - _lastStatus = statusMap + for k, v := range updateMap { + _lastStatus[k] = v + } + + if len(updateMap) > 0 { + fmt.Printf("Status updates: %v\n", updateMap) + } + return updateMap } } @@ -230,4 +280,14 @@ var _statuses = map[int]string{ 207: "fault.common", } +var _inputs = map[int]string{ + 3: "fault.overcrank", // digital input 1 + 4: "fault.fuel.low", + 5: "fault.engine.temp.high", + 6: "fault.common", + 7: "status.gen.running", + 8: "fault.overspeed", +} + var _lastStatus = map[string]int{} +var _lastInput = map[string]int{} diff --git a/server.go b/server.go index 91cfc92..2d0fc39 100644 --- a/server.go +++ b/server.go @@ -29,7 +29,7 @@ func dataSendLoop() { func dataReadLoop() { // Read data all day every day for { dataBuffer := make(map[string][]StampedReading) - reading := readDummyData() // TODO: error handling + reading := readDummyData() // TODO: error handling for metric, value := range reading { // Put our data in the buffer if record, found := dataBuffer[metric]; !found { dataBuffer[metric] = []StampedReading{value} @@ -44,7 +44,11 @@ func dataReadLoop() { // Read data all day every day func statusReadLoop() { // for { - updates := readDummyStatuses() + updates := modbusClient.getStatusUpdates() + digitalUpdates := modbusClient.getDigitalUpdates() + for k, v := range digitalUpdates { + updates[k] = v + } if len(updates) > 0 { packetData := StatusUpdates{int(time.Now().Unix()), updates} go socketClient.sendStatusUpdates(packetData) // Sends statuses immediately diff --git a/socketManager.go b/socketManager.go index a11644b..943b979 100644 --- a/socketManager.go +++ b/socketManager.go @@ -47,9 +47,9 @@ func (c *_socketClient) connect() { c.connLock.Lock() // Shouldn't matter because the other processes will be waiting, but I'm gonna do it anyways defer c.connLock.Unlock() - rootCAs := x509.NewCertPool() // Initialize a cert pool - rootCert, _ := ioutil.ReadFile("/opt/emulation-server/rootCA.pem") // Read our root CA cert - rootCAs.AppendCertsFromPEM(rootCert) // Add it to the pool + rootCAs := x509.NewCertPool() // Initialize a cert pool + rootCert, _ := ioutil.ReadFile("rootCA.pem") // Read our root CA cert + rootCAs.AppendCertsFromPEM(rootCert) // Add it to the pool config := &tls.Config{RootCAs: rootCAs} // Trust our root CA @@ -114,7 +114,7 @@ func (c *_socketClient) handlePackets() { func (c *_socketClient) sendPacket(p Packet) { fmt.Printf("Sending %v packet with ID %v\n", p.Kind, p.ID) - c.connLock.Lock() // Lock to send + c.connLock.Lock() // Lock to send if err := c.conn.WriteJSON(p); err != nil { // Try to send fmt.Printf("Error sending %v packet %v: %v\n", p.Kind, p.ID, err) // If we fail, try to reconnect c.wait.Add(1) // Prevent client things from happening @@ -166,7 +166,7 @@ func (c *_socketClient) readIncoming() { // Read messages from gateway go c.connect() // Reconnect } else { switch packet.Kind { - case kindResponse: // Got a response + case kindResponse: // Got a response go responseManager.received(packet) // Tell the response map default: fmt.Printf("Got unknown packet type: %v\n", packet.Kind) @@ -178,7 +178,7 @@ func (c *_socketClient) readIncoming() { // Read messages from gateway func getHeader() http.Header { h := http.Header{} h.Set("Content-Type", "application/json") - h.Set(headerUUID, "0000000000000001") // TODO: get this from somewhere + h.Set(headerUUID, "0000000000000004") // TODO: get this from somewhere h.Set(headerTimestamp, strconv.FormatInt(time.Now().Unix(), 10)) return h }