Skip to content

Commit 6522797

Browse files
authored
Merge pull request #3 from TylerWilley/pcb
Pcb
2 parents fa1dffb + 44549d5 commit 6522797

18 files changed

+448
-119
lines changed

README.md

+49-13
Original file line numberDiff line numberDiff line change
@@ -5,24 +5,56 @@
55

66
A Flipper Zero app that allows the flipper to communicate with Digimon V-Pets.
77

8-
Currently tested:
9-
- DM20
10-
- DMX
11-
- PenZ
12-
- DMC
13-
- PenOG
14-
- PenProg
15-
- PenX
8+
Currently tested devices:
9+
Classic:
10+
- 1997 Digital Monster
11+
- 1998 Digimon Pendulum
12+
- 1999 Digivice
13+
- 2000 D-3
14+
- 2000 D-Terminal
15+
- 2002 D-Scanner
16+
- 2002 Digimon Pendulum Progress
17+
- 2003 Digimon Pendulum X
18+
- 2005 Digimon Accel
19+
- 2005 Digimon Mini
20+
- 2006 Digivice iC
21+
22+
Modern:
23+
- 2017 Digital Monster Ver.20th
24+
- 2018 Digimon Pendulum Ver.20th
25+
- 2019 Digital Monster X
26+
- 2020 Digimon Pendulum Z
27+
- 2021 Digivice Ver.Complete
28+
29+
Color:
30+
- 2023 Digital Monster COLOR
31+
32+
Currently tested apps:
33+
- W0rld (via Chrome web browser serial)
34+
- Alpha Terminal and Alpha Serial (Android)
35+
- Alpha Terminal (Windows)
36+
- ACom Wiki (Android)
37+
38+
Unsupported Apps:
39+
- Alpha Serial (Windows) still doesn't seem to detect it
1640

1741
Untested:
18-
- All other pets (Pen20, Original Pets, etc)
42+
- PenC
43+
- All other pets
1944
- Listen Mode
2045

46+
Thanks to [Joushiikuta](https://www.youtube.com/@joushiikuta) for testing the classic devices which I do not have.
47+
2148
Based on:
2249
- The DMComm project by BladeSabre: https://github.com/dmcomm/dmcomm-project
50+
- The updated DMComm Arduino library by BladeSabre: https://github.com/dmcomm/dmcomm-arduino-lib
2351
- The Flipper Zero Boilerplate App: https://github.com/leedave/flipper-zero-fap-boilerplate
2452
- The Flipper Zero Firmware: https://github.com/flipperdevices/flipperzero-firmware
2553

54+
### Known Issues
55+
56+
Occasionally when using the USB A-Com mode, the flipper zero USB driver will crash the flipper due to the way I'm overwriting the USB VID/PID. I'm not sure why yet and am still debugging this. Subsequent attempts seem to work and this is uncommon (although not rare).
57+
2658
### Youtube Example
2759

2860
[![Video showing app in action](https://img.youtube.com/vi/pggRzHnXlF4/0.jpg)](https://www.youtube.com/watch?v=pggRzHnXlF4)
@@ -33,12 +65,18 @@ You will need to construct a circuit similar to the A-Com circuit described in t
3365

3466
![Schematic](screenshots/flipper_vpet_circuit.png)
3567

36-
Pin C3 - 2k resistor - Pin B2 - 10k resistor - Pin GND
68+
Pin C3 - 4k resistor - Pin B2 - 20k resistor - Pin GND
3769

3870
Pin B2 - VPet+
3971

4072
Pin GND - VPet-
4173

74+
The 4k/20k resistor pairing is confirmed to work with the older devices. If you only need modern device support 2k/10k is also compatible, though it will not work with older devices.
75+
76+
[Joushiikuta](https://www.youtube.com/@joushiikuta) has created an awesome gerber file for a compatible PCB located [here](pcb/20240225_FlipperZero_F-Com_PCB_Thickness_1.6mm_Gerber.zip) (included with permission)
77+
78+
You will also need compatible right angle header pins and SMD resistors.
79+
4280
## Installation
4381

4482
The F-Com app is compiled and installed with [ufbt](https://github.com/flipperdevices/flipperzero-ufbt)
@@ -54,7 +92,7 @@ flipper to make them accessible under the "Saved" menu option.
5492

5593
### Listen
5694

57-
Listen is currently untested, as I have not created a jig to make it function!!
95+
Listen mode is now partially functional. It is difficult to get a good read at the moment although it is possible. I need to re-work the code to use rising/falling edge detection instead of looping though so the flipper GUI does not hang, and we don't have to spend the whole time looping on a GPIO read.
5896

5997
Listen allows you to connect 2 vpets to each other and eavesdrop on the data they send. Both codes will show up on the flipper after communication completes, and you can save either code to the flipper for later use. Leaving this screen will pause dmcomm.
6098

@@ -76,6 +114,4 @@ The flipper will change the USB port from CLI mode into Serial mode and behave a
76114

77115
Dmcomm supports a voltage test. However, the flipper zero firmware does not yet have ADC support implemented. This is still possible as demonstrated by the flipper zero oscilloscope project. At some point I may implement this. A-Com's themselves use analog input in order to support a wider range of devices logic levels. This may limit the flipper app's compatibility for now.
78116

79-
DMC support isn't included in the dmcomm-project ino, but has been added to the updated https://github.com/dmcomm/dmcomm-arduino-lib project. At some point I may update this to port the CPP code onto the flipper.
80-
81117
Debug mode support could be added at some point.

application.fam

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ App(
88
stack_size=3 * 1024,
99
fap_category="GPIO",
1010
# Optional values
11-
# fap_version="0.1",
11+
fap_version="1.1",
1212
fap_icon="template.png", # 10x10 1-bit PNG
1313
# fap_description="A simple app",
1414
# fap_author="J. Doe",

dmcomm-lib/Print.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ void Stream::set_callback(DmcommCallback callback)
1111

1212
size_t Stream::write(uint8_t i)
1313
{
14+
if(cb == NULL) return 0;
1415
char str[10];
1516
snprintf(str, 10, "%c", (char)i);
1617
size_t sent = furi_stream_buffer_send(
@@ -23,6 +24,7 @@ size_t Stream::write(uint8_t i)
2324

2425
size_t Stream::write(const char *buffer, size_t size)
2526
{
27+
if(cb == NULL) return 0;
2628
char str[10];
2729
size_t sent = 0;
2830
for(size_t i = 0; i < size; i++)
@@ -39,6 +41,7 @@ size_t Stream::write(const char *buffer, size_t size)
3941

4042
size_t Stream::print(const char buffer[])
4143
{
44+
if(cb == NULL) return 0;
4245
return furi_stream_buffer_send(
4346
app->dmcomm_output_stream,
4447
buffer,
@@ -48,6 +51,7 @@ size_t Stream::print(const char buffer[])
4851

4952
size_t Stream::print(int i, int fmt)
5053
{
54+
if(cb == NULL) return 0;
5155
UNUSED(fmt);
5256
char str[10];
5357
snprintf(str, 10, "%d", i);
@@ -62,6 +66,7 @@ size_t Stream::print(int i, int fmt)
6266

6367
size_t Stream::println(void)
6468
{
69+
if(cb == NULL) return 0;
6570
size_t sent = furi_stream_buffer_send(
6671
app->dmcomm_output_stream,
6772
"\n",
@@ -74,6 +79,7 @@ size_t Stream::println(void)
7479

7580
size_t Stream::println(const char buffer[])
7681
{
82+
if(cb == NULL) return 0;
7783
size_t sent = furi_stream_buffer_send(
7884
app->dmcomm_output_stream,
7985
buffer,
@@ -91,6 +97,7 @@ size_t Stream::println(const char buffer[])
9197

9298
size_t Stream::println(int i, int fmt)
9399
{
100+
if(cb == NULL) return 0;
94101
UNUSED(fmt);
95102
char str[10];
96103
snprintf(str, 10, "%d\n", i);

dmcomm-lib/Print.h

+7
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
/*
2+
implementation of the Print/Stream classes
3+
4+
but the underlying I/O is to two flipper stream buffers
5+
instead of an arduino serial interface.
6+
7+
*/
18
#include "arduino.h"
29

310
#define DEC 10

dmcomm-lib/dmcomm_pin_control.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ class BaseProngInput {
4949
void setActiveLevel(uint8_t level);
5050
uint32_t waitForActive(uint32_t timeout);
5151
uint32_t waitForIdle(uint32_t timeout);
52-
uint32_t waitFor(bool active, uint32_t timeout);
52+
virtual uint32_t waitFor(bool active, uint32_t timeout);
5353
ReceiveOutcome waitFrom(bool active, uint32_t dur_min, uint32_t dur_max, int16_t current_bit);
5454
protected:
5555
uint8_t idle_level_;

dmcomm-lib/dmcomm_serial.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,21 @@ uint8_t SerialFollower::serialRead() {
8787
int16_t incoming_int;
8888
uint8_t incoming_byte;
8989
uint8_t i = 0;
90+
bool first = true;
9091
if (serial_.available() == 0) {
9192
return 0;
9293
}
9394
time_start = millis();
9495
do {
9596
do {
9697
incoming_int = serial_.read();
98+
// if we have nothing to read, and this is the first character
99+
// then exit immediately, this makes our loop really tight while we are active
100+
if(first && incoming_int == -1)
101+
{
102+
return 0;
103+
}
104+
first = false;
97105
time = millis() - time_start;
98106
if (time > DMCOMM_SERIAL_TIMEOUT_MILLIS) {
99107
serial_.println(F("[No EOL received]"));

dmcomm-lib/fcom.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ static FComState fcom_state;
2828

2929
void set_serial_callback(DmcommCallback cb)
3030
{
31-
FURI_LOG_I(TAG, "set_serial_callback %p", cb);
31+
//FURI_LOG_I(TAG, "set_serial_callback %p", cb);
3232
fcom_state.stream->set_callback(cb);
3333
}
3434

dmcomm-lib/flipper_pin_control.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include "flipper_pin_control.h"
2+
#include "DMComm.h"
23

34
namespace DMComm {
45

@@ -52,4 +53,59 @@ bool FComInput::isActive() {
5253
return level == active_level_;
5354
}
5455

56+
/*
57+
NOTE: We override this because if we loop without delays on the
58+
flipper, we starve the process scheduler thread... which means
59+
the UI locks up. This isn't an issue for _most_ operations because
60+
they are all 13ms or less. But in listen mode or go-second mode
61+
we are waiting for _FIVE SECONDS_ which is really annoying for the
62+
user being unable to back out of the app during that time.
63+
64+
SO. If the delay is really big, we're going to add a 1ms delay
65+
every loop to allow the UI to process events and stuff so the
66+
user isn't left in the dust.
67+
68+
For tight timeouts though, we will keep the original code.
69+
70+
Technically, this should be done using rising/falling edge
71+
interrupts... However, that's pretty complicated to implement
72+
because we need to determine which state is active, what current
73+
state we are in, call into C code and manage waiting on a lock.
74+
And even then lock timeouts aren't microsecond accurate, so it
75+
still wouldn't be something we could use for everything...
76+
77+
This is "good enough".
78+
*/
79+
uint32_t FComInput::waitFor(bool active, uint32_t timeout) {
80+
if(timeout < 250000)
81+
{
82+
uint32_t start_time = micros();
83+
uint32_t duration;
84+
while (true) {
85+
duration = micros() - start_time;
86+
if (duration > timeout) {
87+
return DMCOMM_SIGNAL_TIMED_OUT;
88+
}
89+
if (active == isActive()) {
90+
return duration;
91+
}
92+
}
93+
}
94+
else
95+
{
96+
uint32_t start_time = micros();
97+
uint32_t duration;
98+
while (true) {
99+
duration = micros() - start_time;
100+
if (duration > timeout) {
101+
return DMCOMM_SIGNAL_TIMED_OUT;
102+
}
103+
if (active == isActive()) {
104+
return duration;
105+
}
106+
delay(1);
107+
}
108+
}
109+
}
110+
55111
}

dmcomm-lib/flipper_pin_control.h

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class FComInput : public BaseProngInput {
2626
bool isActive();
2727
void setThreshold(uint16_t threshold_mV);
2828
uint16_t voltage();
29+
uint32_t waitFor(bool active, uint32_t timeout);
2930
private:
3031
const GpioPin* pin_in_;
3132
};

dmcomm_link.c

+2-14
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,7 @@
55
* dmcomm thread, runs the dmcomm loop. call init first.
66
* exits when the app dmcomm_run var is set to false.
77
* App runs this constantly on startup until app close.
8-
*
9-
int32_t dmcomm_reader(void* context) {
10-
FURI_LOG_I(TAG, "dmcomm_reader start");
11-
App* app = context;
12-
setup();
13-
while(app->dmcomm_run) {
14-
loop();
15-
}
16-
17-
FURI_LOG_I(TAG, "dmcomm_reader end");
18-
return 0;
19-
}*/
20-
8+
*/
219
int32_t fcom_thread(void* context) {
2210
FURI_LOG_I(TAG, "fcom_thread start");
2311
App* app = context;
@@ -37,7 +25,7 @@ Used for comms by app (non USB)
3725
*/
3826
void dmcomm_sendcommand(void* context, const char* cmd)
3927
{
40-
FURI_LOG_I(TAG, "dmcomm_sendcommand");
28+
FURI_LOG_I(TAG, "dmcomm_sendcommand: %s", cmd);
4129
App* app = context;
4230

4331
size_t sent = furi_stream_buffer_send(
Binary file not shown.

scene_listen_menu.c

+8
Original file line numberDiff line numberDiff line change
@@ -59,21 +59,29 @@ bool fcom_listen_menu_scene_on_event(void* context, SceneManagerEvent event) {
5959
switch(event.event) {
6060
case ListenMenuSceneSelectionEvent2Prong:
6161
strncpy(app->state->current_code, "V0\n", MAX_DIGIROM_LEN);
62+
furi_string_reset(app->state->r_code);
63+
furi_string_reset(app->state->s_code);
6264
scene_manager_next_scene(app->scene_manager, FcomReadCodeScene);
6365
consumed = true;
6466
break;
6567
case ListenMenuSceneSelectionEvent3Prong:
6668
strncpy(app->state->current_code, "X0\n", MAX_DIGIROM_LEN);
69+
furi_string_reset(app->state->r_code);
70+
furi_string_reset(app->state->s_code);
6771
scene_manager_next_scene(app->scene_manager, FcomReadCodeScene);
6872
consumed = true;
6973
break;
7074
case ListenMenuSceneSelectionEventXrosMini:
7175
strncpy(app->state->current_code, "Y0\n", MAX_DIGIROM_LEN);
76+
furi_string_reset(app->state->r_code);
77+
furi_string_reset(app->state->s_code);
7278
scene_manager_next_scene(app->scene_manager, FcomReadCodeScene);
7379
consumed = true;
7480
break;
7581
case ListenMenuSceneSelectionEventColor:
7682
strncpy(app->state->current_code, "C0\n", MAX_DIGIROM_LEN);
83+
furi_string_reset(app->state->r_code);
84+
furi_string_reset(app->state->s_code);
7785
scene_manager_next_scene(app->scene_manager, FcomReadCodeScene);
7886
consumed = true;
7987
break;

scene_main_menu.c

+3
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Setup our scene widgets and create callback hooks
1818
*/
1919
void fcom_menu_callback(void* context, uint32_t index);
2020
void fcom_main_menu_scene_on_enter(void* context) {
21+
FURI_LOG_I(TAG, "fcom_main_menu_scene_on_enter");
2122
App* app = context;
2223
submenu_reset(app->submenu);
2324
submenu_add_item(app->submenu, "Listen", MainMenuSelectionListen, fcom_menu_callback, app);
@@ -52,6 +53,7 @@ void fcom_menu_callback(void* context, uint32_t index) {
5253

5354
/** main menu event handler - switches scene based on the event */
5455
bool fcom_main_menu_scene_on_event(void* context, SceneManagerEvent event) {
56+
FURI_LOG_I(TAG, "fcom_main_menu_scene_on_event");
5557
App* app = context;
5658
bool consumed = false;
5759
switch(event.type) {
@@ -83,6 +85,7 @@ bool fcom_main_menu_scene_on_event(void* context, SceneManagerEvent event) {
8385
}
8486

8587
void fcom_main_menu_scene_on_exit(void* context) {
88+
FURI_LOG_I(TAG, "fcom_main_menu_scene_on_exit");
8689
App* app = context;
8790
submenu_reset(app->submenu);
8891
}

0 commit comments

Comments
 (0)