-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
improv.go
96 lines (82 loc) · 3.46 KB
/
improv.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 improv implements the [Improv] protocol for IoT devices.
//
// The Improv protocol is a simple protocol for configuring IoT devices over Bluetooth Low Energy (BLE).
// Allowing for the configuration of Wi-Fi settings and device identification over BLE.
//
// [Improv]: https://www.improv-wifi.com/
package improv
// UUIDs for the Improv service.
var (
SERVICE_UUID = [16]byte{0x00, 0x46, 0x77, 0x68, 0x62, 0x28, 0x22, 0x72, 0x46, 0x63, 0x27, 0x74, 0x78, 0x26, 0x80, 0x00} // Advertisement UUID
STATUS_UUID = [16]byte{0x00, 0x46, 0x77, 0x68, 0x62, 0x28, 0x22, 0x72, 0x46, 0x63, 0x27, 0x74, 0x78, 0x26, 0x80, 0x01} // Current state of the device
ERROR_UUID = [16]byte{0x00, 0x46, 0x77, 0x68, 0x62, 0x28, 0x22, 0x72, 0x46, 0x63, 0x27, 0x74, 0x78, 0x26, 0x80, 0x02} // Current error state of the device
RPC_COMMAND_UUID = [16]byte{0x00, 0x46, 0x77, 0x68, 0x62, 0x28, 0x22, 0x72, 0x46, 0x63, 0x27, 0x74, 0x78, 0x26, 0x80, 0x03} // Command received from the client
RPC_RESULT_UUID = [16]byte{0x00, 0x46, 0x77, 0x68, 0x62, 0x28, 0x22, 0x72, 0x46, 0x63, 0x27, 0x74, 0x78, 0x26, 0x80, 0x04} // Result of the command received from the client
CAPABILITIES_UUID = [16]byte{0x00, 0x46, 0x77, 0x68, 0x62, 0x28, 0x22, 0x72, 0x46, 0x63, 0x27, 0x74, 0x78, 0x26, 0x80, 0x05} // Capabilities of the device (Identify device)
)
// State constants
const (
STATE_STOPPED byte = iota
STATE_AWAITING_AUTHORIZATION // Awaiting authorization via physical interaction.
STATE_AUTHORIZED // Ready to accept credentials.
STATE_PROVISIONING // Credentials received, attempt to connect.
STATE_PROVISIONED // Connection successful.
)
// Command constants
const (
COMMAND_UNKNOWN byte = iota
COMMAND_WIFI_SETTINGS
COMMAND_IDENTIFY
)
// Error constants
const (
ERROR_NONE byte = iota // This shows there is no current error state.
ERROR_INVALID_RPC // RPC packet was malformed/invalid.
ERROR_UNKNOWN_RPC // The command sent is unknown.
ERROR_UNABLE_TO_CONNECT // The credentials have been received and an attempt to connect to the network has failed.
ERROR_NOT_AUTHORIZED // Credentials were sent via RPC but the Improv service is not authorized.
ERROR_UNKNOWN = 0xFF
)
func CmdToString(s byte) string {
switch s {
case COMMAND_UNKNOWN:
return "COMMAND_UNKNOWN"
case COMMAND_WIFI_SETTINGS:
return "COMMAND_WIFI_SETTINGS"
case COMMAND_IDENTIFY:
return "COMMAND_IDENTIFY"
}
return "UNKNOWN"
}
// ParseImprovData parses the data received from the Improv service and returns the command and arguments.
func ParseImprovData(data []byte) (byte, []string) {
cmd := data[0]
switch cmd {
case COMMAND_WIFI_SETTINGS:
ssidLength := int(data[2])
ssidStart := 3
ssidEnd := ssidStart + ssidLength
passLength := int(data[ssidEnd])
passStart := ssidEnd + 1
passEnd := passStart + passLength
ssid := string(data[ssidStart:ssidEnd])
password := string(data[passStart:passEnd])
return cmd, []string{ssid, password}
case COMMAND_IDENTIFY:
return cmd, nil
}
return COMMAND_UNKNOWN, nil
}
// BuildImprovResponse builds the Improv response packet.
func BuildImprovResponse(cmd byte, args []string) []byte {
output := []byte{0x00, (cmd)}
length := 0
for _, arg := range args {
len := len(arg)
length += len + 1
output = append(output, byte(len))
output = append(output, []byte(arg)...)
}
output[0] = byte(length)
return output
}