mirror of
https://github.com/ftl/tetra-pei.git
synced 2025-04-01 19:47:29 +02:00
add functions to read talkgroups
This commit is contained in:
parent
5c7df72d1c
commit
90475db447
2 changed files with 153 additions and 0 deletions
|
@ -54,6 +54,96 @@ func RequestTalkgroup(ctx context.Context, requester tetra.Requester) (string, e
|
|||
return parts[1], nil
|
||||
}
|
||||
|
||||
const (
|
||||
talkgroupRangeRequest = "AT+CNUM%s=?"
|
||||
talkgroupsPrepareRequest = "AT+CNUM%s=0,%d,%d"
|
||||
talkgroupsReadRequest = "AT+CNUM%s?"
|
||||
)
|
||||
|
||||
type TalkgroupKind string
|
||||
|
||||
const (
|
||||
TalkgroupFixed TalkgroupKind = "F"
|
||||
TalkgroupStatic TalkgroupKind = "S"
|
||||
TalkgroupDynamic TalkgroupKind = "D"
|
||||
)
|
||||
|
||||
type TalkgroupRange struct {
|
||||
Min int
|
||||
Max int
|
||||
}
|
||||
|
||||
type TalkgroupInfo struct {
|
||||
GTSI string
|
||||
Name string
|
||||
}
|
||||
|
||||
// RequestTalkgroups reads all available static talkgroups from the device, see [PEI] 6.11.5.2
|
||||
func RequestTalkgroups(ctx context.Context, requester tetra.Requester, kind TalkgroupKind, result []TalkgroupInfo) ([]TalkgroupInfo, error) {
|
||||
rng, err := RequestTalkgroupRange(ctx, requester, kind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
prepareRequest := fmt.Sprintf(talkgroupsPrepareRequest, kind, rng.Min, rng.Max)
|
||||
_, err = requester.Request(ctx, prepareRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
readRequest := fmt.Sprintf(talkgroupsReadRequest, kind)
|
||||
responses, err := requester.Request(ctx, readRequest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if len(responses) < 1 {
|
||||
return nil, fmt.Errorf("no response received")
|
||||
}
|
||||
|
||||
for _, line := range responses {
|
||||
info, err := parseTalkgroupInfo(line)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, info)
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
var talkgroupInfoLine = regexp.MustCompile(`^(\+CNUM(S|D): )?(\d+),(\d+),(.+)`)
|
||||
|
||||
func parseTalkgroupInfo(line string) (TalkgroupInfo, error) {
|
||||
parts := talkgroupInfoLine.FindStringSubmatch(line)
|
||||
if len(parts) != 6 {
|
||||
return TalkgroupInfo{}, fmt.Errorf("invalid talkgroup info: %s", line)
|
||||
}
|
||||
return TalkgroupInfo{
|
||||
GTSI: parts[4],
|
||||
Name: parts[5],
|
||||
}, nil
|
||||
}
|
||||
|
||||
var talkgroupRangeResponse = regexp.MustCompile(`^\+CNUM(S|D): \(.*\),\((\d+)-(\d+)\),\((\d+)-(\d+)\)`)
|
||||
|
||||
func RequestTalkgroupRange(ctx context.Context, requester tetra.Requester, kind TalkgroupKind) (TalkgroupRange, error) {
|
||||
cmd := fmt.Sprintf("AT+CNUM%s=?", kind)
|
||||
parts, err := requestWithSingleLineResponse(ctx, requester, cmd, talkgroupRangeResponse, 6)
|
||||
if err != nil {
|
||||
return TalkgroupRange{}, err
|
||||
}
|
||||
|
||||
min, err := strconv.Atoi(parts[2])
|
||||
if err != nil {
|
||||
return TalkgroupRange{}, fmt.Errorf("cannot parse range minimum: %v", err)
|
||||
}
|
||||
max, err := strconv.Atoi(parts[5])
|
||||
if err != nil {
|
||||
return TalkgroupRange{}, fmt.Errorf("cannot parse range maximum: %v", err)
|
||||
}
|
||||
|
||||
return TalkgroupRange{Min: min, Max: max}, nil
|
||||
}
|
||||
|
||||
const batteryChargeRequest = "AT+CBC?"
|
||||
|
||||
var batteryChargeResponse = regexp.MustCompile(`^\+CBC: .*,(\d+)$`)
|
||||
|
|
|
@ -34,3 +34,66 @@ func TestDegreesMinutesToDecimalDegrees(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTalkgroupRangeResponse(t *testing.T) {
|
||||
tt := []struct {
|
||||
response string
|
||||
kind string
|
||||
min string
|
||||
max string
|
||||
}{
|
||||
{
|
||||
response: "+CNUMS: (0),(1-2000),(1-2000)",
|
||||
kind: "S",
|
||||
min: "1",
|
||||
max: "2000",
|
||||
},
|
||||
{
|
||||
response: "+CNUMD: (0,1,3),(1-10000),(1-10000)",
|
||||
kind: "D",
|
||||
min: "1",
|
||||
max: "10000",
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.response, func(t *testing.T) {
|
||||
parts := talkgroupRangeResponse.FindStringSubmatch(tc.response)
|
||||
assert.Equal(t, 6, len(parts))
|
||||
assert.Equal(t, tc.kind, parts[1])
|
||||
assert.Equal(t, tc.min, parts[2])
|
||||
assert.Equal(t, tc.max, parts[5])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestParseTalkgroupInfo(t *testing.T) {
|
||||
tt := []struct {
|
||||
line string
|
||||
gtsi string
|
||||
name string
|
||||
}{
|
||||
{
|
||||
line: "+CNUMD: 1,123456712341234,Test Group",
|
||||
gtsi: "123456712341234",
|
||||
name: "Test Group",
|
||||
},
|
||||
{
|
||||
line: "+CNUMS: 1,123456712341234,Test Group",
|
||||
gtsi: "123456712341234",
|
||||
name: "Test Group",
|
||||
},
|
||||
{
|
||||
line: "1,123456712341234,Test Group",
|
||||
gtsi: "123456712341234",
|
||||
name: "Test Group",
|
||||
},
|
||||
}
|
||||
for _, tc := range tt {
|
||||
t.Run(tc.line, func(t *testing.T) {
|
||||
info, err := parseTalkgroupInfo(tc.line)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tc.gtsi, info.GTSI)
|
||||
assert.Equal(t, tc.name, info.Name)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue