Files
BattMITM_2.0/config_override.h

191 lines
7.6 KiB
C

/**
MIT License
Copyright (c) 2025 Benjamin Wiegand
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
*/
#include "mitm.h"
#include "battery.h"
#include <stdio.h>
/* ================================= DANGER!!!! READ THIS FIRST ================================= *
* If you don't know what you're doing, do not touch this file. I cannot stress this enough. *
* Modifying reponses from the BMS can have disastrous consequences when done wrong. *
* *
* I am not responsible for property damage or bolidly harm as a result of modifying this file. *
* *
* YOU HAVE BEEN WARNED. *
* ============================================================================================== */
/*
this file lets you define overrides that modify communications between your laptop and your BMS.
currently there is only one supported override type: read command reply override
fortunately, this one override type encompasses 99% of useful modifications.
read command reply overrides allow you to replace or modify the reply of any read command
issued by the laptop (for the battery). they are defined in the form of functions as to not
limit flexibility.
in a read command reply override function you can:
- read bytes from the battery (+ verify crc) to get the real response
- write a custom reply to the reply_buffer that the laptop will read from
- generate a crc to be inserted at the end of your custom reply
- return a negative value to trash the response if an error occurs
- anything else that you can normally do in C on a microcontroller
in a read command reply override function you cannot:
- know the full response length from the battery (i2c limitation)
- know how many bytes the laptop will read from the reply_buffer (i2c limitation)
- explicitly abort the transfer (i2c limitation)
- tell the laptop not to check the crc (you just can't ok)
the examples defined below in this file show how to successfully replace/modify responses from
the bms.
for more information on SBS commands and their nuances, consult the spec: https://sbs-forum.org/specs/
once you have your function defined, remember to add it to the switch statement at the bottom
of this file to enable it!
*/
// example read command reply override that returns a custom serial number
int override_example_replace_serial_number(uint8_t cmd, uint8_t* reply_buffer) {
if (cmd != BATT_CMD_SERIAL_NUMBER) return -1;
// you can use any 2-byte serial number here
uint16_t serial_number = 6969;
// low byte is sent first
reply_buffer[0] = serial_number & 0x00FF;
reply_buffer[1] = (serial_number & 0xFF00) >> 8;
// generate a crc-8 checksum for the new reply
if (mitm_generate_reply_crc(reply_buffer, 2, false) < 0) return -1;
return 0;
}
// example read command reply override that returns a custom manufacturer name
int override_example_replace_manufacturer_name(uint8_t cmd, uint8_t* reply_buffer) {
if (cmd != BATT_CMD_MANUFACTURER_NAME) return -1;
// set whatever string you want here as long as it fits within the reply buffer (MITM_REPLY_BUFFER_SIZE - 2)
char manufacturer_name[] = "BattMITM";
uint8_t length = sizeof(manufacturer_name);
// set block length (in this case the string length)
reply_buffer[0] = length;
// add block content
for (int i = 0; i < length; i++) {
reply_buffer[i+1] = manufacturer_name[i];
}
// generate a crc-8 checksum for the new reply
// note: is_block is true since the manufacturer name uses a block read!
if (mitm_generate_reply_crc(reply_buffer, length + 1, true) < 0) return -1;
return 0;
}
// example read command reply override that replaces all 'A's in the manufacturer name with 'O's
int override_example_modify_manufacturer_name(uint8_t cmd, uint8_t* reply_buffer) {
if (cmd != BATT_CMD_MANUFACTURER_NAME) return -1;
int reply_index = 0;
int ret;
uint8_t block_length;
// read the block length
ret = mitm_read_batt_reply(reply_buffer, 1);
if (ret < 0) return -1;
reply_index += ret;
block_length = reply_buffer[0];
// ensure we won't overrun the buffer, considering 2 bytes for block length and crc
if (block_length + 2 > MITM_REPLY_BUFFER_SIZE) {
// this could be due to a corrupted reply from the battery
printf("reply won't fit in buffer! reply_length = %d, buffer_size = %d\n", block_length + 2, MITM_REPLY_BUFFER_SIZE);
return -1;
}
// read the block content + crc
ret = mitm_read_batt_reply(reply_buffer + reply_index, block_length + 1);
if (ret < 0) return -1;
reply_index += ret;
// validate the crc
if (!mitm_validate_batt_reply(reply_buffer, reply_index - 1, true)) return -1;
// modify block content (replace all 'A's with 'O's)
for (int i = 1; i < reply_index - 1; i++) {
if (reply_buffer[i] == 'A') {
reply_buffer[i] = 'O';
}
}
// generate a crc-8 checksum for the new reply
if (mitm_generate_reply_crc(reply_buffer, reply_index - 1, true) < 0) return -1;
return 0;
}
// map command codes to override functions here
// for a list of command code definitions see battery.h
cmd_reply_override config_get_read_command_reply_override(uint8_t cmd) {
switch (cmd) {
// examples:
//case BATT_CMD_SERIAL_NUMBER: return &override_example_replace_serial_number;
//case BATT_CMD_MANUFACTURER_NAME: return &override_example_replace_manufacturer_name;
//case BATT_CMD_MANUFACTURER_NAME: return &override_example_modify_manufacturer_name;
default: return NULL; // no override
}
}
// defines whether the gui (defused) will use the override instead of reading directly from the battery
bool config_defused_use_read_command_reply_override(uint8_t cmd) {
// you can write a switch statement here to change this behavior per command
return true; // use the override by default
}
// defines whether the uart interface (not yet implemented) will use the override instead of reading directly from the battery
bool config_uart_use_read_command_reply_override(uint8_t cmd) {
// you can write a switch statement here to change this behavior per command
return false; // don't use the override by default
}