Skip to content

Commit

Permalink
add simple serial driver (#78)
Browse files Browse the repository at this point in the history
  • Loading branch information
wizzomafizzo authored Jul 6, 2024
1 parent 7dfe090 commit a8de32f
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 0 deletions.
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ require (

require (
github.com/ajg/form v1.5.1 // indirect
github.com/creack/goselect v0.1.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/stretchr/testify v1.9.0 // indirect
go.bug.st/serial v1.6.2 // indirect
golang.org/x/term v0.22.0 // indirect
)

Expand Down
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ github.com/bendahl/uinput v1.6.0/go.mod h1:Np7w3DINc9wB83p12fTAM3DPPhFnAKP0WTXRq
github.com/clausecker/nfc/v2 v2.1.4 h1:zw2Cnny7pxPnuxVMBo+DXqXYETzUN7pMhNEA61yT5gY=
github.com/clausecker/nfc/v2 v2.1.4/go.mod h1:BjRBQUQTQmiwh2tEfQ+xBM5xY05sV2gnZ0JRYEHog/o=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/goselect v0.1.2 h1:2DNy14+JPjRBgPzAd1thbQp4BSIihxcBf0IXhQXDRa0=
github.com/creack/goselect v0.1.2/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
Expand Down Expand Up @@ -46,6 +48,8 @@ github.com/txn2/txeh v1.4.0 h1:0tdvpA4HGJrj8X3kmrU6o/JFStI009nKxwDpMK5CnRU=
github.com/txn2/txeh v1.4.0/go.mod h1:Mgq0hY184zCrDBLgvkIp+9NYGHoYbJcu4xKqUcx1shc=
github.com/wizzomafizzo/mrext v0.0.0-20240705120538-5efdc40f9c08 h1:IfCVEDGCzNY4Lx+1tUUkTOLEv4yxXh9Jpsj6T+8YWr4=
github.com/wizzomafizzo/mrext v0.0.0-20240705120538-5efdc40f9c08/go.mod h1:pWjoPIzJIXlDfEmdf++eUqsZKrEsYVkOHy39s/H7WLA=
go.bug.st/serial v1.6.2 h1:kn9LRX3sdm+WxWKufMlIRndwGfPWsH1/9lCWXQCasq8=
go.bug.st/serial v1.6.2/go.mod h1:UABfsluHAiaNI+La2iESysd9Vetq7VRdpxvjx7CmmOE=
go.etcd.io/bbolt v1.3.9 h1:8x7aARPEXiXbHmtUwAIv7eV2fQFHrLLavdiJ3uzJXoI=
go.etcd.io/bbolt v1.3.9/go.mod h1:zaO32+Ti0PK1ivdPtgMESzuzL2VPoIG1PCQNvOdo/dE=
golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 h1:yixxcjnhBmY0nkL253HFVIm0JsFHwrHdT3Yh6szTnfY=
Expand Down
11 changes: 11 additions & 0 deletions pkg/daemon/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (

"github.com/wizzomafizzo/tapto/pkg/readers/file"
"github.com/wizzomafizzo/tapto/pkg/readers/libnfc"
"github.com/wizzomafizzo/tapto/pkg/readers/simple_serial"
"github.com/wizzomafizzo/tapto/pkg/tokens"
)

Expand Down Expand Up @@ -85,6 +86,16 @@ func connectReaders(
st.SetReader(device, r)
log.Info().Msgf("opened file reader: %s", device)
}
} else if rt == "simple_serial" {
r := simple_serial.NewReader(cfg)
err := r.Open(device, iq)
if err != nil {
log.Error().Msgf("error opening simple serial reader: %s", err)
continue
} else {
st.SetReader(device, r)
log.Info().Msgf("opened simple serial reader: %s", device)
}
} else {
r := libnfc.NewReader(cfg)
err := r.Open(device, iq)
Expand Down
2 changes: 2 additions & 0 deletions pkg/readers/libnfc/libnfc.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,9 @@ func (r *Reader) Close() error {
func (r *Reader) Ids() []string {
return []string{
"pn532_uart",
"pn532_i2c",
"acr122_usb",
"pcsc",
}
}

Expand Down
196 changes: 196 additions & 0 deletions pkg/readers/simple_serial/simple_serial.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package simple_serial

import (
"errors"
"os"
"path/filepath"
"strings"
"time"

"github.com/rs/zerolog/log"
"github.com/wizzomafizzo/tapto/pkg/config"
"github.com/wizzomafizzo/tapto/pkg/readers"
"github.com/wizzomafizzo/tapto/pkg/tokens"
"github.com/wizzomafizzo/tapto/pkg/utils"

"go.bug.st/serial"
)

type SimpleSerialReader struct {
cfg *config.UserConfig
device string
path string
polling bool
port serial.Port
lastToken *tokens.Token
}

func NewReader(cfg *config.UserConfig) *SimpleSerialReader {
return &SimpleSerialReader{
cfg: cfg,
}
}

func (r *SimpleSerialReader) Ids() []string {
return []string{"simple_serial"}
}

func (r *SimpleSerialReader) parseLine(line string) (*tokens.Token, error) {
line = strings.TrimSpace(line)
line = strings.Trim(line, "\r")

if len(line) == 0 {
return nil, nil
}

if !strings.HasPrefix(line, "SCAN\t") {
return nil, nil
}

args := line[5:]
if len(args) == 0 {
return nil, nil
}

t := tokens.Token{
Data: line,
ScanTime: time.Now(),
Source: r.device,
}

ps := strings.Split(args, "\t")
for i := 0; i < len(ps); i++ {
ps[i] = strings.TrimSpace(ps[i])
if strings.HasPrefix(ps[i], "uid=") {
t.UID = ps[i][4:]
} else if strings.HasPrefix(ps[i], "text=") {
t.Text = ps[i][5:]
}
}

return &t, nil
}

func (r *SimpleSerialReader) Open(device string, iq chan<- readers.Scan) error {
ps := strings.SplitN(device, ":", 2)
if len(ps) != 2 {
return errors.New("invalid device string: " + device)
}

if !utils.Contains(r.Ids(), ps[0]) {
return errors.New("invalid reader id: " + ps[0])
}

path := ps[1]

if !filepath.IsAbs(path) {
return errors.New("invalid device path, must be absolute")
}

if _, err := os.Stat(path); err != nil {
return err
}

port, err := serial.Open(path, &serial.Mode{
BaudRate: 115200,
})
if err != nil {
return err
}

err = port.SetReadTimeout(100 * time.Millisecond)
if err != nil {
return err
}

r.port = port
r.device = device
r.path = path
r.polling = true

go func() {
var lineBuf []byte

for r.polling {
time.Sleep(100 * time.Millisecond)

buf := make([]byte, 4096)
n, err := r.port.Read(buf)
if err != nil {
log.Error().Err(err).Msg("failed to read from serial port")
err = r.Close()
if err != nil {
log.Error().Err(err).Msg("failed to close serial port")
}
break
}

for i := 0; i < n; i++ {
if buf[i] == '\n' {
line := string(lineBuf)
lineBuf = nil

t, err := r.parseLine(line)
if err != nil {
log.Error().Err(err).Msg("failed to parse line")
continue
}

if t != nil && !utils.TokensEqual(t, r.lastToken) {
iq <- readers.Scan{
Source: r.device,
Token: t,
}
}

if t != nil {
r.lastToken = t
}
} else {
lineBuf = append(lineBuf, buf[i])
}
}

if r.lastToken != nil && time.Since(r.lastToken.ScanTime) > 1*time.Second {
iq <- readers.Scan{
Source: r.device,
Token: nil,
}
r.lastToken = nil
}
}
}()

return nil
}

func (r *SimpleSerialReader) Close() error {
r.polling = false
if r.port != nil {
err := r.port.Close()
if err != nil {
return err
}
}
return nil
}

func (r *SimpleSerialReader) Detect(connected []string) string {
return ""
}

func (r *SimpleSerialReader) Device() string {
return r.device
}

func (r *SimpleSerialReader) Connected() bool {
return r.polling && r.port != nil
}

func (r *SimpleSerialReader) Info() string {
return r.path
}

func (r *SimpleSerialReader) Write(text string) (*tokens.Token, error) {
return nil, errors.New("writing not supported on this reader")
}

0 comments on commit a8de32f

Please sign in to comment.