Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New loglib #55

Merged
merged 7 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading