blitzer-v2/radar_lib/main.go
2025-08-10 16:06:44 +01:00

188 lines
5.2 KiB
Go

package radar_lib
import (
"errors"
"log"
"sync"
"go.bug.st/serial"
)
type configResponse struct {
CommandCode int
Success bool
}
type Direction int
type OutputLogic int
type Port int
type Baud int
type OutputType int
type TriggerMethod int
type OperatingMode int
const (
ControlPinRelay = iota
ControlPinCtrl1
ControlPinCtrl2
)
const (
DirectionBidirectional Direction = iota
DirectionIncoming
DirectionOutgoing
)
const (
TargetStateInvalid = iota
TargetStateMovingInside
TargetStateExit
TargetStateWithin
)
const (
OutputLogicLargestSpeed = iota
OutputLogicStrongestEngergy
OutputLogicMostPlausible
)
const (
PortTTL Port = iota
PortRS485
)
const (
Baud9600 Baud = iota
Baud19200
Baud57600
Baud115200
)
const (
OutputTypeNoOutput OutputType = iota
OutputTypePeriodicOutput
OutputTypeValidOutput
)
const (
TriggerMethodHigh TriggerMethod = iota
TriggerMethodLow
TriggerMethodPositivePulse
TriggerMethodNegativePulse
)
const (
OperatingModeNoOutput OperatingMode = iota
OperatingModeFirstProtocol
OperatingModeSecondProtocol
)
var (
startSequence = []byte{0x43, 0x46}
endSequence = []byte{0x0D, 0x0A}
)
func New(port string, baudrate int) *Radar {
s, err := serial.Open(port, &serial.Mode{
BaudRate: baudrate,
DataBits: 8,
Parity: serial.NoParity,
})
if err != nil {
log.Fatal(err)
}
//s.SetReadTimeout(1000 * time.Millisecond)
r := &Radar{
port: s,
baudrate: baudrate,
configResponseChannel: make(chan configResponse),
}
go r.listenSerial()
return r
}
type Radar struct {
port serial.Port
lock sync.RWMutex
configResponseChannel chan (configResponse)
baudrate int
handler func(int)
speedHandler func(int)
configLock sync.RWMutex
}
func (r *Radar) write(data []byte) error {
r.lock.Lock()
defer r.lock.Unlock()
log.Printf("writing %#x", data)
_, err := r.port.Write(data)
if err != nil {
return err
}
return r.port.Drain()
}
// SetPinTrigger configures a pin to trigger on the radar when an object is detected in a specific range.
// controlPin defines the Pin to trigger, distance is the target distance in 0.5 meters, outputLevel is the voltage in 0.1V steps, direction defines weather to trigger on incoming / outgoing or both
func (r *Radar) SetPinTrigger(controlPin int, distance int, outputLevel int, direction Direction) error {
data := startSequence
data = append(data, 0x00, byte(controlPin), byte(distance), byte(outputLevel), byte(direction))
data = append(data, endSequence...)
return r.write(data)
}
// SetBaseConfig configures the base configuration. height defines the mounted height in 1cm steps, angle defines the vertical angle in degrees, waveformConfig is used to differentiate 2 different radars
func (r *Radar) SetBaseConfig(height int, angle int, waveformConfig int) error {
data := startSequence
data = append(data, 0x01, byte(height), byte(angle), byte(waveformConfig), 0x00)
data = append(data, endSequence...)
return r.write(data)
}
// SetEventConfig can configure up to 8 events that will trigger a response from the radar. distances are in 0.5m, speeds are in km/h.
func (r *Radar) SetEventConfig(eventNumber, minDistance, maxDistance, minSpeed, maxSpeed, direction, state int) error {
if eventNumber < 1 || eventNumber > 1 {
return errors.New("eventNumber needs to be between 1 and 8")
}
data := startSequence
data = append(data, 0x02, byte(eventNumber), byte(minDistance), byte(maxDistance), byte(minSpeed), byte(maxSpeed), byte(direction), byte(state))
data = append(data, endSequence...)
return r.write(data)
}
func (r *Radar) SetTargetSpeedConfig(direction Direction, minDistance, maxDistance, minSpeed, maxSpeed, speeding int, outputLogic OutputLogic) error {
data := startSequence
data = append(data, 0x03, byte(direction), byte(minDistance), byte(maxDistance), byte(minSpeed), byte(maxSpeed), byte(speeding), byte(outputLogic))
data = append(data, endSequence...)
return r.write(data)
}
func (r *Radar) SetCommunicationConfig(port Port, baud Baud, speedOutput, targetOutput, triggerOutput OutputType, communicationPeriod int) error {
data := startSequence
speed := byte(speedOutput)
target := byte(targetOutput)
trigger := byte(triggerOutput)
var outputProtocol byte = (speed << 4) | (target << 2) | trigger
data = append(data, 0x04, byte(port), byte(baud), outputProtocol, byte(int(communicationPeriod/50)))
data = append(data, endSequence...)
return r.write(data)
}
func (r *Radar) SetControlPinConfig(controlPin int, triggerMethod TriggerMethod, outputLevel int, triggerEvent int, span int) error {
data := startSequence
data = append(data, 0x05, byte(controlPin), byte(triggerMethod), byte(outputLevel), byte(triggerEvent), byte(span))
data = append(data, endSequence...)
return r.write(data)
}
func (r *Radar) SetLampBoardOutput(operatingMode OperatingMode, luminance int, span int) error {
data := startSequence
data = append(data, 0x06, byte(operatingMode), byte(luminance), byte(span))
data = append(data, endSequence...)
return r.write(data)
}
func (r *Radar) SetEventHandler(handler func(int)) {
r.handler = handler
}
func (r *Radar) SetSpeedHandler(handler func(int)) {
r.speedHandler = handler
}