-
Notifications
You must be signed in to change notification settings - Fork 8
/
node_send_message.go
96 lines (78 loc) · 2.7 KB
/
node_send_message.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package zstack
import (
"context"
"errors"
"fmt"
"github.com/shimmeringbee/logwrap"
"github.com/shimmeringbee/zigbee"
)
const DefaultRadius uint8 = 0x20
func (z *ZStack) SendApplicationMessageToNode(ctx context.Context, destinationAddress zigbee.IEEEAddress, message zigbee.ApplicationMessage, requireAck bool) error {
network, err := z.ResolveNodeNWKAddress(ctx, destinationAddress)
if err != nil {
z.logger.LogError(ctx, "Failed to send AfDataRequest (application message), failed to resolve IEEE Address to Network Adddress.", logwrap.Err(err), logwrap.Datum("IEEEAddress", destinationAddress.String()))
return err
}
if err := z.sem.Acquire(ctx, 1); err != nil {
return fmt.Errorf("failed to acquire semaphore: %w", err)
}
defer z.sem.Release(1)
var transactionId uint8
select {
case transactionId = <-z.transactionIdStore:
defer func() { z.transactionIdStore <- transactionId }()
case <-ctx.Done():
return errors.New("context expired while obtaining a free transaction ID")
}
request := AfDataRequest{
DestinationAddress: network,
DestinationEndpoint: message.DestinationEndpoint,
SourceEndpoint: message.SourceEndpoint,
ClusterID: message.ClusterID,
TransactionID: transactionId,
Options: AfDataRequestOptions{ACKRequest: requireAck},
Radius: DefaultRadius,
Data: message.Data,
}
if requireAck {
_, err = z.nodeRequest(ctx, &request, &AfDataRequestReply{}, &AfDataConfirm{}, func(i interface{}) bool {
msg := i.(*AfDataConfirm)
return msg.TransactionID == transactionId && msg.Endpoint == message.DestinationEndpoint
})
} else {
err = z.requestResponder.RequestResponse(ctx, &request, &AfDataRequestReply{})
}
return err
}
type AfDataRequestOptions struct {
Reserved0 uint8 `bcfieldwidth:"1"`
EnableSecurity bool `bcfieldwidth:"1"`
DiscoveryRoute bool `bcfieldwidth:"1"`
ACKRequest bool `bcfieldwidth:"1"`
Reserved1 uint8 `bcfieldwidth:"4"`
}
type AfDataRequest struct {
DestinationAddress zigbee.NetworkAddress
DestinationEndpoint zigbee.Endpoint
SourceEndpoint zigbee.Endpoint
ClusterID zigbee.ClusterID
TransactionID uint8
Options AfDataRequestOptions
Radius uint8
Data []byte `bcsliceprefix:"8"`
}
const AfDataRequestID uint8 = 0x01
type AfDataRequestReply GenericZStackStatus
func (s AfDataRequestReply) WasSuccessful() bool {
return s.Status == ZSuccess
}
const AfDataRequestReplyID uint8 = 0x01
type AfDataConfirm struct {
Status ZStackStatus
Endpoint zigbee.Endpoint
TransactionID uint8
}
func (s AfDataConfirm) WasSuccessful() bool {
return s.Status == ZSuccess
}
const AfDataConfirmID uint8 = 0x80