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)
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.
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"
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"
61 #include "flight/pid.h"
63 static const char * const cmsx_BlackboxDeviceNames
[] = {
70 static const char * const cmsx_BlackboxRateNames
[] = {
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)
93 #if defined(USE_SDCARD) || defined(USE_FLASHFS)
94 bool storageDeviceIsWorking
= false;
96 uint32_t storageUsed
= 0;
97 uint32_t storageFree
= 0;
99 switch (blackboxConfig()->device
)
102 case BLACKBOX_DEVICE_SDCARD
:
105 if (!sdcard_isInserted()) {
106 tfp_sprintf(cmsx_BlackboxStatus
, "NO CARD");
107 } else if (!sdcard_isFunctional()) {
108 tfp_sprintf(cmsx_BlackboxStatus
, "FAULT");
110 switch (afatfs_getFilesystemState()) {
111 case AFATFS_FILESYSTEM_STATE_READY
:
112 tfp_sprintf(cmsx_BlackboxStatus
, "READY");
113 storageDeviceIsWorking
= true;
115 case AFATFS_FILESYSTEM_STATE_INITIALIZATION
:
116 tfp_sprintf(cmsx_BlackboxStatus
, "INIT");
118 case AFATFS_FILESYSTEM_STATE_FATAL
:
119 case AFATFS_FILESYSTEM_STATE_UNKNOWN
:
121 tfp_sprintf(cmsx_BlackboxStatus
, "FAULT");
126 if (storageDeviceIsWorking
) {
127 storageFree
= afatfs_getContiguousFreeSpace() / 1024000;
128 storageUsed
= (sdcard_getMetadata()->numBlocks
/ 2000) - storageFree
;
135 case BLACKBOX_DEVICE_FLASH
:
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
;
148 tfp_sprintf(cmsx_BlackboxStatus
, "FAULT");
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
);
164 static const void *cmsx_EraseFlash(displayPort_t
*pDisplay
, const void *ptr
)
168 if (!flashfsIsSupported()) {
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!
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
)
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);
206 tfp_sprintf(cmsx_pidFreq
, "%3dHZ", pidFreq
);
211 static const void *cmsx_Blackbox_onExit(displayPort_t
*pDisp
, const OSD_Entry
*self
)
216 if (blackboxMayEditConfig()) {
217 blackboxConfigMutable()->device
= cmsx_BlackboxDevice
;
218 blackboxValidateConfig();
220 blackboxConfigMutable()->sample_rate
= cmsx_BlackboxRate
;
221 systemConfigMutable()->debug_mode
= systemConfig_debug_mode
;
226 // Check before erase flash
228 static const OSD_Entry menuEraseFlashCheckEntries
[] = {
229 { "CONFIRM ERASE", OME_Label
, NULL
, NULL
, 0},
230 { "YES", OME_Funcall
, cmsx_EraseFlash
, NULL
, 0 },
232 { "NO", OME_Back
, NULL
, NULL
, 0 },
233 { NULL
, OME_END
, NULL
, NULL
, 0 }
236 static CMS_Menu cmsx_menuEraseFlashCheck
= {
237 #ifdef CMS_MENU_DEBUG
238 .GUARD_text
= "MENUERASEFLASH",
239 .GUARD_type
= OME_MENU
,
243 .onDisplayUpdate
= NULL
,
244 .entries
= menuEraseFlashCheckEntries
248 static const OSD_Entry cmsx_menuBlackboxEntries
[] =
250 { "-- BLACKBOX --", OME_Label
, NULL
, NULL
, 0},
251 { "(PID FREQ)", OME_String
, NULL
, &cmsx_pidFreq
, 0 },
252 { "SAMPLERATE", OME_TAB
, NULL
, &cmsx_BlackboxRateTable
, REBOOT_REQUIRED
},
253 { "DEVICE", OME_TAB
, NULL
, &cmsx_BlackboxDeviceTable
, REBOOT_REQUIRED
},
254 { "(STATUS)", OME_String
, NULL
, &cmsx_BlackboxStatus
, 0 },
255 { "(USED)", OME_String
, NULL
, &cmsx_BlackboxDeviceStorageUsed
, 0 },
256 { "(FREE)", OME_String
, NULL
, &cmsx_BlackboxDeviceStorageFree
, 0 },
257 { "DEBUG MODE", OME_TAB
, NULL
, &(OSD_TAB_t
) { &systemConfig_debug_mode
, DEBUG_COUNT
- 1, debugModeNames
}, REBOOT_REQUIRED
},
260 { "ERASE FLASH", OME_Submenu
, cmsMenuChange
, &cmsx_menuEraseFlashCheck
, 0 },
261 #endif // USE_FLASHFS
263 { "BACK", OME_Back
, NULL
, NULL
, 0 },
264 { NULL
, OME_END
, NULL
, NULL
, 0 }
267 CMS_Menu cmsx_menuBlackbox
= {
268 #ifdef CMS_MENU_DEBUG
269 .GUARD_text
= "MENUBB",
270 .GUARD_type
= OME_MENU
,
272 .onEnter
= cmsx_Blackbox_onEnter
,
273 .onExit
= cmsx_Blackbox_onExit
,
274 .onDisplayUpdate
= NULL
,
275 .entries
= cmsx_menuBlackboxEntries