### Build and Send Raw Packets (C#) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Demonstrates how to construct and send custom SBHACK commands programmatically. Includes examples for reading from and writing to registers, with checksum calculation. ```csharp // Generic packet builder used by all button handlers List packet = new List(); // Example: read word from register 0x09 (Voltage) byte reg = 0x09; packet.AddRange(new byte[] { 0x3D, 0x00, 0x03, 0x04, 0x02, reg }); // SYNC LEN─ DC SDC payload // Append checksum (sum of bytes 1..N-1) byte cs = 0; for (int i = 1; i < packet.Count; i++) cs += packet[i]; packet.Add(cs); serial.Write(packet.ToArray(), 0, packet.Count); // Expected response: 3D 00 05 84 02 09 // Payload = [0x09, voltage_HB, voltage_LB] // e.g. 3D 00 05 84 02 09 2E E0 xx → voltage = 0x2EE0 = 11.996 V // Example: write word 0x1234 to register 0x00 (ManufacturerAccess / unseal) byte[] wordData = { 0x12, 0x34 }; packet.Clear(); packet.AddRange(new byte[] { 0x3D, 0x00, 0x05, 0x05, 0x02, 0x00, wordData[0], wordData[1] }); cs = 0; for (int i = 1; i < packet.Count; i++) cs += packet[i]; packet.Add(cs); serial.Write(packet.ToArray(), 0, packet.Count); ``` -------------------------------- ### Byte-Order Reversal Example Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Illustrates how to reverse the byte order of a key, converting from regular (MSB) order to reversed (LSB) order, which is often required by battery controllers. ```text UnsealKey: 0414 3672 -> 1404 7236 regular reversed ``` -------------------------------- ### Arduino Uno/Mega Hardware Setup for SMBus Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Connect Arduino I2C pins to the battery's SDA/SCL lines with appropriate pull-up resistors. Ensure correct pin mapping for Uno and Mega. ```text Arduino Uno → Smart Battery ────────────────────────────── GND → GND A4 (SDA) → SDA (4.7 kΩ pull-up to 5 V) A5 (SCL) → SCL (4.7 kΩ pull-up to 5 V) "System Present" pin → GND via 100–1000 Ω resistor (if required) Arduino Mega: D20 (SDA) → SDA D21 (SCL) → SCL ``` -------------------------------- ### smbus_reg_dump() Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads all registers within a specified range (start to end) as 16-bit words. The complete data dump is then transmitted to the host in a single status packet. ```APIDOC ## smbus_reg_dump() ### Description Reads every register in a start-to-end range as 16-bit words and sends the complete dump back to the host in a single status packet. ### Example ```cpp // Host sends: 3D 00 04 02 03 00 FF (dump all regs 0x00–0xFF) // ... function implementation ... // GUI interprets the dump with human-readable labels, e.g.: // [08]: 0EA5 // Temperature: 4.69°C (0x0EA5 = 3749 → 3749/100 - 273.15 ≈ 4.69) // [09]: 2EE0 // Voltage: 12.0 V // [0D]: 0064 // RelativeStateOfCharge: 100% // [17]: 0096 // CycleCount: 150 ``` ``` -------------------------------- ### Connect to Arduino via Serial Port (C#) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Establishes a serial connection to the Arduino at 250,000 baud and performs the SBHACK handshake. Requires setting up SerialPort with appropriate timeouts and buffer handling. ```csharp // Relevant fields byte[] HandshakeRequest = { 0x3D, 0x00, 0x02, 0x01, 0x00, 0x03 }; byte[] ExpectedHandshake = { 0x3D, 0x00, 0x08, 0x81, 0x00, 0x53, 0x42, 0x48, 0x41, 0x43, 0x4B, 0x35 }; // S B H A C K // Connection sequence SerialPort port = new SerialPort("COM3", 250000, Parity.None, 8, StopBits.One); port.ReadTimeout = 500; port.WriteTimeout = 500; port.Open(); port.DiscardInBuffer(); // Send handshake port.Write(HandshakeRequest, 0, HandshakeRequest.Length); // Read 12-byte response byte[] buf = new byte[2048]; port.Read(buf, 0, 12); // Verify "SBHACK" in bytes 5–10 bool connected = buf.Take(12).SequenceEqual(ExpectedHandshake); // connected == true → request current settings and enable UI // After connection, request current settings automatically: byte[] CurrentSettingsRequest = { 0x3D, 0x00, 0x02, 0x03, 0x01, 0x06 }; port.Write(CurrentSettingsRequest, 0, CurrentSettingsRequest.Length); // Response payload[0] = byte-order flags, payload[1..2] = design voltage (mV) ``` -------------------------------- ### Default Security Keys Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Lists common default security keys for UnSealKey, FullAccessKey, and PFKey. Note that these keys may need to be byte-reversed for some controllers. ```text [60] UnSealKey: 1234 5678 or 0414 3672 [61] FullAccessKey: 2234 5678 or FFFF FFFF [62] PFKey: 3234 5678 or 2673 1712 [63] AuthenKey3: 7654 3210 [64] AuthenKey2: FEDC BA98 [65] AuthenKey1: 89AB CDEF [66] AuthenKey0: 0123 4567 ``` -------------------------------- ### read_rom_byte() / read_rom_block() Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt These functions allow dumping the internal ROM of the BQ8050 by reading non-repeating address spaces and streaming data in chunks. The GUI then writes these chunks to a .bin file. ```APIDOC ## Arduino Firmware: `read_rom_byte()` / `read_rom_block()` Dumps the internal ROM of the BQ8050 by iterating through the non-repeating address spaces (0x0000–0x07FF, 0x4000–0x47FF, 0x8000–0x87FF) and streaming 128-byte chunks back to the host. The GUI writes each chunk to a `.bin` file. ```cpp // Host request (byte-by-byte mode): 3D 00 02 04 04 0A // Host request (block mode, 32 B): 3D 00 02 04 05 0B // Byte-by-byte approach (simplified): void read_rom_byte(void) { uint16_t address = 0; bool done = false; while (!done) { wdt_reset(); write_word(SetROMAddress, address); // 0x71 = SetROMAddress uint8_t data = read_byte(PeekROMByte); // 0x42 = PeekROMByte // ... buffer and send in 128-byte chunks via send_usb_packet() address++; if (address == 0x0800) address = 0x4000; // skip repeating region if (address == 0x4800) address = 0x8000; if (address == 0x8800) done = true; } send_usb_packet(ok_error, ok, ack, 1); // GUI writes received chunks to: ROMs/rom_YYYYMMDD_HHmmss.bin } ``` ``` -------------------------------- ### Enable Full Access Mode with FullAccessKey Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Enables full access mode after the battery has been unsealed. The FullAccessKey is written in two parts to the ManufacturerAccess register, similar to the unsealing process. ```shell 00 2234 write word 00 5678 write word ``` -------------------------------- ### Python: SBHack Class for SMBus Access Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Provides direct SMBus access on a Raspberry Pi using smbus2, bypassing Arduino. Useful for automation and headless environments. Handles reading and writing 16-bit words. ```python from smbus2 import SMBus import time class SBHack: def __init__(self, bus, address): self.bus = bus self.address = address def read_word(self, reg): """Read a 16-bit word (little-endian) from an SMBus register.""" try: data = self.bus.read_i2c_block_data(self.address, reg, 2) return (data[1] << 8) + data[0] # bytes are LSB-first except: return -1 def write_word(self, reg, word): """Write a 16-bit word (little-endian) to an SMBus register.""" data = [(word & 0xFF), (word >> 8) & 0xFF] try: self.bus.write_i2c_block_data(self.address, reg, data) except: return -1 def operation_status(self): status = self.read_word(0x54) print(f"OperationStatus: {status:#06x}") return status battery = SBHack(SMBus(1), 0x0B) # Dump all registers 0x00–0xFF for reg in range(0x100): val = battery.read_word(reg) if val > -1: print(f" {reg:#04x}: {val:#06x}") # Check seal status status = battery.operation_status() # 0xff0d → sealed, full-access disabled # 0xc001 → unsealed # 0x8001 → unsealed + full-access enabled # Unseal using default key 0x1234 / 0x5678 battery.write_word(0x00, 0x1234) time.sleep(0.1) battery.write_word(0x00, 0x5678) battery.operation_status() # should now be 0xc001 ``` -------------------------------- ### Arduino Firmware: Read ROM Data Byte-by-Byte Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads the internal ROM of the BQ8050 byte by byte. Requires iterating through specific address ranges and buffering data in 128-byte chunks for USB transmission. Ensure watchdog timer is reset periodically. ```cpp // Host request (byte-by-byte mode): 3D 00 02 04 04 0A // Host request (block mode, 32 B): 3D 00 02 04 05 0B // Byte-by-byte approach (simplified): void read_rom_byte(void) { uint16_t address = 0; bool done = false; while (!done) { wdt_reset(); write_word(SetROMAddress, address); // 0x71 = SetROMAddress uint8_t data = read_byte(PeekROMByte); // 0x42 = PeekROMByte // ... buffer and send in 128-byte chunks via send_usb_packet() address++; if (address == 0x0800) address = 0x4000; // skip repeating region if (address == 0x4800) address = 0x8000; if (address == 0x8800) done = true; } send_usb_packet(ok_error, ok, ack, 1); // GUI writes received chunks to: ROMs/rom_YYYYMMDD_HHmmss.bin } ``` -------------------------------- ### Arduino Firmware: Send USB Packet Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Core function for assembling and sending USB packets. Automatically prepends sync, length, and datacode bytes, and appends a checksum. Used for all responses. ```cpp // Sending a "handshake OK" response (SBHACK): uint8_t payload[] = { 0x53, 0x42, 0x48, 0x41, 0x43, 0x4B }; // "SBHACK" send_usb_packet(handshake, 0x00, payload, 6); // Emits: 3D 00 08 81 00 53 42 48 41 43 4B 35 // SY LEN── DC SDC S B H A C K CS // Sending a word-read result for reg 0x09 (voltage = 0x2EE0): uint8_t resp[] = { 0x09, 0x2E, 0xE0 }; send_usb_packet(read_data, sd_read_word, resp, 3); // Emits: 3D 00 05 84 02 09 2E E0 // Sending an error: send_usb_packet(ok_error, error_checksum_invalid_value, err, 1); // Emits: 3D 00 03 8F 05 FF ``` -------------------------------- ### Arduino: Dump SMBus Registers Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads every register in a specified start-to-end range as 16-bit words and sends the complete dump back to the host in a single status packet. The GUI interprets the dump with human-readable labels. ```cpp // Host sends: 3D 00 04 02 03 00 FF (dump all regs 0x00–0xFF) void smbus_reg_dump(void) { // payload = [start_reg, end_reg, reg0_HB, reg0_LB, reg1_HB, reg1_LB, ...] uint16_t payload_len = 3 * (smbus_reg_end - smbus_reg_start + 1) + 2; uint8_t payload[payload_len]; payload[0] = smbus_reg_start; payload[1] = smbus_reg_end; for (uint16_t i = smbus_reg_start; i <= smbus_reg_end; i++) { uint16_t data = read_word(i, reverse_read_word_byte_order); payload[2 + 3*(i-smbus_reg_start)] = i; payload[3 + 3*(i-smbus_reg_start)] = (data >> 8) & 0xFF; payload[4 + 3*(i-smbus_reg_start)] = data & 0xFF; } send_usb_packet(status, sd_smbus_reg_dump, payload, payload_len); } // GUI interprets the dump with human-readable labels, e.g.: // [08]: 0EA5 // Temperature: 4.69°C (0x0EA5 = 3749 → 3749/100 - 273.15 ≈ 4.69) // [09]: 2EE0 // Voltage: 12.0 V // [0D]: 0064 // RelativeStateOfCharge: 100% // [17]: 0096 // CycleCount: 150 ``` -------------------------------- ### Arduino: Scan SMBus Addresses Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Probes every I²C address from 0x03 to 0x7F and returns ACK'd addresses. The result is sent back to the host as an SBHACK status packet. If no devices are found, an error code (0xFF) is sent. ```cpp // Triggered by host packet: 3D 00 02 02 02 06 void scan_smbus_address(void) { scan_smbus_address_result_ptr = 0; for (uint8_t i = 3; i < 120; i++) { bool ack = i2c_start((i << 1) | I2C_WRITE); if (ack) { i2c_stop(); scan_smbus_address_result[scan_smbus_address_result_ptr++] = i; if (scan_smbus_address_result_ptr > 7) scan_smbus_address_result_ptr = 7; } i2c_stop(); } if (scan_smbus_address_result_ptr > 0) send_usb_packet(status, sd_scan_smbus_address, scan_smbus_address_result, scan_smbus_address_result_ptr); else send_usb_packet(status, sd_scan_smbus_address, err, 1); // 0xFF = no device // Response packet example when battery found at 0x0B: // 3D 00 03 82 02 0B 92 // ^^ address = 0x0B } ``` -------------------------------- ### send_usb_packet(command, subdatacode, payload, length) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt This is the core function for assembling and transmitting USB packets. It automatically adds SYNC, LENGTH, and DATACODE bytes, and appends a CHECKSUM to all responses. ```APIDOC ## Arduino Firmware: `send_usb_packet(command, subdatacode, payload, length)` Core packet assembly and transmission function used for all responses. Automatically prepends SYNC, LENGTH, and DATACODE bytes and appends the CHECKSUM. ```cpp // Sending a "handshake OK" response (SBHACK): uint8_t payload[] = { 0x53, 0x42, 0x48, 0x41, 0x43, 0x4B }; // "SBHACK" send_usb_packet(handshake, 0x00, payload, 6); // Emits: 3D 00 08 81 00 53 42 48 41 43 4B 35 // SY LEN── DC SDC S B H A C K CS // Sending a word-read result for reg 0x09 (voltage = 0x2EE0): uint8_t resp[] = { 0x09, 0x2E, 0xE0 }; send_usb_packet(read_data, sd_read_word, resp, 3); // Emits: 3D 00 05 84 02 09 2E E0 // Sending an error: send_usb_packet(ok_error, error_checksum_invalid_value, err, 1); // Emits: 3D 00 03 8F 05 FF ``` ``` -------------------------------- ### Unsealing Battery Security (UnsealKey method) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt This section details the protocol for unsealing a battery using the UnsealKey. It involves writing two 16-bit halves of the key to the ManufacturerAccess register within a specific time frame and verifying the status. ```APIDOC ## Battery Security: Unsealing (UnsealKey method) The 32-bit UnsealKey is split into two 16-bit halves and written sequentially to ManufacturerAccess (0x00) within 4 seconds. The OperationStatus register (0x54) indicates success. ``` # Protocol sequence (register notation: ) # 1. Check current seal state 54 read word # → FFFF (bit0=1 sealed, bit1=1 full-access disabled) or # → FF0D (same meaning, alternate reading) # 2. Write first half of UnSealKey to ManufacturerAccess 00 1234 write word ← first 16-bit half (reversed on wire: 34 12) # 3. Write second half within 4 seconds 00 5678 write word ← second 16-bit half (reversed on wire: 78 56) # 4. Verify 54 read word # → C001 (bit0=0 unsealed ✓, bit1=1 full-access still disabled) # Known default keys (try in order): # UnSealKey: 1234 5678 or 0414 3672 # FullAccessKey: 2234 5678 or FFFF FFFF # PFKey: 3234 5678 or 2673 1712 ``` ``` -------------------------------- ### SBHACK Serial Packet Format Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Defines the framing format for communication between the host and the Arduino. Includes SYNC, LENGTH, DATACODE, SUBDATACODE, PAYLOAD, and CHECKSUM. ```text Packet structure (host → device): [ 0x3D | LEN_HB | LEN_LB | DATACODE | SUBDATACODE | PAYLOAD… | CHECKSUM ] DATACODE low nibble = command: 0x00 reset 0x01 handshake 0x02 status 0x03 settings 0x04 read_data 0x05 write_data 0x0F ok_error CHECKSUM = sum of all bytes from LEN_HB through last PAYLOAD byte (mod 256) Example — handshake request packet (no payload): 3D 00 02 01 00 03 │ └──┘ │ │ └─ checksum (0x00+0x02+0x01+0x00 = 0x03) SYNC LEN DC SDC Expected handshake response from device: 3D 00 08 81 00 53 42 48 41 43 4B 35 S B H A C K ``` -------------------------------- ### SBHack class Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt A Python class for the Raspberry Pi that provides direct SMBus access to the battery, bypassing the Arduino. It's suitable for automated tasks and headless operation. ```APIDOC ## Python (RPi): `SBHack` class Provides direct SMBus access on a Raspberry Pi using `smbus2`, bypassing the Arduino bridge entirely. Useful for scripted automation or headless environments. ```python from smbus2 import SMBus import time class SBHack: def __init__(self, bus, address): self.bus = bus self.address = address def read_word(self, reg): """Read a 16-bit word (little-endian) from an SMBus register.""" try: data = self.bus.read_i2c_block_data(self.address, reg, 2) return (data[1] << 8) + data[0] # bytes are LSB-first except: return -1 def write_word(self, reg, word): """Write a 16-bit word (little-endian) to an SMBus register.""" data = [(word & 0xFF), (word >> 8) & 0xFF] try: self.bus.write_i2c_block_data(self.address, reg, data) except: return -1 def operation_status(self): status = self.read_word(0x54) print(f"OperationStatus: {status:#06x}") return status battery = SBHack(SMBus(1), 0x0B) # Dump all registers 0x00–0xFF for reg in range(0x100): val = battery.read_word(reg) if val > -1: print(f" {reg:#04x}: {val:#06x}") # Check seal status status = battery.operation_status() # 0xff0d → sealed, full-access disabled # 0xc001 → unsealed # 0x8001 → unsealed + full-access enabled # Unseal using default key 0x1234 / 0x5678 battery.write_word(0x00, 0x1234) time.sleep(0.1) battery.write_word(0x00, 0x5678) battery.operation_status() # should now be 0xc001 ``` ``` -------------------------------- ### Battery Security: SHA-1 Authentication Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Describes the SHA-1 based challenge-response authentication scheme for batteries. Requires computing a 160-bit HMAC digest from the device's challenge and a 128-bit authentication key. ```text # For batteries that use the SHA-1-based challenge-response authentication scheme, a 160-bit HMAC digest must be computed from the device's challenge and the 128-bit authentication key. ``` -------------------------------- ### scan_smbus_address() Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Probes every I²C address from 0x03 to 0x7F to identify active devices on the SMBus. The addresses that respond with an ACK are reported back to the host as an SBHACK status packet. ```APIDOC ## scan_smbus_address() ### Description Probes every I²C address from 0x03 to 0x7F and returns ACK'd addresses; result is sent back to the host as an SBHACK status packet. ### Example ```cpp // Triggered by host packet: 3D 00 02 02 02 06 // ... function implementation ... // Response packet example when battery found at 0x0B: // 3D 00 03 82 02 0B 92 // ^^ address = 0x0B ``` ``` -------------------------------- ### Unseal Battery with UnsealKey Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Unseals the battery by writing the UnsealKey in two parts to the ManufacturerAccess register. Ensure the writes are less than 4 seconds apart; otherwise, the attempt will fail and lock out for 4 seconds. ```shell 00 1234 write word 00 5678 write word ``` -------------------------------- ### SHA-1 Authentication Key Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Provides the known 128-bit authentication key for SHA-1 authentication as specified in the BQ8050 datasheet. ```text CBA4CBA4CBA4CBA4C317C317C317C317 ``` -------------------------------- ### Read OperationStatus Register Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Reads the OperationStatus register to check the current security state of the battery. Use this before and after attempting security operations. ```shell 54 read word ``` -------------------------------- ### write_word(reg, data, reverse) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Writes a 16-bit word to an SMBus register. This function is used for key-writing operations like unsealing the battery, granting full access, and clearing protection flags. Words are written in LSB-first order by default to match the battery controller's byte order. ```APIDOC ## write_word(reg, data, reverse) ### Description Writes a 16-bit word to an SMBus register. Used for all key-writing operations (unseal, full-access, PF-clear). Words must be written reversed (LSB first) to match the battery controller's byte order. ### Parameters - **reg** (uint8_t) - The SMBus register address to write to. - **data** (uint16_t) - The 16-bit data to write. - **reverse** (bool) - Optional. If true (default), writes data LSB first. If false, writes MSB first. ### Returns - uint8_t - The number of bytes written (always 2 for a word). ### Example ```cpp // Write first half of UnSealKey (0x1234) to ManufacturerAccess (0x00) write_word(0x00, 0x1234); // writes bytes: 34 12 // Write second half (0x5678) within 4 seconds write_word(0x00, 0x5678); // writes bytes: 78 56 // Check result // uint16_t status = read_word(0x54); // 0xC001 → unsealed, full-access disabled ✓ ``` ``` -------------------------------- ### Arduino: Read SMBus Block from Register Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads a variable-length SMBus block from a register. The first byte returned is the block length, followed by the data bytes. Ensure the buffer is large enough to hold the length byte plus up to 256 data bytes. ```cpp uint8_t buffer[257]; // 1 length + up to 256 data bytes uint8_t read_block(uint8_t reg, uint8_t* block_buffer) { i2c_start((sb_address << 1) | I2C_WRITE); i2c_write(reg); i2c_rep_start((sb_address << 1) | I2C_READ); uint8_t len = i2c_read(false); // first byte = length block_buffer[0] = len; for (uint8_t i = 0; i < (len - 1); i++) block_buffer[1 + i] = i2c_read(false); block_buffer[len] = i2c_read(true); // NACK last byte i2c_stop(); return (len + 1); } // Read ManufacturerName (0x20) – ASCII string block uint8_t block[257]; uint8_t total = read_block(0x20, block); // block[0] = length (e.g. 4) // block[1..4] = ASCII chars, e.g. "DELL" ``` -------------------------------- ### Battery Security: Unsealing Protocol Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Details the protocol for unsealing a battery using a 32-bit UnsealKey, split into two 16-bit halves written sequentially to ManufacturerAccess (0x00) within 4 seconds. The OperationStatus register (0x54) is used to verify the state. ```text # Protocol sequence (register notation: ) # 1. Check current seal state 54 read word # → FFFF (bit0=1 sealed, bit1=1 full-access disabled) or # → FF0D (same meaning, alternate reading) # 2. Write first half of UnSealKey to ManufacturerAccess 00 1234 write word ← first 16-bit half (reversed on wire: 34 12) # 3. Write second half within 4 seconds 00 5678 write word ← second 16-bit half (reversed on wire: 78 56) # 4. Verify 54 read word # → C001 (bit0=0 unsealed ✓, bit1=1 full-access still disabled) # Known default keys (try in order): # UnSealKey: 1234 5678 or 0414 3672 # FullAccessKey: 2234 5678 or FFFF FFFF # PFKey: 3234 5678 or 2673 1712 ``` -------------------------------- ### Arduino: Write 16-bit Word to SMBus Register Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Writes a 16-bit word to an SMBus register, used for key-writing operations. Words are written reversed (LSB first) by default to match the battery controller's byte order. ```cpp uint8_t write_word(uint8_t reg, uint16_t data, bool reverse = true) { i2c_start((sb_address << 1) | I2C_WRITE); i2c_write(reg); if (reverse) { i2c_write(data & 0xFF); // LSB first i2c_write((data >> 8) & 0xFF); // MSB second } else { i2c_write((data >> 8) & 0xFF); i2c_write(data & 0xFF); } i2c_stop(); return 2; } // Write first half of UnSealKey (0x1234) to ManufacturerAccess (0x00) write_word(0x00, 0x1234); // writes bytes: 34 12 // Write second half (0x5678) within 4 seconds write_word(0x00, 0x5678); // writes bytes: 78 56 // Check result uint16_t status = read_word(0x54); // 0xC001 → unsealed, full-access disabled ✓ ``` -------------------------------- ### read_block(reg, block_buffer) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads a variable-length SMBus block from a specified register. The first byte returned by the device indicates the block length, followed by the actual data bytes. ```APIDOC ## read_block(reg, block_buffer) ### Description Reads a variable-length SMBus block from a register. The first byte returned by the device is the block length; the remaining bytes are the data. ### Parameters - **reg** (uint8_t) - The SMBus register address to read from. - **block_buffer** (uint8_t*) - A buffer to store the read data. The first element `block_buffer[0]` will store the length of the block. ### Returns - uint8_t - The total number of bytes read, including the length byte. ### Example ```cpp // Read ManufacturerName (0x20) – ASCII string block uint8_t buffer[257]; // 1 length + up to 256 data bytes uint8_t total = read_block(0x20, buffer); // buffer[0] = length (e.g. 4) // buffer[1..4] = ASCII chars, e.g. "DELL" ``` ``` -------------------------------- ### write_block(reg, block_buffer, length) Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Writes a block of bytes to an SMBus register. This function is typically used for changing security keys when the battery is in full-access mode. ```APIDOC ## write_block(reg, block_buffer, length) ### Description Writes a block of bytes to an SMBus register (used for changing security keys in full-access mode). ### Parameters - **reg** (uint8_t) - The SMBus register address to write to. - **block_buffer** (uint8_t*) - A pointer to the buffer containing the data to write. - **block_buffer_length** (uint8_t) - The number of data bytes to write (excluding the length byte). ### Returns - uint8_t - The number of data bytes written. ### Example ```cpp // Change UnSealKey register (0x60) to new 4-byte key in full-access mode uint8_t new_key[] = { 0x04, 0x14, 0x36, 0x72 }; // bytes LSB-first write_block(0x60, new_key, 4); // Verify with a subsequent read_block(0x60, buffer) ``` ``` -------------------------------- ### Arduino C++: Read Single SMBus Byte Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads a single byte from a specified SMBus register using the SoftI2CMaster library. Assumes default battery address (0x0B). ```cpp #include uint8_t sb_address = 0x0B; // default BQ8050 address uint8_t read_byte(uint8_t reg) { i2c_start((sb_address << 1) | I2C_WRITE); i2c_write(reg); i2c_rep_start((sb_address << 1) | I2C_READ); uint8_t ret = i2c_read(true); // NACK last byte, release bus i2c_stop(); return ret; } // Usage uint8_t low = read_byte(0x54); // Returns e.g. 0x0D → battery is sealed, full-access disabled ``` -------------------------------- ### Arduino: Write Block of Bytes to SMBus Register Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Writes a block of bytes to an SMBus register, typically used for changing security keys in full-access mode. The first byte sent after the register address is the block length. ```cpp uint8_t write_block(uint8_t reg, uint8_t* block_buffer, uint8_t block_buffer_length) { i2c_start((sb_address << 1) | I2C_WRITE); i2c_write(reg); i2c_write(block_buffer_length); // length byte for (uint8_t i = 0; i < block_buffer_length; i++) i2c_write(block_buffer[i]); i2c_stop(); return block_buffer_length; } // Change UnSealKey register (0x60) to new 4-byte key in full-access mode uint8_t new_key[] = { 0x04, 0x14, 0x36, 0x72 }; // bytes LSB-first write_block(0x60, new_key, 4); // Verify with a subsequent read_block(0x60, buffer) ``` -------------------------------- ### Seal Battery Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Seals the battery to reduce security access by writing 0020 to the ManufacturerAccess register. This action reverts the battery to a sealed state. ```shell 00 0020 write word ``` -------------------------------- ### Arduino C++: Read 16-bit SMBus Word Source: https://context7.com/laszlodaniel/smartbatteryhack/llms.txt Reads a 16-bit word from an SMBus register, handling byte order. By default, it reverses bytes to account for little-endian storage. ```cpp // Read OperationStatus (0x54) – 16-bit word uint16_t read_word(uint8_t reg, bool reverse = true) { i2c_start((sb_address << 1) | I2C_WRITE); i2c_write(reg); i2c_rep_start((sb_address << 1) | I2C_READ); uint8_t b1 = i2c_read(false); // ACK first byte uint8_t b2 = i2c_read(true); // NACK last byte i2c_stop(); if (!reverse) return ((b1 << 8) | b2); // MSB-first else return ((b2 << 8) | b1); // LSB-first (default) } // Read OperationStatus uint16_t op = read_word(0x54); // e.g. 0xFF0D → sealed // Bits: YX...... // X=1 → sealed X=0 → unsealed // Y=1 → full-access disabled Y=0 → full-access enabled // Read pack voltage (0x5A) uint16_t millivolts = read_word(0x5A); // e.g. 12600 → 12.6 V ``` -------------------------------- ### Indirectly Read OperationStatus Register Source: https://github.com/laszlodaniel/smartbatteryhack/wiki/Basics Reads the OperationStatus register indirectly via ManufacturerAccess. This method is an alternative to direct reading. ```shell 00 0054 write word 00 read word ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.