Skip to content

Commit

Permalink
Merge pull request #1 from Crow314/develop
Browse files Browse the repository at this point in the history
v0.1.0
  • Loading branch information
Crow314 authored Dec 21, 2021
2 parents ecd911d + 9316286 commit f62eb94
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 0 deletions.
49 changes: 49 additions & 0 deletions cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package main

import (
"bufio"
"fmt"
"github.com/Crow314/im920s-controller/pkg/connector"
"github.com/Crow314/im920s-controller/pkg/module"
"os"
)

func main() {
scanner := bufio.NewScanner(os.Stdin)

fmt.Print("Please input COM port path/name: ")
var portName string
if scanner.Scan() {
portName = scanner.Text()
}

conn := connector.NewConnector(portName)
im920s := module.NewIm920s(conn.TransmitChannel(), conn.ReceiveChannel())

go func() {
for {
data := <-im920s.DataReceiver()
fmt.Printf("node: %d\n", data.Node())
fmt.Printf("RSSI: %ddb\n", data.Rssi())

for _, v := range data.Data() {
fmt.Printf("%X, ", v)
}
fmt.Println()
}
}()

for {
var msg string
if scanner.Scan() {
msg = scanner.Text()
}

res, err := im920s.SendCommand(msg)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "%v\n", err)
} else {
fmt.Println(res)
}
}
}
7 changes: 7 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
module github.com/Crow314/im920s-controller

go 1.17

require github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07

require golang.org/x/sys v0.0.0-20210903071746-97244b99971b // indirect
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
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-20210903071746-97244b99971b h1:3Dq0eVHn0uaQJmPO+/aYPI/fRMqdrVDbu7MQcku54gg=
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
79 changes: 79 additions & 0 deletions pkg/connector/uart.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package connector

import (
"github.com/tarm/serial"
"log"
)

type Connector struct {
portName string
port *serial.Port
txChan chan string
rxChan chan string
}

func NewConnector(portName string) *Connector {
conn := new(Connector)
conn.portName = portName

conf := &serial.Config{Name: portName, Baud: 19200}

p, err := serial.OpenPort(conf)
if err != nil {
log.Fatalf("Failed to open COM port\n%v", err)
}
conn.port = p

conn.txChan = make(chan string)
conn.rxChan = make(chan string, 5) // 損失対策 / RTSを受け取ってくれないので

go conn.transmit()
go conn.receive()

return conn
}

func (conn *Connector) transmit() {
for {
msg := <-conn.txChan

_, err := conn.port.Write([]byte(msg))
if err != nil {
log.Fatal(err)
}
}
}

func (conn *Connector) receive() {
dataBuf := make([]byte, 128)
msgBuf := make([]byte, 0, 128)

for {
n, err := conn.port.Read(dataBuf)
if err != nil {
log.Fatal(err)
}

// 1回での受信データ (!= 1行)
for _, v := range dataBuf[:n] {
msgBuf = append(msgBuf, v)

if v == '\n' { // LFで一区切り
msg := string(msgBuf)
msgBuf = msgBuf[:0] // 要素を全て削除

conn.rxChan <- msg
}
}
}
}

// Getter

func (conn Connector) TransmitChannel() chan<- string {
return conn.txChan
}

func (conn Connector) ReceiveChannel() <-chan string {
return conn.rxChan
}
74 changes: 74 additions & 0 deletions pkg/module/im920.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package module

import (
"errors"
"strings"
"time"
)

type Im920s struct {
uartChannel uartChannel
dataReceiver chan ReceivedData
responseReceiver chan string
}

type uartChannel struct {
transmitter chan<- string
receiver <-chan string
}

func NewIm920s(transmitter chan<- string, receiver <-chan string) *Im920s {
im920s := new(Im920s)

im920s.uartChannel.transmitter = transmitter
im920s.uartChannel.receiver = receiver

im920s.dataReceiver = make(chan ReceivedData)

go im920s.receiver()

return im920s
}

func (im920s *Im920s) SendCommand(msg string) (string, error) {
if !strings.HasSuffix(msg, "\r\n") { // 末尾がCRLFでない場合
msg += "\r\n"
}

im920s.responseReceiver = make(chan string)
im920s.uartChannel.transmitter <- msg

res := ""
var err error

select {
case res = <-im920s.responseReceiver:
if res == "NG\r\n" {
err = errors.New("returned \"NG\" response")
}

if msg == "RPRM\r\n" || msg == "rprm\r\n" {
loop:
for { // 2行目以降に対応
select {
case res2 := <-im920s.responseReceiver:
res += res2
case <-time.After(1 * time.Second):
break loop
}
}
}
case <-time.After(10 * time.Second):
err = errors.New("returned no response")
}

close(im920s.responseReceiver)

return res, err
}

// Getter

func (im920s Im920s) DataReceiver() <-chan ReceivedData {
return im920s.dataReceiver
}
115 changes: 115 additions & 0 deletions pkg/module/receive.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package module

import (
"errors"
"fmt"
"os"
"regexp"
"strconv"
"strings"
)

type ReceivedData struct {
node uint16
rssi int8
data []byte
}

var receiveDataFormat *regexp.Regexp

func (im920s *Im920s) receiver() {
for {
str := <-im920s.uartChannel.receiver

// onReceived的なsomething

if isReceivedData(str) { // データ受信
data, err := parseData(str)
if err != nil {
_, _ = fmt.Fprintf(os.Stderr, "Error: Failed to parse data\n%v\n", err)
continue
}

im920s.dataReceiver <- *data
} else {
if str == "GRNOREGD\r\n" { // STGNコマンド実行後 グループ番号設定パケット受信時
// TODO config struct
println("Info: Group number has been registered")
} else { // コマンドに対するレスポンス
im920s.responseReceiver <- str
}
}
}
}

func isReceivedData(receivedStr string) bool {
// 正規表現定義
if receiveDataFormat == nil {
receiveDataFormat = regexp.MustCompile("^00,[0-9A-F]{4},[0-9A-F]{2}:.+\r\n$")
}

return receiveDataFormat.MatchString(receivedStr)
}

func parseData(dataStr string) (*ReceivedData, error) {
// 末尾CRLF除去
if strings.HasSuffix(dataStr, "\r\n") {
dataStr = dataStr[:len(dataStr)-2]
}

data := new(ReceivedData)

tmpStrs := strings.Split(dataStr, ":")

if len(tmpStrs) != 2 {
return nil, errors.New("invalid format\nCan't separate header and body.")
}

header := strings.Split(tmpStrs[0], ",")
// TODO ECIO
body := strings.Split(tmpStrs[1], ",") // Only DCIO mode

if header[0] != "00" {
return nil, errors.New("invalid format\nDummy is not 0x00.")
}

// Node
hex, err := strconv.ParseInt(header[1], 16, 16)
if err != nil {
return nil, err
}
data.node = uint16(hex)

// RSSI
tmpByte, err := parseByteHex(header[2])
if err != nil {
return nil, err
}
data.rssi = int8(tmpByte)

// Data
data.data = make([]byte, len(body))
for i, v := range body {
res, err := parseByteHex(v)
if err != nil {
return nil, err
}
data.data[i] = res
}

return data, nil
}

// Getter

func (data *ReceivedData) Node() uint16 {
return data.node
}

func (data *ReceivedData) Rssi() int8 {
return data.rssi
}

func (data *ReceivedData) Data() []byte {
return data.data
}
20 changes: 20 additions & 0 deletions pkg/module/transmit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package module

import (
"encoding/hex"
"errors"
)

func (im920s *Im920s) Broadcast(data []byte) error {
size := len(data)
if size < 1 || size > 32 {
return errors.New("invalid data size")
}

_, err := im920s.SendCommand("TXDA " + hex.EncodeToString(data))
if err != nil {
return err
}

return nil
}
11 changes: 11 additions & 0 deletions pkg/module/util.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package module

import "strconv"

func parseByteHex(rssi string) (byte, error) {
hex, err := strconv.ParseUint(rssi, 16, 8)
if err != nil {
return 0, err
}
return byte(hex), nil
}

0 comments on commit f62eb94

Please sign in to comment.