Compare commits
2 commits
d54c904c1b
...
3126e777bf
Author | SHA1 | Date | |
---|---|---|---|
3126e777bf | |||
90b0c24d36 |
8 changed files with 227 additions and 1 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,3 +3,5 @@ secrets.yaml
|
||||||
.esphome/
|
.esphome/
|
||||||
dist/
|
dist/
|
||||||
__pycache__/
|
__pycache__/
|
||||||
|
build/
|
||||||
|
tmp.*
|
||||||
|
|
|
@ -39,7 +39,7 @@ update:
|
||||||
- platform: http_request
|
- platform: http_request
|
||||||
id: auto_update
|
id: auto_update
|
||||||
source: "https://juju.nz/michaelh/assets/esphome/${project_name}.json"
|
source: "https://juju.nz/michaelh/assets/esphome/${project_name}.json"
|
||||||
update_interval: 2min
|
update_interval: 4hours
|
||||||
|
|
||||||
interval:
|
interval:
|
||||||
- interval: 50s
|
- interval: 50s
|
||||||
|
|
6
interceptor/CMakeLists.txt
Normal file
6
interceptor/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
cmake_minimum_required(VERSION 3.13.1)
|
||||||
|
find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
|
||||||
|
|
||||||
|
project(app LANGUAGES CXX)
|
||||||
|
|
||||||
|
target_sources(app PRIVATE src/main.cc)
|
8
interceptor/README.md
Normal file
8
interceptor/README.md
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
# Interceptor
|
||||||
|
|
||||||
|
A passive digital signal sampler for the CH32V003. Tracks the levels of PC1 and PC2 and sends any
|
||||||
|
changes over serial to the host. These can be converted to a VCD format file and analyzed in
|
||||||
|
sigrock.
|
||||||
|
|
||||||
|
Designed for sniffing I2C traffic. PC1 and PC2 are 5 V tollerant and have pullups enabled. Tested at
|
||||||
|
up to 200 kHz.
|
48
interceptor/boards/wch_ch32v003evt.overlay
Normal file
48
interceptor/boards/wch_ch32v003evt.overlay
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
#include <zephyr/dt-bindings/pinctrl/ch32v003-pinctrl.h>
|
||||||
|
|
||||||
|
/ {
|
||||||
|
chosen {
|
||||||
|
zephyr,console = &usart1;
|
||||||
|
zephyr,shell-uart = &usart1;
|
||||||
|
};
|
||||||
|
|
||||||
|
leds {
|
||||||
|
compatible = "gpio-leds";
|
||||||
|
|
||||||
|
red_led: led0 {
|
||||||
|
gpios = <&gpioa 1 GPIO_ACTIVE_HIGH>;
|
||||||
|
};
|
||||||
|
|
||||||
|
scl_pin: scl_pin {
|
||||||
|
gpios = <&gpioc 2 GPIO_PULL_UP>;
|
||||||
|
};
|
||||||
|
|
||||||
|
sda_pin: sda_pin {
|
||||||
|
gpios = <&gpioc 1 GPIO_PULL_UP>;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
aliases {
|
||||||
|
led0 = &red_led;
|
||||||
|
scl = &scl_pin;
|
||||||
|
sda = &sda_pin;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
&pinctrl {
|
||||||
|
};
|
||||||
|
|
||||||
|
&gpioa {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&gpioc {
|
||||||
|
status = "okay";
|
||||||
|
};
|
||||||
|
|
||||||
|
&usart1 {
|
||||||
|
status = "okay";
|
||||||
|
current-speed = <460800>;
|
||||||
|
pinctrl-0 = <&usart1_default>;
|
||||||
|
pinctrl-names = "default";
|
||||||
|
};
|
25
interceptor/prj.conf
Normal file
25
interceptor/prj.conf
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Trim back the memory usage.
|
||||||
|
CONFIG_THREAD_STACK_INFO=n
|
||||||
|
CONFIG_ERRNO=n
|
||||||
|
CONFIG_CURRENT_THREAD_USE_TLS=n
|
||||||
|
CONFIG_TIMESLICING=n
|
||||||
|
CONFIG_KERNEL_MEM_POOL=n
|
||||||
|
CONFIG_COMMON_LIBC_MALLOC=n
|
||||||
|
CONFIG_MINIMAL_LIBC=y
|
||||||
|
CONFIG_CBPRINTF_NANO=y
|
||||||
|
CONFIG_CBPRINTF_REDUCED_INTEGRAL=y
|
||||||
|
CONFIG_CBPRINTF_N_SPECIFIER=n
|
||||||
|
|
||||||
|
CONFIG_WCH_CH32V00X_HSI=y
|
||||||
|
CONFIG_WCH_CH32V00X_HSE=n
|
||||||
|
CONFIG_WCH_CH32V00X_HSI_AS_PLLSRC=y
|
||||||
|
|
||||||
|
CONFIG_GPIO=y
|
||||||
|
CONFIG_SERIAL=y
|
||||||
|
CONFIG_CONSOLE=y
|
||||||
|
CONFIG_UART_CONSOLE=y
|
||||||
|
|
||||||
|
CONFIG_CPP=y
|
||||||
|
CONFIG_STD_CPP2B=y
|
||||||
|
|
||||||
|
CONFIG_MAIN_STACK_SIZE=1024
|
88
interceptor/src/main.cc
Normal file
88
interceptor/src/main.cc
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024 Google LLC.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <zephyr/drivers/gpio.h>
|
||||||
|
#include <zephyr/kernel.h>
|
||||||
|
|
||||||
|
#include <ch32_gpio.h>
|
||||||
|
#include <ch32_uart.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
constexpr struct gpio_dt_spec kLed = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
|
||||||
|
constexpr struct gpio_dt_spec kScl = GPIO_DT_SPEC_GET(DT_ALIAS(scl), gpios);
|
||||||
|
constexpr struct gpio_dt_spec kSda = GPIO_DT_SPEC_GET(DT_ALIAS(sda), gpios);
|
||||||
|
|
||||||
|
void sniff()
|
||||||
|
{
|
||||||
|
GPIO_TypeDef *port = GPIOC;
|
||||||
|
USART_TypeDef *uart = USART1;
|
||||||
|
uint8_t fifo[256];
|
||||||
|
int head = 0;
|
||||||
|
int tail = 0;
|
||||||
|
|
||||||
|
// Note that using `int` reduces the code size by removing unneeded truncation.
|
||||||
|
int samples = 0;
|
||||||
|
int sample_count = 0;
|
||||||
|
int last_sample = 0;
|
||||||
|
int unchanged_for = 0;
|
||||||
|
|
||||||
|
csr_clear(mstatus, MSTATUS_IEN);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
static_assert(kScl.port == kSda.port);
|
||||||
|
static_assert(kScl.pin == kSda.pin + 1);
|
||||||
|
int sample = (port->INDR >> kSda.pin) & 3;
|
||||||
|
|
||||||
|
// Record when the value changes, or the value has been unchanged for some time.
|
||||||
|
if (sample != last_sample || ++unchanged_for >= 1024) {
|
||||||
|
samples <<= 2;
|
||||||
|
samples |= sample;
|
||||||
|
last_sample = sample;
|
||||||
|
unchanged_for = 0;
|
||||||
|
|
||||||
|
if (++sample_count >= 3) {
|
||||||
|
// Encode the three samples into valid ASCII.
|
||||||
|
fifo[head++] = samples + ' ';
|
||||||
|
head %= sizeof(fifo);
|
||||||
|
samples = 0;
|
||||||
|
sample_count = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tail != head && (uart->STATR & USART_STATR_TXE) != 0) {
|
||||||
|
uart->DATAR = fifo[tail++];
|
||||||
|
tail %= sizeof(fifo);
|
||||||
|
|
||||||
|
if (tail == 0 && (uart->STATR & USART_STATR_RXNE) != 0 &&
|
||||||
|
uart->DATAR == '~') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
csr_set(mstatus, MSTATUS_IEN);
|
||||||
|
}
|
||||||
|
|
||||||
|
void interceptor()
|
||||||
|
{
|
||||||
|
gpio_pin_configure_dt(&kLed, GPIO_OUTPUT_ACTIVE);
|
||||||
|
gpio_pin_configure_dt(&kScl, GPIO_INPUT);
|
||||||
|
gpio_pin_configure_dt(&kSda, GPIO_INPUT);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
printk("sniff\n");
|
||||||
|
sniff();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
interceptor();
|
||||||
|
return 0;
|
||||||
|
}
|
49
interceptor/tovcd.py
Normal file
49
interceptor/tovcd.py
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
"""Converts the samples from the board to a VCD file for sigrok.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python3 tovcd.py < /dev/ttyUSB0 | tee log.vcd
|
||||||
|
"""
|
||||||
|
|
||||||
|
import datetime
|
||||||
|
import sys
|
||||||
|
|
||||||
|
_HEADER = """
|
||||||
|
$date {date} $end
|
||||||
|
$version juju.nz tovcd.py $end
|
||||||
|
$timescale 1 us $end
|
||||||
|
$scope module libsigrok $end
|
||||||
|
"""
|
||||||
|
|
||||||
|
_MID = """
|
||||||
|
$upscope $end
|
||||||
|
$enddefinitions $end
|
||||||
|
"""
|
||||||
|
|
||||||
|
_IDS = "!#$%&'()"
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print(_HEADER.strip().format(date=datetime.datetime.now()))
|
||||||
|
|
||||||
|
for wire in range(2):
|
||||||
|
print(f"$var wire 1 {_IDS[wire]} D{wire} $end")
|
||||||
|
|
||||||
|
print(_MID.strip())
|
||||||
|
|
||||||
|
now = 0
|
||||||
|
last_d = None
|
||||||
|
|
||||||
|
for ch in sys.stdin.read():
|
||||||
|
ch = ord(ch) - 32
|
||||||
|
for i in range(3):
|
||||||
|
now += 1
|
||||||
|
d = (ch >> 5) & 1, (ch >> 4) & 1
|
||||||
|
ch <<= 2
|
||||||
|
if d != last_d:
|
||||||
|
parts = (f"{x}{_IDS[i]}" for i, x in enumerate(d))
|
||||||
|
print(f"#{now}", " ".join(parts))
|
||||||
|
last_d = d
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in a new issue