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"
46 #include "common/time.h"
48 #include "config/feature.h"
50 #include "drivers/flash/flash.h"
51 #include "drivers/time.h"
52 #include "drivers/sdcard.h"
53 #include "drivers/usb_msc.h"
55 #include "config/config.h"
57 #include "io/asyncfatfs/asyncfatfs.h"
58 #include "io/flashfs.h"
59 #include "io/beeper.h"
60 #include "io/usb_msc.h"
64 #include "flight/pid.h"
66 static const char * const cmsx_BlackboxDeviceNames
[] = {
73 static const char * const cmsx_BlackboxRateNames
[] = {
81 static uint8_t cmsx_BlackboxDevice
;
82 static OSD_TAB_t cmsx_BlackboxDeviceTable
= { &cmsx_BlackboxDevice
, 3, cmsx_BlackboxDeviceNames
};
83 static uint8_t cmsx_BlackboxRate
;
84 static OSD_TAB_t cmsx_BlackboxRateTable
= { &cmsx_BlackboxRate
, 4, cmsx_BlackboxRateNames
};
85 static debugType_e systemConfig_debug_mode
;
87 #define CMS_BLACKBOX_STRING_LENGTH 8
88 static char cmsx_BlackboxStatus
[CMS_BLACKBOX_STRING_LENGTH
];
89 static char cmsx_BlackboxDeviceStorageUsed
[CMS_BLACKBOX_STRING_LENGTH
];
90 static char cmsx_BlackboxDeviceStorageFree
[CMS_BLACKBOX_STRING_LENGTH
];
91 static char cmsx_pidFreq
[CMS_BLACKBOX_STRING_LENGTH
];
93 static void cmsx_Blackbox_GetDeviceStatus(void)
96 #if defined(USE_SDCARD) || defined(USE_FLASHFS)
97 bool storageDeviceIsWorking
= false;
99 uint32_t storageUsed
= 0;
100 uint32_t storageFree
= 0;
102 switch (blackboxConfig()->device
)
105 case BLACKBOX_DEVICE_SDCARD
:
108 if (!sdcard_isInserted()) {
109 tfp_sprintf(cmsx_BlackboxStatus
, "NO CARD");
110 } else if (!sdcard_isFunctional()) {
111 tfp_sprintf(cmsx_BlackboxStatus
, "FAULT");
113 switch (afatfs_getFilesystemState()) {
114 case AFATFS_FILESYSTEM_STATE_READY
:
115 tfp_sprintf(cmsx_BlackboxStatus
, "READY");
116 storageDeviceIsWorking
= true;
118 case AFATFS_FILESYSTEM_STATE_INITIALIZATION
:
119 tfp_sprintf(cmsx_BlackboxStatus
, "INIT");
121 case AFATFS_FILESYSTEM_STATE_FATAL
:
122 case AFATFS_FILESYSTEM_STATE_UNKNOWN
:
124 tfp_sprintf(cmsx_BlackboxStatus
, "FAULT");
129 if (storageDeviceIsWorking
) {
130 storageFree
= afatfs_getContiguousFreeSpace() / 1024000;
131 storageUsed
= (sdcard_getMetadata()->numBlocks
/ 2000) - storageFree
;
138 case BLACKBOX_DEVICE_FLASH
:
141 storageDeviceIsWorking
= flashfsIsSupported();
142 if (storageDeviceIsWorking
) {
143 tfp_sprintf(cmsx_BlackboxStatus
, "READY");
145 const flashPartition_t
*flashPartition
= flashPartitionFindByType(FLASH_PARTITION_TYPE_FLASHFS
);
146 const flashGeometry_t
*flashGeometry
= flashGetGeometry();
148 storageUsed
= flashfsGetOffset() / 1024;
149 storageFree
= ((FLASH_PARTITION_SECTOR_COUNT(flashPartition
) * flashGeometry
->sectorSize
) / 1024) - storageUsed
;
151 tfp_sprintf(cmsx_BlackboxStatus
, "FAULT");
158 tfp_sprintf(cmsx_BlackboxStatus
, "---");
161 /* Storage counters */
162 tfp_sprintf(cmsx_BlackboxDeviceStorageUsed
, "%ld%s", storageUsed
, unit
);
163 tfp_sprintf(cmsx_BlackboxDeviceStorageFree
, "%ld%s", storageFree
, unit
);
167 static const void *cmsx_EraseFlash(displayPort_t
*pDisplay
, const void *ptr
)
171 if (!flashfsIsSupported()) {
175 displayClearScreen(pDisplay
, DISPLAY_CLEAR_WAIT
);
176 displayWrite(pDisplay
, 5, 3, DISPLAYPORT_SEVERITY_INFO
, "ERASING FLASH...");
177 displayRedraw(pDisplay
);
179 flashfsEraseCompletely();
180 while (!flashfsIsReady()) {
181 //TODO: Make this non-blocking!
185 beeper(BEEPER_BLACKBOX_ERASE
);
186 displayClearScreen(pDisplay
, DISPLAY_CLEAR_WAIT
);
187 displayRedraw(pDisplay
);
189 // Update storage device status to show new used space amount
190 cmsx_Blackbox_GetDeviceStatus();
192 return MENU_CHAIN_BACK
;
194 #endif // USE_FLASHFS
197 static const void *cmsx_StorageDevice(displayPort_t
*pDisplay
, const void *ptr
)
201 if (mscCheckFilesystemReady()) {
202 displayClearScreen(pDisplay
, DISPLAY_CLEAR_WAIT
);
203 displayWrite(pDisplay
, 2, 4, DISPLAYPORT_SEVERITY_INFO
, "USB MASS STORAGE MODE IS ON");
204 displayWrite(pDisplay
, 4, 5, DISPLAYPORT_SEVERITY_INFO
, "CONNECT YOUR GADGET");
205 displayRedraw(pDisplay
);
207 int timezoneOffsetMinutes
= timeConfig()->tz_offsetMinutes
;
209 int timezoneOffsetMinutes
= 0;
212 systemResetToMsc(timezoneOffsetMinutes
);
215 displayWrite(pDisplay
, 5, 3, DISPLAYPORT_SEVERITY_INFO
, "STORAGE NOT PRESENT OR FAILED TO INITIALIZE!");
216 displayRedraw(pDisplay
);
218 return MENU_CHAIN_BACK
;
223 static const void *cmsx_Blackbox_onEnter(displayPort_t
*pDisp
)
227 cmsx_Blackbox_GetDeviceStatus();
228 cmsx_BlackboxDevice
= blackboxConfig()->device
;
229 cmsx_BlackboxRate
= blackboxConfig()->sample_rate
;
230 systemConfig_debug_mode
= systemConfig()->debug_mode
;
232 const uint16_t pidFreq
= (uint16_t)pidGetPidFrequency();
233 if (pidFreq
> 1000) {
234 tfp_sprintf(cmsx_pidFreq
, "%1d.%02dKHZ", (pidFreq
/ 10) / 100, (pidFreq
/ 10) % 100);
236 tfp_sprintf(cmsx_pidFreq
, "%3dHZ", pidFreq
);
241 static const void *cmsx_Blackbox_onExit(displayPort_t
*pDisp
, const OSD_Entry
*self
)
246 if (blackboxMayEditConfig()) {
247 blackboxConfigMutable()->device
= cmsx_BlackboxDevice
;
248 blackboxValidateConfig();
250 blackboxConfigMutable()->sample_rate
= cmsx_BlackboxRate
;
251 systemConfigMutable()->debug_mode
= systemConfig_debug_mode
;
256 // Check before erase flash
258 static const OSD_Entry menuEraseFlashCheckEntries
[] = {
259 { "CONFIRM ERASE", OME_Label
, NULL
, NULL
},
260 { "NO", OME_Back
, NULL
, NULL
},
262 { "YES", OME_Funcall
, cmsx_EraseFlash
, NULL
},
263 { NULL
, OME_END
, NULL
, NULL
}
266 static CMS_Menu cmsx_menuEraseFlashCheck
= {
267 #ifdef CMS_MENU_DEBUG
268 .GUARD_text
= "MENUERASEFLASH",
269 .GUARD_type
= OME_MENU
,
273 .onDisplayUpdate
= NULL
,
274 .entries
= menuEraseFlashCheckEntries
279 static const OSD_Entry menuStorageDeviceCheckEntries
[] = {
280 { "CONFIRM USB MASS STORAGE", OME_Label
, NULL
, NULL
},
281 { "NO", OME_Back
, NULL
, NULL
},
283 { "YES", OME_Funcall
, cmsx_StorageDevice
, NULL
},
284 { NULL
, OME_END
, NULL
, NULL
}
287 static CMS_Menu cmsx_menuStorageDeviceCheck
= {
288 #ifdef CMS_MENU_DEBUG
289 .GUARD_text
= "STORAGEDEVICE",
290 .GUARD_type
= OME_MENU
,
294 .onDisplayUpdate
= NULL
,
295 .entries
= menuStorageDeviceCheckEntries
299 static const OSD_Entry cmsx_menuBlackboxEntries
[] =
301 { "-- BLACKBOX --", OME_Label
, NULL
, NULL
},
302 { "(PID FREQ)", OME_String
, NULL
, &cmsx_pidFreq
},
303 { "SAMPLERATE", OME_TAB
| REBOOT_REQUIRED
, NULL
, &cmsx_BlackboxRateTable
},
304 { "DEVICE", OME_TAB
| REBOOT_REQUIRED
, NULL
, &cmsx_BlackboxDeviceTable
},
305 { "(STATUS)", OME_String
, NULL
, &cmsx_BlackboxStatus
},
306 { "(USED)", OME_String
, NULL
, &cmsx_BlackboxDeviceStorageUsed
},
307 { "(FREE)", OME_String
, NULL
, &cmsx_BlackboxDeviceStorageFree
},
308 { "DEBUG MODE", OME_TAB
| REBOOT_REQUIRED
, NULL
, &(OSD_TAB_t
) { &systemConfig_debug_mode
, DEBUG_COUNT
- 1, debugModeNames
} },
311 { "USB MASS STORAGE", OME_Submenu
, cmsMenuChange
, &cmsx_menuStorageDeviceCheck
},
312 #endif // USE_USB_MSC
314 { "ERASE FLASH", OME_Submenu
, cmsMenuChange
, &cmsx_menuEraseFlashCheck
},
315 #endif // USE_FLASHFS
317 { "BACK", OME_Back
, NULL
, NULL
},
318 { NULL
, OME_END
, NULL
, NULL
}
321 CMS_Menu cmsx_menuBlackbox
= {
322 #ifdef CMS_MENU_DEBUG
323 .GUARD_text
= "MENUBB",
324 .GUARD_type
= OME_MENU
,
326 .onEnter
= cmsx_Blackbox_onEnter
,
327 .onExit
= cmsx_Blackbox_onExit
,
328 .onDisplayUpdate
= NULL
,
329 .entries
= cmsx_menuBlackboxEntries