Skip to content

Commit e28c07e

Browse files
committed
move base pack here
0 parents  commit e28c07e

30 files changed

+1627
-0
lines changed

LICENSE

+674
Large diffs are not rendered by default.

README.md

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# flipperzero-i2ctools
2+
3+
[Original link](https://github.com/NaejEL/flipperzero-i2ctools)
4+
Set of i2c tools for Flipper Zero
5+
6+
![Preview](i2ctools.gif)
7+
8+
## Wiring
9+
10+
C0 -> SCL
11+
12+
C1 -> SDA
13+
14+
GND -> GND
15+
16+
>/!\ Target must use 3v3 logic levels. If you not sure use an i2c isolator like ISO1541
17+
18+
## Tools
19+
20+
### Scanner
21+
22+
Look for i2c peripherals adresses
23+
24+
### Sniffer
25+
26+
Spy i2c traffic
27+
28+
### Sender
29+
30+
Send command to i2c peripherals and read result
31+
32+
## TODO
33+
34+
- [ ] Read more than 2 bytes in sender mode
35+
- [ ] Add 10-bits adresses support
36+
- [ ] Test with rate > 100khz
37+
- [ ] Save records
38+
- [ ] Play from files
39+
- [ ] Kicad module
40+
- [ ] Improve UI
41+
- [ ] Refactor Event Management Code
42+
- [ ] Add Documentation
43+
- [ ] Remove max data size
44+
- [ ] Remove max frames read size

application.fam

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
App(
2+
appid="i2ctools",
3+
name="[GPIO] i2c Tools",
4+
apptype=FlipperAppType.EXTERNAL,
5+
entry_point="i2ctools_app",
6+
requires=["gui"],
7+
stack_size=2 * 1024,
8+
order=175,
9+
fap_icon="i2ctools.png",
10+
fap_category="GPIO",
11+
fap_icon_assets="images",
12+
fap_author="@NaejEL",
13+
fap_version="1.1",
14+
fap_description="Set of i2c tools",
15+
)

i2cscanner.c

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#include "i2cscanner.h"
2+
3+
void scan_i2c_bus(i2cScanner* i2c_scanner) {
4+
i2c_scanner->nb_found = 0;
5+
i2c_scanner->scanned = true;
6+
// Get the bus
7+
furi_hal_i2c_acquire(I2C_BUS);
8+
// scan
9+
for(uint8_t addr = 0x01; addr <= MAX_I2C_ADDR << 1; addr++) {
10+
// Check for peripherals
11+
if(furi_hal_i2c_is_device_ready(I2C_BUS, addr, I2C_TIMEOUT)) {
12+
// skip even 8-bit addr
13+
if(addr % 2 != 0) {
14+
continue;
15+
}
16+
// convert addr to 7-bits
17+
i2c_scanner->addresses[i2c_scanner->nb_found] = addr >> 1;
18+
i2c_scanner->nb_found++;
19+
}
20+
}
21+
furi_hal_i2c_release(I2C_BUS);
22+
}
23+
24+
i2cScanner* i2c_scanner_alloc() {
25+
i2cScanner* i2c_scanner = malloc(sizeof(i2cScanner));
26+
i2c_scanner->nb_found = 0;
27+
i2c_scanner->menu_index = 0;
28+
i2c_scanner->scanned = false;
29+
return i2c_scanner;
30+
}
31+
32+
void i2c_scanner_free(i2cScanner* i2c_scanner) {
33+
furi_assert(i2c_scanner);
34+
free(i2c_scanner);
35+
}

i2cscanner.h

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
#include <furi_hal.h>
5+
6+
// I2C BUS
7+
#define I2C_BUS &furi_hal_i2c_handle_external
8+
#define I2C_TIMEOUT 3
9+
10+
// 7 bits addresses
11+
#define MAX_I2C_ADDR 0x7F
12+
13+
typedef struct {
14+
uint8_t addresses[MAX_I2C_ADDR + 1];
15+
uint8_t nb_found;
16+
uint8_t menu_index;
17+
bool scanned;
18+
} i2cScanner;
19+
20+
void scan_i2c_bus(i2cScanner* i2c_scanner);
21+
22+
i2cScanner* i2c_scanner_alloc();
23+
void i2c_scanner_free(i2cScanner* i2c_scanner);

i2csender.c

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#include "i2csender.h"
2+
3+
void i2c_send(i2cSender* i2c_sender) {
4+
furi_hal_i2c_acquire(I2C_BUS);
5+
uint8_t adress = i2c_sender->scanner->addresses[i2c_sender->address_idx] << 1;
6+
i2c_sender->error = furi_hal_i2c_trx(
7+
I2C_BUS,
8+
adress,
9+
&i2c_sender->value,
10+
sizeof(i2c_sender->value),
11+
i2c_sender->recv,
12+
sizeof(i2c_sender->recv),
13+
I2C_TIMEOUT);
14+
furi_hal_i2c_release(I2C_BUS);
15+
i2c_sender->must_send = false;
16+
i2c_sender->sended = true;
17+
}
18+
19+
i2cSender* i2c_sender_alloc() {
20+
i2cSender* i2c_sender = malloc(sizeof(i2cSender));
21+
i2c_sender->must_send = false;
22+
i2c_sender->sended = false;
23+
return i2c_sender;
24+
}
25+
26+
void i2c_sender_free(i2cSender* i2c_sender) {
27+
furi_assert(i2c_sender);
28+
free(i2c_sender);
29+
}

i2csender.h

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
#include <furi_hal.h>
5+
#include "i2cscanner.h"
6+
7+
typedef struct {
8+
uint8_t address_idx;
9+
uint8_t value;
10+
uint8_t recv[2];
11+
bool must_send;
12+
bool sended;
13+
bool error;
14+
15+
i2cScanner* scanner;
16+
} i2cSender;
17+
18+
void i2c_send();
19+
20+
i2cSender* i2c_sender_alloc();
21+
void i2c_sender_free(i2cSender* i2c_sender);

i2csniffer.c

+101
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
#include "i2csniffer.h"
2+
3+
void clear_sniffer_buffers(i2cSniffer* i2c_sniffer) {
4+
furi_assert(i2c_sniffer);
5+
for(uint8_t i = 0; i < MAX_RECORDS; i++) {
6+
for(uint8_t j = 0; j < MAX_MESSAGE_SIZE; j++) {
7+
i2c_sniffer->frames[i].ack[j] = false;
8+
i2c_sniffer->frames[i].data[j] = 0;
9+
}
10+
i2c_sniffer->frames[i].bit_index = 0;
11+
i2c_sniffer->frames[i].data_index = 0;
12+
}
13+
i2c_sniffer->frame_index = 0;
14+
i2c_sniffer->state = I2C_BUS_FREE;
15+
i2c_sniffer->first = true;
16+
}
17+
18+
void start_interrupts(i2cSniffer* i2c_sniffer) {
19+
furi_assert(i2c_sniffer);
20+
furi_hal_gpio_init(pinSCL, GpioModeInterruptRise, GpioPullNo, GpioSpeedHigh);
21+
furi_hal_gpio_add_int_callback(pinSCL, SCLcallback, i2c_sniffer);
22+
23+
// Add Rise and Fall Interrupt on SDA pin
24+
furi_hal_gpio_init(pinSDA, GpioModeInterruptRiseFall, GpioPullNo, GpioSpeedHigh);
25+
furi_hal_gpio_add_int_callback(pinSDA, SDAcallback, i2c_sniffer);
26+
}
27+
28+
void stop_interrupts() {
29+
furi_hal_gpio_remove_int_callback(pinSCL);
30+
furi_hal_gpio_remove_int_callback(pinSDA);
31+
// Reset GPIO pins to default state
32+
furi_hal_gpio_init(pinSCL, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
33+
furi_hal_gpio_init(pinSDA, GpioModeAnalog, GpioPullNo, GpioSpeedLow);
34+
}
35+
36+
// Called on Fallin/Rising SDA
37+
// Used to monitor i2c bus state
38+
void SDAcallback(void* _i2c_sniffer) {
39+
i2cSniffer* i2c_sniffer = _i2c_sniffer;
40+
// SCL is low maybe cclock strecching
41+
if(furi_hal_gpio_read(pinSCL) == false) {
42+
return;
43+
}
44+
// Check for stop condition: SDA rising while SCL is High
45+
if(i2c_sniffer->state == I2C_BUS_STARTED) {
46+
if(furi_hal_gpio_read(pinSDA) == true) {
47+
i2c_sniffer->state = I2C_BUS_FREE;
48+
}
49+
}
50+
// Check for start condition: SDA falling while SCL is high
51+
else if(furi_hal_gpio_read(pinSDA) == false) {
52+
i2c_sniffer->state = I2C_BUS_STARTED;
53+
if(i2c_sniffer->first) {
54+
i2c_sniffer->first = false;
55+
return;
56+
}
57+
i2c_sniffer->frame_index++;
58+
if(i2c_sniffer->frame_index >= MAX_RECORDS) {
59+
clear_sniffer_buffers(i2c_sniffer);
60+
}
61+
}
62+
return;
63+
}
64+
65+
// Called on Rising SCL
66+
// Used to read bus datas
67+
void SCLcallback(void* _i2c_sniffer) {
68+
i2cSniffer* i2c_sniffer = _i2c_sniffer;
69+
if(i2c_sniffer->state == I2C_BUS_FREE) {
70+
return;
71+
}
72+
uint8_t frame = i2c_sniffer->frame_index;
73+
uint8_t bit = i2c_sniffer->frames[frame].bit_index;
74+
uint8_t data_idx = i2c_sniffer->frames[frame].data_index;
75+
if(bit < 8) {
76+
i2c_sniffer->frames[frame].data[data_idx] <<= 1;
77+
i2c_sniffer->frames[frame].data[data_idx] |= (int)furi_hal_gpio_read(pinSDA);
78+
i2c_sniffer->frames[frame].bit_index++;
79+
} else {
80+
i2c_sniffer->frames[frame].ack[data_idx] = !furi_hal_gpio_read(pinSDA);
81+
i2c_sniffer->frames[frame].data_index++;
82+
i2c_sniffer->frames[frame].bit_index = 0;
83+
}
84+
}
85+
86+
i2cSniffer* i2c_sniffer_alloc() {
87+
i2cSniffer* i2c_sniffer = malloc(sizeof(i2cSniffer));
88+
i2c_sniffer->started = false;
89+
i2c_sniffer->row_index = 0;
90+
i2c_sniffer->menu_index = 0;
91+
clear_sniffer_buffers(i2c_sniffer);
92+
return i2c_sniffer;
93+
}
94+
95+
void i2c_sniffer_free(i2cSniffer* i2c_sniffer) {
96+
furi_assert(i2c_sniffer);
97+
if(i2c_sniffer->started) {
98+
stop_interrupts();
99+
}
100+
free(i2c_sniffer);
101+
}

i2csniffer.h

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#pragma once
2+
3+
#include <furi.h>
4+
#include <furi_hal.h>
5+
6+
// I2C Pins
7+
#define pinSCL &gpio_ext_pc0
8+
#define pinSDA &gpio_ext_pc1
9+
10+
// Bus States
11+
typedef enum { I2C_BUS_FREE, I2C_BUS_STARTED } i2cBusStates;
12+
13+
// Max read size of i2c frame by message
14+
// Arbitraly defined
15+
// They're not real limit to maximum frames send
16+
#define MAX_MESSAGE_SIZE 128
17+
18+
// Nb of records
19+
#define MAX_RECORDS 128
20+
21+
/// @brief Struct used to store our reads
22+
typedef struct {
23+
uint8_t data[MAX_MESSAGE_SIZE];
24+
bool ack[MAX_MESSAGE_SIZE];
25+
uint8_t bit_index;
26+
uint8_t data_index;
27+
} i2cFrame;
28+
29+
typedef struct {
30+
bool started;
31+
bool first;
32+
i2cBusStates state;
33+
i2cFrame frames[MAX_RECORDS];
34+
uint8_t frame_index;
35+
uint8_t menu_index;
36+
uint8_t row_index;
37+
} i2cSniffer;
38+
39+
void clear_sniffer_buffers(i2cSniffer* i2c_sniffer);
40+
void start_interrupts(i2cSniffer* i2c_sniffer);
41+
void stop_interrupts();
42+
void SDAcallback(void* _i2c_sniffer);
43+
void SCLcallback(void* _i2c_sniffer);
44+
45+
i2cSniffer* i2c_sniffer_alloc();
46+
void i2c_sniffer_free(i2cSniffer* i2c_sniffer);

0 commit comments

Comments
 (0)