Merge pull request #11299 from daleckystepan/vtx-start-bit
[betaflight.git] / src / main / cms / cms_menu_blackbox.c
blobc6d329f722db06f186ad85801b90b4a10b90253e
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
22 // CMS things for blackbox and flashfs.
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <ctype.h>
30 #include "platform.h"
32 #if defined(USE_CMS) && defined(USE_BLACKBOX)
34 #include "build/debug.h"
35 #include "build/version.h"
37 #include "blackbox/blackbox.h"
38 #include "blackbox/blackbox_io.h"
40 #include "cms/cms.h"
41 #include "cms/cms_types.h"
42 #include "cms/cms_menu_blackbox.h"
44 #include "common/printf.h"
45 #include "common/utils.h"
47 #include "config/feature.h"
49 #include "drivers/flash.h"
50 #include "drivers/time.h"
51 #include "drivers/sdcard.h"
53 #include "config/config.h"
55 #include "io/asyncfatfs/asyncfatfs.h"
56 #include "io/flashfs.h"
57 #include "io/beeper.h"
59 #include "pg/pg.h"
61 #include "flight/pid.h"
63 static const char * const cmsx_BlackboxDeviceNames[] = {
64 "NONE",
65 "FLASH",
66 "SDCARD",
67 "SERIAL"
70 static const char * const cmsx_BlackboxRateNames[] = {
71 "1/1",
72 "1/2",
73 "1/4",
74 "1/8",
75 "1/16"
78 static uint8_t cmsx_BlackboxDevice;
79 static OSD_TAB_t cmsx_BlackboxDeviceTable = { &cmsx_BlackboxDevice, 3, cmsx_BlackboxDeviceNames };
80 static uint8_t cmsx_BlackboxRate;
81 static OSD_TAB_t cmsx_BlackboxRateTable = { &cmsx_BlackboxRate, 4, cmsx_BlackboxRateNames };
82 static debugType_e systemConfig_debug_mode;
84 #define CMS_BLACKBOX_STRING_LENGTH 8
85 static char cmsx_BlackboxStatus[CMS_BLACKBOX_STRING_LENGTH];
86 static char cmsx_BlackboxDeviceStorageUsed[CMS_BLACKBOX_STRING_LENGTH];
87 static char cmsx_BlackboxDeviceStorageFree[CMS_BLACKBOX_STRING_LENGTH];
88 static char cmsx_pidFreq[CMS_BLACKBOX_STRING_LENGTH];
90 static void cmsx_Blackbox_GetDeviceStatus(void)
92 char * unit = "B";
93 #if defined(USE_SDCARD) || defined(USE_FLASHFS)
94 bool storageDeviceIsWorking = false;
95 #endif
96 uint32_t storageUsed = 0;
97 uint32_t storageFree = 0;
99 switch (blackboxConfig()->device)
101 #ifdef USE_SDCARD
102 case BLACKBOX_DEVICE_SDCARD:
103 unit = "MB";
105 if (!sdcard_isInserted()) {
106 tfp_sprintf(cmsx_BlackboxStatus, "NO CARD");
107 } else if (!sdcard_isFunctional()) {
108 tfp_sprintf(cmsx_BlackboxStatus, "FAULT");
109 } else {
110 switch (afatfs_getFilesystemState()) {
111 case AFATFS_FILESYSTEM_STATE_READY:
112 tfp_sprintf(cmsx_BlackboxStatus, "READY");
113 storageDeviceIsWorking = true;
114 break;
115 case AFATFS_FILESYSTEM_STATE_INITIALIZATION:
116 tfp_sprintf(cmsx_BlackboxStatus, "INIT");
117 break;
118 case AFATFS_FILESYSTEM_STATE_FATAL:
119 case AFATFS_FILESYSTEM_STATE_UNKNOWN:
120 default:
121 tfp_sprintf(cmsx_BlackboxStatus, "FAULT");
122 break;
126 if (storageDeviceIsWorking) {
127 storageFree = afatfs_getContiguousFreeSpace() / 1024000;
128 storageUsed = (sdcard_getMetadata()->numBlocks / 2000) - storageFree;
131 break;
132 #endif
134 #ifdef USE_FLASHFS
135 case BLACKBOX_DEVICE_FLASH:
136 unit = "KB";
138 storageDeviceIsWorking = flashfsIsSupported();
139 if (storageDeviceIsWorking) {
140 tfp_sprintf(cmsx_BlackboxStatus, "READY");
142 const flashPartition_t *flashPartition = flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS);
143 const flashGeometry_t *flashGeometry = flashGetGeometry();
145 storageUsed = flashfsGetOffset() / 1024;
146 storageFree = ((FLASH_PARTITION_SECTOR_COUNT(flashPartition) * flashGeometry->sectorSize) / 1024) - storageUsed;
147 } else {
148 tfp_sprintf(cmsx_BlackboxStatus, "FAULT");
151 break;
152 #endif
154 default:
155 tfp_sprintf(cmsx_BlackboxStatus, "---");
158 /* Storage counters */
159 tfp_sprintf(cmsx_BlackboxDeviceStorageUsed, "%ld%s", storageUsed, unit);
160 tfp_sprintf(cmsx_BlackboxDeviceStorageFree, "%ld%s", storageFree, unit);
163 #ifdef USE_FLASHFS
164 static const void *cmsx_EraseFlash(displayPort_t *pDisplay, const void *ptr)
166 UNUSED(ptr);
168 if (!flashfsIsSupported()) {
169 return NULL;
172 displayClearScreen(pDisplay);
173 displayWrite(pDisplay, 5, 3, DISPLAYPORT_ATTR_INFO, "ERASING FLASH...");
174 displayRedraw(pDisplay);
176 flashfsEraseCompletely();
177 while (!flashfsIsReady()) {
178 //TODO: Make this non-blocking!
179 delay(100);
182 beeper(BEEPER_BLACKBOX_ERASE);
183 displayClearScreen(pDisplay);
184 displayRedraw(pDisplay);
186 // Update storage device status to show new used space amount
187 cmsx_Blackbox_GetDeviceStatus();
189 return MENU_CHAIN_BACK;
191 #endif // USE_FLASHFS
193 static const void *cmsx_Blackbox_onEnter(displayPort_t *pDisp)
195 UNUSED(pDisp);
197 cmsx_Blackbox_GetDeviceStatus();
198 cmsx_BlackboxDevice = blackboxConfig()->device;
199 cmsx_BlackboxRate = blackboxConfig()->sample_rate;
200 systemConfig_debug_mode = systemConfig()->debug_mode;
202 const uint16_t pidFreq = (uint16_t)pidGetPidFrequency();
203 if (pidFreq > 1000) {
204 tfp_sprintf(cmsx_pidFreq, "%1d.%02dKHZ", (pidFreq / 10) / 100, (pidFreq / 10) % 100);
205 } else {
206 tfp_sprintf(cmsx_pidFreq, "%3dHZ", pidFreq);
208 return NULL;
211 static const void *cmsx_Blackbox_onExit(displayPort_t *pDisp, const OSD_Entry *self)
213 UNUSED(pDisp);
214 UNUSED(self);
216 if (blackboxMayEditConfig()) {
217 blackboxConfigMutable()->device = cmsx_BlackboxDevice;
218 blackboxValidateConfig();
220 blackboxConfigMutable()->sample_rate = cmsx_BlackboxRate;
221 systemConfigMutable()->debug_mode = systemConfig_debug_mode;
223 return NULL;
226 // Check before erase flash
227 #ifdef USE_FLASHFS
228 static const OSD_Entry menuEraseFlashCheckEntries[] = {
229 { "CONFIRM ERASE", OME_Label, NULL, NULL},
230 { "YES", OME_Funcall, cmsx_EraseFlash, NULL },
232 { "NO", OME_Back, NULL, NULL },
233 { NULL, OME_END, NULL, NULL }
236 static CMS_Menu cmsx_menuEraseFlashCheck = {
237 #ifdef CMS_MENU_DEBUG
238 .GUARD_text = "MENUERASEFLASH",
239 .GUARD_type = OME_MENU,
240 #endif
241 .onEnter = NULL,
242 .onExit = NULL,
243 .onDisplayUpdate = NULL,
244 .entries = menuEraseFlashCheckEntries
246 #endif
248 static const OSD_Entry cmsx_menuBlackboxEntries[] =
250 { "-- BLACKBOX --", OME_Label, NULL, NULL},
251 { "(PID FREQ)", OME_String, NULL, &cmsx_pidFreq },
252 { "SAMPLERATE", OME_TAB | REBOOT_REQUIRED, NULL, &cmsx_BlackboxRateTable },
253 { "DEVICE", OME_TAB | REBOOT_REQUIRED, NULL, &cmsx_BlackboxDeviceTable },
254 { "(STATUS)", OME_String, NULL, &cmsx_BlackboxStatus },
255 { "(USED)", OME_String, NULL, &cmsx_BlackboxDeviceStorageUsed },
256 { "(FREE)", OME_String, NULL, &cmsx_BlackboxDeviceStorageFree },
257 { "DEBUG MODE", OME_TAB | REBOOT_REQUIRED, NULL, &(OSD_TAB_t) { &systemConfig_debug_mode, DEBUG_COUNT - 1, debugModeNames } },
259 #ifdef USE_FLASHFS
260 { "ERASE FLASH", OME_Submenu, cmsMenuChange, &cmsx_menuEraseFlashCheck },
261 #endif // USE_FLASHFS
263 { "BACK", OME_Back, NULL, NULL },
264 { NULL, OME_END, NULL, NULL}
267 CMS_Menu cmsx_menuBlackbox = {
268 #ifdef CMS_MENU_DEBUG
269 .GUARD_text = "MENUBB",
270 .GUARD_type = OME_MENU,
271 #endif
272 .onEnter = cmsx_Blackbox_onEnter,
273 .onExit = cmsx_Blackbox_onExit,
274 .onDisplayUpdate = NULL,
275 .entries = cmsx_menuBlackboxEntries
278 #endif