I got myself a Petzl NAO RL for (ultra-)trailrunning, wich is equipped with a USB C connetor for the battery. My first thougt: Nice, I could run it on a bigger powerbank in my backpack. 

This kind of works, when using a extention cord with 5 kOhm "OTG" resistors on CC pins to enable power output. But this only enables the "normal" operation mode, the reactive lighting is not working. So lets find out why. 

When the USB plug is connected, the Naos battery outputs 5.1V to the headlamp. The headlamp then uses the sidebanduse (SBU, B8) pin to talk back to the battery. This happens as 1-wire bus running at 19200 baud and a level of 2.7V. The headlamp acts as the master.

The headlamp authentificates with the battery with a challenge by sending a seed, which the battery has to reply to. If correct, a second seed is send. Then some yet unknown messages are send.

Handshake example:

--> 40 01 A8 9F AE (request)
<-- 60 01 9B 2D 9C (response)
--> 41 01 09 1C 17
<-- 61 01 09 5E 38
--> 42 05 00 00 5F
<-- 62 05 32 2A 19
--> 03 04 00 00 62
<-- 23 04 0B 86 D4
--> 04 12 00 00 F1
(VCC is lowered to 3.9V)
--> 24 12 0B 86 47
<-- 05 0C 00 00 39
...

When authentification was sucessful, the voltage on VCC lowers to ~3.9V (probably Li-Ion passthru) as long as the SBU is pulled high. Even when completly "off", as long as you dont disconnect the battery.

General protocol information:

example:  

03 0A 00 00 95 
23 0A 90 18 52

Structure: SID+SN PID data[...] Checksum

SID read request: 0x0X
SID write request: 0x4X

SID response: request + 0x20 where X = Sequence number in range 0 to 7 starting at 0 incrementing after each message.

Checksum is calculated with these parameters (thanks to this): 

width=8  poly=0x31  init=0xff  refin=false  refout=false  xorout=0x00  check=0xf7  residue=0x00  name="CRC-8/NRSC-5"


Authentification 

To understand the authentification I made a circuit to power the headlamp and capture the handshake with an Arduino, then power the headlamp off, waiting 4 second (required as cooldown for the battery) and then apply power again. The serial recording and analysis was done in python with pandas. In this way I collected ~2000 samples within a few hours to work with. The first to check if a response to a challenge is constant (so same result for each time requested). With this approach I found out, that the challenges are nestet, so the first request ist answered last and the other one in between. The second thing to check was, if the challenges are dependent on each other. For this I compared the results of the same challenge, one time as the inner one, one time as the outer one: They are the same. Yea, much less complexity.

 So we got a function mapping 2 Byte on 2 Byte. Checking the data revealed, that there are several inputs (challenges) for the same output (response) and he first byte of the resonse is alway below 16. The second byte of the response differs a lot when only one bit of the input is changed. 

After a few hours of manual search and the attempt of getting something out of ChatGPT (did not work at all, it just provided incorrect FAKE answers preteending to be the solution) it was clear: The first byte is the "sum of set bits" (like Brian Kernighan Algorithm) and the second one is the same as the checksum calculation (again found with reveng.exe)

The authentification is done in 2 steps:

--> 40 01 A8 9F AE Challenge (outer) from headlamp: A8 9F
<-- 60 01 9B 2D 9C Challenge (inner) from Battery: 9B 2D
--> 41 01 09 1C 17 Response to battery (inner): 09 1C
<-- 61 01 09 5E 38 Response to headlamp (outer): 09 5E

Known commands:

These commands can be decoded easily by knowing the environment (voltage, current, temperature, power state)

4X 0D 00 0Y CRC: Set default value of red backlight without enabeling it. Y= 0: off, 1: constant, 2: blinking
4X 0E 00 0Y CRC: Set red backlight. Y= 0: off, 1: constant, 2: blinking

0X 0D 00 00...
Read more »