initial commit

This commit is contained in:
Benjamin Wiegand
2025-08-24 19:35:56 -07:00
commit 4d175613e9
6 changed files with 323 additions and 0 deletions
+2
View File
@@ -0,0 +1,2 @@
build
!.vscode/*
+57
View File
@@ -0,0 +1,57 @@
# Generated Cmake Pico project file
cmake_minimum_required(VERSION 3.13)
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Initialise pico_sdk from installed location
# (note this can come from environment, CMake cache etc)
# == DO NOT EDIT THE FOLLOWING LINES for the Raspberry Pi Pico VS Code Extension to work ==
if(WIN32)
set(USERHOME $ENV{USERPROFILE})
else()
set(USERHOME $ENV{HOME})
endif()
set(sdkVersion 2.2.0)
set(toolchainVersion 14_2_Rel1)
set(picotoolVersion 2.2.0)
set(picoVscode ${USERHOME}/.pico-sdk/cmake/pico-vscode.cmake)
if (EXISTS ${picoVscode})
include(${picoVscode})
endif()
# ====================================================================================
set(PICO_BOARD pico CACHE STRING "Board type")
# Pull in Raspberry Pi Pico SDK (must be before project)
include(pico_sdk_import.cmake)
project(BattMITM_2.0 C CXX ASM)
# Initialise the Raspberry Pi Pico SDK
pico_sdk_init()
# Add executable. Default name is the project name, version 0.1
add_executable(BattMITM_2.0 main.c )
pico_set_program_name(BattMITM_2.0 "BattMITM_2.0")
pico_set_program_version(BattMITM_2.0 "0.1")
# Modify the below lines to enable/disable output over UART/USB
pico_enable_stdio_uart(BattMITM_2.0 0)
pico_enable_stdio_usb(BattMITM_2.0 0)
# Add the standard library to the build
target_link_libraries(BattMITM_2.0
pico_stdlib)
# Add the standard include files to the build
target_include_directories(BattMITM_2.0 PRIVATE
${CMAKE_CURRENT_LIST_DIR}
)
pico_add_extra_outputs(BattMITM_2.0)
+9
View File
@@ -0,0 +1,9 @@
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.
+121
View File
@@ -0,0 +1,121 @@
# BattMITM
rewriting it for pi pico for some reason.
the goal is to match (and possibly exceed) the existing implementation currently mounted to my laptop that I'm typing this on:
![the arduino leonardo that's attached to my battery, complete with small OLED display](https://ben.wiegand.pw/img/smbus-mitm-arduino-thumb.webp)
to imagine what it would look like, pretend that it's a pi pico and that I've figured out a solution for the 5V regulator that I now need.
## liability disclaimer
**if you use BattMITM, you are doing so at your own risk.** while battery protection technology tends to be pretty safe these days, I'm not responsible for any adverse side-effects of using BattMITM.
Additionally, BattMITM allows you to instruct your equipment to exceed safe operating limits if used improperly. it is your responsibility to understand and identify these limits to safely operate your equipment.
please refer to the MIT license text for more information on this matter.
## project status
hello world
## what does it do exactly and how
### what it does
the basic job of BattMITM is to intercept SMBus commands between the laptop and the BMS. when put in this position, it can do a few useful things.
specifically:
- act as a pass-through to forward SMBus commands between the laptop and BMS and return their responses.
- intercept specified SMBus commands to return a custom response instead of forwarding them.
- allow sending SMBus commands to the BMS via a USB UART connection and getting the response back, without involving the laptop.
- query the BMS over SMBus independently to display relevant battery health metrics on an attached display so they can be viewed.
### diagram
the most frequently asked question I get about this project is about where the microcontroller sits and a clarification on what it does. I think a diagram could help explain this better:
#### glossary
- battery pack: a group of battery cells wired in a combination of parallel and series configurations
- BMS: "Battery Management System" - protects and tends to the health of your battery pack. it is supposed to know how to maintain safe and smooth operation for the specific construction and chemistry of your battery pack.
- SMBus: "System Management Bus" - a protocol based on i2c which is commonly used throughout computer hardware for communication.
- balance: in the context of the connection shown below it refers to a group of wires, one for each parallel cell group plus a GND. it's used for individually addressing each cell group to monitor it and keep the pack "balanced".
#### normal setup
this is how your battery communicates with your computer normally (without BattMITM):
```
________________ _____ __________________
| | | | power | |
| | power | |=========| |
| battery pack |=========| BMS | SMBus | laptop |
| | balance | |=========| |
| |=========| | detect | |
|________________| |_____|=========|__________________|
\ \
\ \
\ \
\__________________\
```
#### BattMITM
this is how BattMITM fits in to this:
```
________________ ______ __________________
| | | | power | |
| | power | |=========| |
| battery pack |=========| BMS | | laptop |
| | balance | | | |
| |=========| | detect | |
|________________| |______|=========|__________________|
|||| \ \
____________________ |||| \ \
| | power |||| \ \
| |======// || \__________________\
| microcontroller | SMBus || ||
| (running BattMITM) |========// ||
| | SMBus ||
|____________________|============================//
```
instead of your laptop and BMS talking directly, they now have to go through the microcontroller, allowing it to monitor, modify, and inject communications. if you haven't already guessed, at this point it should be clear that the "MITM" in "BattMITM" stands for "man-in-the-middle".
## why
why not?
seriously though, usually the EC (embedded controller) in your laptop is the thing that interfaces with your BMS. it's up to your laptop manufacturer as to what gets exposed to the operating system, and up to the operating system what gets exposed to you. BattMITM allows you to view any battery health metrics exposed by your BMS, and do so even while it's running.
such metrics can include (but are not limited to):
- individual cell group voltages
- temperature
- cycle count
- instantaneous current/voltage
- maximum charge capacity
- available capacity
- design capacity
- charging current
- decimal precision battery percentage
additionally, BattMITM allows you to modify the information exposed to your laptop if you've re-celled your battery pack, letting you correct any information which has changed as opposed to when it was stock.
nothing would stop you from even trying to enter the bootrom of your BMS and reprogramming it through this (I'm not going to make any promises about success there though).
## is this safe?
to an extent.
here is my full honest answer:
the BMS is generally responsible for protecting the battery pack and ensuring it doesn't get damaged or pushed beyond its design. the BMS accomplishes this by advising the laptop in what to do in order to maintain safe operation. the BMS is also capable of limiting and cutting power to and from the battery pack to protect it if the laptop is unresponsive, though this is usually a last resort.
as BattMITM only intercepts communications between the laptop and the BMS, it in theory doesn't put the battery pack itself in too much danger. that being said, introducing new components to a system that was never designed for them always presents a risk that something could go wrong.
in an ideal world, the BMS *should* cut power to the laptop if it senses something wrong, and the laptop *should* terminate discharge if the BMS isn't behaving. both ends of this communication are *supposed to be* designed to appropriately handle a situation in which communications are degraded. in a case where the firmware on either the BMS or the laptop isn't properly designed, it could cause certain safety measures to not behave as intended if the communications are interrupted or modified.
if you use BattMITM, you are doing so at your own risk. it is not my responsibility to check if your equipment properly implements relevant safety features if something were to go wrong.
additionally, BattMITM allows you to instruct your equipment to exceed safe operating limits if used improperly. it is your responsibility to understand and identify these limits to safely operate your equipment.
please refer to the MIT license text for more information on this matter.
+13
View File
@@ -0,0 +1,13 @@
#include <stdio.h>
#include "pico/stdlib.h"
int main()
{
stdio_init_all();
while (true) {
printf("Hello, world!\n");
sleep_ms(1000);
}
}
+121
View File
@@ -0,0 +1,121 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
# Copyright 2020 (c) 2020 Raspberry Pi (Trading) Ltd.
#
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
# following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
# disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
# disclaimer in the documentation and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_TAG} AND (NOT PICO_SDK_FETCH_FROM_GIT_TAG))
set(PICO_SDK_FETCH_FROM_GIT_TAG $ENV{PICO_SDK_FETCH_FROM_GIT_TAG})
message("Using PICO_SDK_FETCH_FROM_GIT_TAG from environment ('${PICO_SDK_FETCH_FROM_GIT_TAG}')")
endif ()
if (PICO_SDK_FETCH_FROM_GIT AND NOT PICO_SDK_FETCH_FROM_GIT_TAG)
set(PICO_SDK_FETCH_FROM_GIT_TAG "master")
message("Using master as default value for PICO_SDK_FETCH_FROM_GIT_TAG")
endif()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
set(PICO_SDK_FETCH_FROM_GIT_TAG "${PICO_SDK_FETCH_FROM_GIT_TAG}" CACHE FILEPATH "release tag for SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
)
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Populate(
pico_sdk
QUIET
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
GIT_SUBMODULES_RECURSE FALSE
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
)
else ()
FetchContent_Populate(
pico_sdk
QUIET
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG ${PICO_SDK_FETCH_FROM_GIT_TAG}
SOURCE_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-src
BINARY_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-build
SUBBUILD_DIR ${FETCHCONTENT_BASE_DIR}/pico_sdk-subbuild
)
endif ()
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})