Skip to content

Commit aca0124

Browse files
committed
api/firmware/device: info use device status fields
Return initialized status from info() and use unlocked and initialized to set the device status appropriately. Since the device will not respond with the expected byte if the firmware does not support it we return nil if it is not available.
1 parent 383ad4b commit aca0124

File tree

1 file changed

+45
-19
lines changed

1 file changed

+45
-19
lines changed

api/firmware/device.go

+45-19
Original file line numberDiff line numberDiff line change
@@ -145,24 +145,24 @@ func NewDevice(
145145

146146
// info uses the opInfo api endpoint to learn about the version, platform/edition, and unlock
147147
// status (true if unlocked).
148-
func (device *Device) info() (*semver.SemVer, common.Product, bool, error) {
148+
func (device *Device) info() (*semver.SemVer, common.Product, bool, *bool, error) {
149149

150150
// CAREFUL: hwwInfo is called on the raw transport, not on device.rawQuery, which behaves
151151
// differently depending on the firmware version. Reason: the version is not
152152
// available (this call is used to get the version), so it must work for all firmware versions.
153153
response, err := device.communication.Query([]byte(hwwInfo))
154154
if err != nil {
155-
return nil, "", false, err
155+
return nil, "", false, nil, err
156156
}
157157

158158
if len(response) < 4 {
159-
return nil, "", false, errp.New("unexpected response")
159+
return nil, "", false, nil, errp.New("unexpected response")
160160
}
161161
versionStrLen, response := int(response[0]), response[1:]
162162
versionBytes, response := response[:versionStrLen], response[versionStrLen:]
163163
version, err := semver.NewSemVerFromString(string(versionBytes))
164164
if err != nil {
165-
return nil, "", false, err
165+
return nil, "", false, nil, err
166166
}
167167
platformByte, response := response[0], response[1:]
168168
editionByte, response := response[0], response[1:]
@@ -175,24 +175,41 @@ func (device *Device) info() (*semver.SemVer, common.Product, bool, error) {
175175
}
176176
editions, ok := products[platformByte]
177177
if !ok {
178-
return nil, "", false, errp.Newf("unrecognized platform: %v", platformByte)
178+
return nil, "", false, nil, errp.Newf("unrecognized platform: %v", platformByte)
179179
}
180180
product, ok := editions[editionByte]
181181
if !ok {
182-
return nil, "", false, errp.Newf("unrecognized platform/edition: %v/%v", platformByte, editionByte)
182+
return nil, "", false, nil, errp.Newf("unrecognized platform/edition: %v/%v", platformByte, editionByte)
183183
}
184184

185185
var unlocked bool
186-
unlockedByte := response[0]
186+
unlockedByte, response := response[0], response[1:]
187187
switch unlockedByte {
188188
case 0x00:
189189
unlocked = false
190190
case 0x01:
191191
unlocked = true
192192
default:
193-
return nil, "", false, errp.New("unexpected reply")
193+
return nil, "", false, nil, errp.New("unexpected reply")
194194
}
195-
return version, product, unlocked, nil
195+
196+
// Before 9.20.0 REQ_INFO does not respond with a byte for the initialized status.
197+
if !version.AtLeast(semver.NewSemVer(9, 20, 0)) {
198+
return version, product, unlocked, nil, nil
199+
}
200+
201+
var initialized bool
202+
initializedByte := response[0]
203+
switch initializedByte {
204+
case 0x00:
205+
initialized = false
206+
case 0x01:
207+
initialized = true
208+
default:
209+
return nil, "", false, nil, errp.New("unexpected reply")
210+
}
211+
212+
return version, product, unlocked, &initialized, nil
196213
}
197214

198215
// Version returns the firmware version.
@@ -206,14 +223,9 @@ func (device *Device) Version() *semver.SemVer {
206223
// inferVersionAndProduct either sets the version and product by using OP_INFO if they were not
207224
// provided. In this case, the firmware is assumed to be >=v4.3.0, before that OP_INFO was not
208225
// available.
209-
func (device *Device) inferVersionAndProduct() error {
226+
func (device *Device) inferVersionAndProduct(version *semver.SemVer, product common.Product) error {
210227
// The version has not been provided, so we try to get it from OP_INFO.
211228
if device.version == nil {
212-
version, product, _, err := device.info()
213-
if err != nil {
214-
return errp.New(
215-
"OP_INFO unavailable; need to provide version and product via the USB HID descriptor")
216-
}
217229
device.log.Info(fmt.Sprintf("OP_INFO: version=%s, product=%s", version, product))
218230

219231
// sanity check
@@ -241,11 +253,25 @@ func (device *Device) Init() error {
241253
device.channelHashDeviceVerified = false
242254
device.sendCipher = nil
243255
device.receiveCipher = nil
244-
device.changeStatus(StatusConnected)
245256

246-
if err := device.inferVersionAndProduct(); err != nil {
247-
return err
257+
version, product, unlocked, initialized, err := device.info()
258+
if err != nil {
259+
return errp.New(
260+
"OP_INFO unavailable; need to provide version and product via the USB HID descriptor")
248261
}
262+
// The semantics of the firmware and status.Status are not the same.
263+
// status.Status StatusInitialized means the device is unlocked.
264+
// The firmware initialized = true means the device can be unlocked.
265+
if unlocked {
266+
device.changeStatus(StatusInitialized)
267+
} else if initialized {
268+
device.changeStatus(StatusConnected)
269+
} else {
270+
device.changeStatus(StatusUninitialized)
271+
}
272+
273+
device.inferVersionAndProduct(version, product)
274+
249275
if device.version.AtLeast(lowestNonSupportedFirmwareVersion) {
250276
device.changeStatus(StatusRequireAppUpgrade)
251277
return nil
@@ -261,7 +287,7 @@ func (device *Device) Init() error {
261287

262288
// Before 2.0.0, unlock was invoked automatically by the device before USB communication
263289
// started.
264-
if device.version.AtLeast(semver.NewSemVer(2, 0, 0)) {
290+
if device.version.AtLeast(semver.NewSemVer(2, 0, 0)) && (device.status != StatusInitialized) {
265291
_, err := device.rawQuery([]byte(opUnlock))
266292
if err != nil {
267293
// Most likely the device has been unplugged.

0 commit comments

Comments
 (0)