Skip to content

Commit

Permalink
New loglib (#55)
Browse files Browse the repository at this point in the history
* Some typofixing and doc improvements

Signed-off-by: Malte Muench <[email protected]>

* Write help to stderr

Signed-off-by: Malte Muench <[email protected]>

* Improve logging, and improve error handling in reading the csv

Signed-off-by: Malte Muench <[email protected]>

* Remove unused methods

Signed-off-by: Malte Muench <[email protected]>

* Adds logging for receivehandling.go

Signed-off-by: Malte Muench <[email protected]>

* Various smaller IDE proposed improvements

Signed-off-by: Malte Muench <[email protected]>

* renamings, prefer short names

Signed-off-by: Malte Muench <[email protected]>

---------

Signed-off-by: Malte Muench <[email protected]>
Co-authored-by: Malte Muench <[email protected]>
  • Loading branch information
mxmxchere and Malte Muench authored May 10, 2024
1 parent b963565 commit 3c920dd
Show file tree
Hide file tree
Showing 11 changed files with 118 additions and 191 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ Example:
123,uint322ascii,huette/all/000/airmonitor/sensors/pm10
```

Explanation for the 1st Line: For example our Doorstatus is published on the CAN-Bus every second with the CAN-ID 112 (decimal). can2mqtt will take everything thats published there and will push it through to mqtt-topic huette/all/a03/door/sensors/opened.
Explanation for the 1st Line: For example our Doorstatus is published on the CAN-Bus every second with the CAN-ID 112 (decimal). can2mqtt will take everything that is published there and will push it through to mqtt-topic huette/all/a03/door/sensors/opened.

## convert-modes
Here they are:
Expand Down
12 changes: 6 additions & 6 deletions src/can2mqtt.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ func main() {

// help function (obvious...)
func printHelp() {
fmt.Printf("welcome to the CAN2MQTT bridge!\n\n")
fmt.Printf("Usage: can2mqtt [-f <file>] [-c <CAN-Interface>] [-m <MQTT-Connect>] [-v] [-h] [-d <dirMode>]\n")
fmt.Printf("<file>: a can2mqtt.csv file\n")
fmt.Printf("<CAN-Interface>: a CAN-Interface e.g. can0\n")
fmt.Printf("<MQTT-Connect>: connectstring for MQTT. e.g.: tcp://[user:pass@]localhost:1883\n")
fmt.Printf("<dirMode>: directional Mode 0 = bidirectional, 1 = can2mqtt only, 2 = mqtt2can only\n")
_, _ = fmt.Fprintf(os.Stderr, "welcome to the CAN2MQTT bridge!\n\n")
_, _ = fmt.Fprintf(os.Stderr, "Usage: can2mqtt [-f <file>] [-c <CAN-Interface>] [-m <MQTT-Connect>] [-v] [-h] [-d <dirMode>]\n")
_, _ = fmt.Fprintf(os.Stderr, "<file>: a can2mqtt.csv file\n")
_, _ = fmt.Fprintf(os.Stderr, "<CAN-Interface>: a CAN-Interface e.g. can0\n")
_, _ = fmt.Fprintf(os.Stderr, "<MQTT-Connect>: connectstring for MQTT. e.g.: tcp://[user:pass@]localhost:1883\n")
_, _ = fmt.Fprintf(os.Stderr, "<dirMode>: directional Mode 0 = bidirectional, 1 = can2mqtt only, 2 = mqtt2can only\n")
}
47 changes: 17 additions & 30 deletions src/internal/canbushandling.go → src/internal/canbus.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
// Package can2mqtt contains some tools for bridging a CAN-Interface
// Package internal of c3re/can2mqtt contains some tools for bridging a CAN-Interface
// and a mqtt-network
package internal

import (
"fmt"
"github.com/brutella/can"
"log"
"log/slog"
"os"
"sync"
)

Expand All @@ -18,23 +18,21 @@ var bus *can.Bus // CAN-Bus pointer
func canStart(canInterface string) {

var err error
if dbg {
fmt.Printf("canbushandler: initializing CAN-Bus interface %s\n", canInterface)
}
slog.Debug("canbus: initializing CAN-Bus", "interface", canInterface)
bus, err = can.NewBusForInterfaceWithName(canInterface)
if err != nil {
if dbg {
fmt.Printf("canbushandler: error while activating CAN-Bus interface: %s\n", canInterface)
}
log.Fatal(err)
slog.Error("canbus: error while initializing CAN-Bus", "error", err)
os.Exit(1)
}
slog.Info("canbus: connected to CAN")
slog.Debug("canbus: registering handler")
bus.SubscribeFunc(handleCANFrame)
slog.Debug("canbus: starting receive loop")
// will not return if everything is fine
err = bus.ConnectAndPublish()
if err != nil {
if dbg {
fmt.Printf("canbushandler: error while activating CAN-Bus interface: %s\n", canInterface)
}
log.Fatal(err)
slog.Error("canbus: error while processing CAN-Bus", "error", err)
os.Exit(1)
}
}

Expand All @@ -43,18 +41,14 @@ func handleCANFrame(frame can.Frame) {
var idSub = false // indicates, whether the id was subscribed or not
for _, i := range csi {
if i == frame.ID {
if dbg {
fmt.Printf("canbushandler: ID %d is in subscribed list, calling receivehadler.\n", frame.ID)
}
slog.Debug("canbus: received subscribed frame", "id", frame.ID)
go handleCAN(frame)
idSub = true
break
}
}
if !idSub {
if dbg {
fmt.Printf("canbushandler: ID:%d was not subscribed. /dev/nulled that frame...\n", frame.ID)
}
slog.Debug("canbus: ignored unsubscribed frame", "id", frame.ID)
}
}

Expand All @@ -63,26 +57,19 @@ func canSubscribe(id uint32) {
csiLock.Lock()
csi = append(csi, id)
csiLock.Unlock()
if dbg {
fmt.Printf("canbushandler: mutex lock+unlock successful. subscribed to ID:%d\n", id)
}
slog.Debug("canbus: successfully subscribed CAN-ID", "id", id)
}

// expects a CANFrame and sends it
func canPublish(frame can.Frame) {
if dbg {
fmt.Println("canbushandler: sending CAN-Frame: ", frame)
}
slog.Debug("canbus: sending CAN-Frame", "frame", frame)
// Check if ID is using more than 11-Bits:
if frame.ID >= 0x800 {
// if so, enable extended frame format
frame.ID |= 0x80000000
}
err := bus.Publish(frame)
if err != nil {
if dbg {
fmt.Printf("canbushandler: error while transmitting the CAN-Frame.\n")
}
log.Fatal(err)
slog.Error("canbus: error while publishing CAN-Frame", "error", err)
}
}
2 changes: 1 addition & 1 deletion src/internal/convertfunctions/bytecolor2colorcode.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func ByteColor2ColorCodeToCan(input []byte) (can.Frame, error) {
if err != nil {
return can.Frame{}, errors.New(fmt.Sprintf("Error while converting: %s", err.Error()))
}
var returner can.Frame = can.Frame{Length: 3}
var returner = can.Frame{Length: 3}
copy(res, returner.Data[0:3])
return returner, nil
}
Expand Down
2 changes: 1 addition & 1 deletion src/internal/convertfunctions/int2ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func FourInt162AsciiToMqtt(input can.Frame) ([]byte, error) {
// numberAmount*numberWidth shall not be larger than 64
// input has to contain the data that shall be converted. The input is split at whitespaces, the amount of fields has
// to match numberAmount.
// If the amount of fields matches, each field is converted to a uint of size numberWidth. The results are then added to the CAN-frame.
// If the amount of fields matches, each field is converted to an uint of size numberWidth. The results are then added to the CAN-frame.
func NIntM2AsciiToCan(numberAmount, numberWidth uint, input []byte) (can.Frame, error) {
if !(numberWidth == 8 || numberWidth == 16 || numberWidth == 32 || numberWidth == 64) {

Expand Down
2 changes: 1 addition & 1 deletion src/internal/convertfunctions/pixelbin2ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ func PixelBin2AsciiToCan(input []byte) (can.Frame, error) {
if err != nil {
return can.Frame{}, errors.New(fmt.Sprintf("Error while converting: %s", err.Error()))
}
var returner can.Frame = can.Frame{Length: 4}
var returner = can.Frame{Length: 4}
returner.Data[0] = uint8(number)
copy(res, returner.Data[1:4])
return returner, nil
Expand Down
4 changes: 2 additions & 2 deletions src/internal/convertfunctions/uint2ascii.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ func FourUint162AsciiToMqtt(input can.Frame) ([]byte, error) {
// numberAmount*numberWidth shall not be larger than 64
// input has to contain the data that shall be converted. The input is split at whitespaces, the amount of fields has
// to match numberAmount.
// If the amount of fields matches, each field is converted to a uint of size numberWidth. The results are then added to the CAN-frame.
// If the amount of fields matches, each field is converted to an uint of size numberWidth. The results are then added to the CAN-frame.
func NUintM2AsciiToCan(numberAmount, numberWidth uint, input []byte) (can.Frame, error) {
if !(numberWidth == 8 || numberWidth == 16 || numberWidth == 32 || numberWidth == 64) {

Expand Down Expand Up @@ -139,7 +139,7 @@ func NUintM2AsciiToMqtt(numberAmount, numberWidth uint, input can.Frame) ([]byte
for i := uint(0); i < numberAmount; i++ {
switch numberWidth {
case 64:
returnStrings = append(returnStrings, strconv.FormatUint(uint64(binary.LittleEndian.Uint64(input.Data[i*bytePerNumber:(i+1)*bytePerNumber])), 10))
returnStrings = append(returnStrings, strconv.FormatUint(binary.LittleEndian.Uint64(input.Data[i*bytePerNumber:(i+1)*bytePerNumber]), 10))
case 32:
returnStrings = append(returnStrings, strconv.FormatUint(uint64(binary.LittleEndian.Uint32(input.Data[i*bytePerNumber:(i+1)*bytePerNumber])), 10))
case 16:
Expand Down
91 changes: 29 additions & 62 deletions src/internal/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import (
"fmt" // print :)
"github.com/brutella/can"
"github.com/c3re/can2mqtt/internal/convertfunctions"
"io" // EOF const
"log" // error management
"io" // EOF const
"log" // error management
"log/slog"
"os" // open files
"strconv" // parse strings
"sync"
Expand Down Expand Up @@ -46,6 +47,7 @@ var wg sync.WaitGroup
// just standard information output. Default is false.
func SetDbg(v bool) {
dbg = v
slog.SetLogLoggerLevel(slog.LevelDebug)
}

// SetCi sets the CAN-Interface to use for the CAN side
Expand Down Expand Up @@ -86,28 +88,8 @@ func SetConfDirMode(s string) {
// parses the can2mqtt.csv file and from there everything takes
// its course...
func Start() {
fmt.Println("Starting can2mqtt")
fmt.Println()
fmt.Println("MQTT-Config: ", cs)
fmt.Println("CAN-Config: ", ci)
fmt.Println("can2mqtt.csv: ", c2mf)
fmt.Print("dirMode: ", dirMode, " (")
if dirMode == 0 {
fmt.Println("bidirectional)")
}
if dirMode == 1 {
fmt.Println("can2mqtt only)")
}
if dirMode == 2 {
fmt.Println("mqtt2can only)")
}
fmt.Print("Debug-Mode: ")
if dbg {
fmt.Println("yes")
} else {
fmt.Println("no")
}
fmt.Println()
log.SetFlags(0)
slog.Info("Starting can2mqtt", "mqtt-config", cs, "can-interface", ci, "can2mqtt.csv", c2mf, "dir-mode", dirMode, "debug", dbg)
wg.Add(1)
go canStart(ci) // epic parallel shit ;-)
mqttStart(cs)
Expand All @@ -121,10 +103,12 @@ func readC2MPFromFile(filename string) {

file, err := os.Open(filename)
if err != nil {
log.Fatal(err)
slog.Error("can2mqtt.csv could not be opened", "filename", filename, "error", err)
os.Exit(1)
}

r := csv.NewReader(bufio.NewReader(file))
r.FieldsPerRecord = 3
pairFromID = make(map[uint32]*can2mqtt)
pairFromTopic = make(map[string]*can2mqtt)
for {
Expand All @@ -133,16 +117,26 @@ func readC2MPFromFile(filename string) {
if err == io.EOF {
break
}
if err != nil {
slog.Warn("skipping line", "filename", filename, "error", err)
continue
}
line, _ := r.FieldPos(0)
tmp, err := strconv.ParseUint(record[0], 10, 32)
if err != nil {
fmt.Printf("Error while converting can-ID: %s :%s\n", record[0], err.Error())
slog.Warn("skipping line, malformed can-ID", "error", err, "line", line)
continue
}
canID := uint32(tmp)
convMode := record[1]
topic := record[2]
if isInSlice(canID, topic) {
panic("main: each ID and each topic is only allowed once!")
if isIDInSlice(canID) {
slog.Warn("skipping line, duplicate ID", "id", canID, "line", line)
continue
}
if isTopicInSlice(topic) {
slog.Warn("skipping line duplicate topic", "topic", topic, "line", line)
continue
}
switch convMode {
case "16bool2ascii":
Expand Down Expand Up @@ -217,7 +211,7 @@ func readC2MPFromFile(filename string) {
toCan: convertfunctions.EightUint82AsciiToCan,
toMqtt: convertfunctions.EightUint82AsciiToMqtt,
}
// Int methodes come here now
// Int methods come here now
case "int82ascii":
pairFromID[canID] = &can2mqtt{
canId: canID,
Expand Down Expand Up @@ -311,45 +305,18 @@ func readC2MPFromFile(filename string) {
mqttSubscribe(topic) // TODO move to append function
canSubscribe(canID) // TODO move to append function
}
if dbg {
fmt.Printf("main: the following CAN-MQTT pairs have been extracted:\n")
fmt.Printf("main: CAN-ID\t\t conversion mode\t\tMQTT-topic\n")
for _, c2mp := range pairFromID {
fmt.Printf("main: %d\t\t%s\t\t%s\n", c2mp.canId, c2mp.convMethod, c2mp.mqttTopic)
}
}
}

// check function to check if a topic or an ID is in the slice
func isInSlice(canId uint32, mqttTopic string) bool {
if pairFromID[canId] != nil {
if dbg {
fmt.Printf("main: The ID %d or the Topic %s is already in the list!\n", canId, mqttTopic)
}
return true
for _, c2mp := range pairFromID {
slog.Debug("extracted pair", "id", c2mp.canId, "convertmode", c2mp.convMethod, "topic", c2mp.mqttTopic)
}
if pairFromTopic[mqttTopic] != nil {
if dbg {
fmt.Printf("main: The ID %d or the Topic %s is already in the list!\n", canId, mqttTopic)
}
return true
}
return false
}

// get the corresponding ID for a given topic
func getIdFromTopic(topic string) uint32 {
return pairFromTopic[topic].canId
}

// get the conversion mode for a given topic
func getConvModeFromTopic(topic string) string {
return pairFromTopic[topic].convMethod
func isIDInSlice(canId uint32) bool {
return pairFromID[canId] != nil
}

// get the convertMode for a given ID
func getConvModeFromId(canId uint32) string {
return pairFromID[canId].convMethod
func isTopicInSlice(mqttTopic string) bool {
return pairFromTopic[mqttTopic] != nil
}

// get the corresponding topic for an ID
Expand Down
Loading

0 comments on commit 3c920dd

Please sign in to comment.