Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
sdlog_chibios.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2013-2015 Gautier Hattenberger, Alexandre Bustico
3  *
4  * This file is part of paparazzi.
5  *
6  * paparazzi is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2, or (at your option)
9  * any later version.
10  *
11  * paparazzi is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with paparazzi; see the file COPYING. If not, write to
18  * the Free Software Foundation, 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 
22 /*
23  * @file modules/loggers/sdlog_chibios.c
24  * @brief sdlog process with battery monitoring
25  *
26  */
27 
28 #include <ch.h>
29 #include <hal.h>
35 #include "mcu_periph/adc.h"
36 #include "mcu.h"
37 #include "led.h"
38 
39 #if HAL_USE_RTC
40 #include <hal_rtc.h>
41 #include <time.h>
42 #include "modules/gps/gps.h"
43 #endif
44 
45 // Delay before starting SD log
46 #ifndef SDLOG_START_DELAY
47 #define SDLOG_START_DELAY 30
48 #endif
49 
50 // Auto-flush period (in seconds)
51 #ifndef SDLOG_AUTO_FLUSH_PERIOD
52 #define SDLOG_AUTO_FLUSH_PERIOD 10
53 #endif
54 
55 // Contiguous storage memory (in Mo)
56 #ifndef SDLOG_CONTIGUOUS_STORAGE_MEM
57 #define SDLOG_CONTIGUOUS_STORAGE_MEM 50
58 #endif
59 
60 #if (!defined USE_ADC_WATCHDOG) || (USE_ADC_WATCHDOG == 0)
61 #error sdlog_chibios need USE_ADC_WATCHDOG in order to properly close files when power is unplugged
62 #endif
63 
64 static const char PPRZ_LOG_NAME[] = "pprzlog_";
65 static const char PPRZ_LOG_DIR[] = "PPRZ";
66 
67 /*
68  * Start log thread
69  */
70 static IN_DMA_SECTION(THD_WORKING_AREA(wa_thd_startlog, 4096));
71 static __attribute__((noreturn)) void thd_startlog(void *arg);
72 
73 bool sdOk = false;
74 
76 
78 
79 #if FLIGHTRECORDER_SDLOG
80 static const char FLIGHTRECORDER_LOG_NAME[] = "fr_";
81 static const char FR_LOG_DIR[] = "FLIGHT_RECORDER";
82 FileDes flightRecorderLogFile = -1;
83 #endif
84 
87 static enum {
92 
95 static char chibios_sdlog_filenames[68];
96 static char NO_FILE_NAME[] = "none";
97 
98 #if PREFLIGHT_CHECKS
99 /* Preflight checks */
101 static struct preflight_check_t sdlog_pfc;
102 
103 static void sdlog_preflight(struct preflight_result_t *result) {
105 #ifdef SDLOG_PREFLIGHT_ERROR
106  preflight_error(result, "SDLogger is not running [%d:%d]", chibios_sdlog_status, sdLogGetStorageStatus());
107 #else
108  preflight_warning(result, "SDLogger is not running [%d:%d]", chibios_sdlog_status, sdLogGetStorageStatus());
109 #endif
110  } else {
111  preflight_success(result, "SDLogger running");
112  }
113 }
114 #endif // PREFLIGHT_CHECKS
115 
116 #if PERIODIC_TELEMETRY
118 static void send_sdlog_status(struct transport_tx *trans, struct link_device *dev)
119 {
121  uint8_t errno = (uint8_t) sdLogGetStorageStatus();
122  uint32_t used = (uint32_t) sdLogGetNbBytesWrittenToStorage();
123  uint8_t size = strlen(chibios_sdlog_filenames);
124  char *filenames = chibios_sdlog_filenames;
125  if (size == 0) {
126  // when no file opened
127  filenames = NO_FILE_NAME;
128  size = strlen(filenames);
129  }
130  pprz_msg_send_LOGGER_STATUS(trans, dev, AC_ID, &status, &errno, &used, size, filenames);
131 }
132 #endif
133 
134 
135 // Functions for the generic device API
136 static int sdlog_check_free_space(struct chibios_sdlog *p __attribute__((unused)), long *fd, uint16_t len)
137 {
138  SdLogBuffer *sdb;
139  SdioError status = sdLogAllocSDB(&sdb, len);
140  if (status != SDLOG_OK) {
141  return 0;
142  } else {
143  *fd = (long) sdb;
144  return 1;
145  }
146 }
147 
148 static void sdlog_transmit(struct chibios_sdlog *p __attribute__((unused)), long fd, uint8_t byte)
149 {
150  SdLogBuffer *sdb = (SdLogBuffer *) fd;
151  uint8_t *data = (uint8_t *) sdLogGetBufferFromSDB(sdb);
152  *data = byte;
153  sdLogSeekBufferFromSDB(sdb, 1);
154 }
155 
156 static void sdlog_transmit_buffer(struct chibios_sdlog *p __attribute__((unused)), long fd, uint8_t *data, uint16_t len)
157 {
158  SdLogBuffer *sdb = (SdLogBuffer *) fd;
159  memcpy(sdLogGetBufferFromSDB(sdb), data, len);
160  sdLogSeekBufferFromSDB(sdb, len);
161 }
162 
163 static void sdlog_send(struct chibios_sdlog *p, long fd)
164 {
165  SdLogBuffer *sdb = (SdLogBuffer *) fd;
166  sdLogWriteSDB(*(p->file), sdb);
167 }
168 
169 static int null_function(struct chibios_sdlog *p __attribute__((unused))) { return 0; }
170 static uint8_t null_byte_function(struct chibios_sdlog *p __attribute__((unused))) { return 0; }
171 
172 void chibios_sdlog_init(struct chibios_sdlog *sdlog, FileDes *file)
173 {
174  // Store file descriptor
175  sdlog->file = file;
176  // Configure generic device
177  sdlog->device.periph = (void *)(sdlog);
178  sdlog->device.check_free_space = (check_free_space_t) sdlog_check_free_space;
179  sdlog->device.put_byte = (put_byte_t) sdlog_transmit;
180  sdlog->device.put_buffer = (put_buffer_t) sdlog_transmit_buffer;
181  sdlog->device.send_message = (send_message_t) sdlog_send;
182  sdlog->device.char_available = (char_available_t) null_function; // write only
183  sdlog->device.get_byte = (get_byte_t) null_byte_function; // write only
184 
185 }
186 
188 {
190 #if PERIODIC_TELEMETRY
192 #endif
193 
194 #if PREFLIGHT_CHECKS
195  preflight_check_register(&sdlog_pfc, sdlog_preflight);
196 #endif
197 
198  // Start polling on USB
200 
201  // Start log thread
202  chThdCreateStatic(wa_thd_startlog, sizeof(wa_thd_startlog),
203  NORMALPRIO + 2, thd_startlog, NULL);
204 }
205 
206 
207 void sdlog_chibios_finish(const bool flush)
208 {
209  if (pprzLogFile != -1) {
210  // if a FF_FS_REENTRANT is true, we can umount fs without closing
211  // file, fatfs lock will assure that umount is done after a write,
212  // and umount will close all open files cleanly. Thats the fatest
213  // way to umount cleanly filesystem.
214  //
215  // if FF_FS_REENTRANT is false,
216  // we have to flush and close files before unmounting filesystem
217 #if FF_FS_REENTRANT == 0
218  sdLogCloseAllLogs(flush);
219 #else
220  (void) flush;
221 #endif
222 
223  sdLogFinish();
224  pprzLogFile = -1;
225 #if FLIGHTRECORDER_SDLOG
226  flightRecorderLogFile = -1;
227 #endif
228  }
230 }
231 
232 #if defined(SDLOG_BAT_ADC) && defined(SDLOG_BAT_CHAN)
233 /*
234  * Bat survey thread
235  */
236 static THD_WORKING_AREA(wa_thd_bat_survey, 1024);
237 static __attribute__((noreturn)) void thd_bat_survey(void *arg);
238 static void powerOutageIsr(void);
239 event_source_t powerOutageSource;
240 event_listener_t powerOutageListener;
241 
242 #define DefaultAdcOfVoltage(voltage) ((uint32_t) (voltage/(DefaultVoltageOfAdc(1))))
243 static const uint16_t V_ALERT = DefaultAdcOfVoltage(5.5f);
244 
245 /*
246  powerOutageIsr is called within a lock zone from an isr, so no lock/unlock is needed
247 */
248 static void powerOutageIsr(void)
249 {
250  chEvtBroadcastI(&powerOutageSource);
251 }
252 
253 static void thd_bat_survey(void *arg)
254 {
255  (void)arg;
256  chRegSetThreadName("battery survey");
257  chEvtRegister(&powerOutageSource, &powerOutageListener, 1);
258  chThdSleepMilliseconds(2000);
259 
260  register_adc_watchdog(&SDLOG_BAT_ADC, SDLOG_BAT_CHAN, V_ALERT, &powerOutageIsr);
261 
262  chEvtWaitOne(EVENT_MASK(1));
263  // Only try to energy save is it is really a problem and not powered through USB
264  if (palReadPad(SDLOG_USB_VBUS_PORT, SDLOG_USB_VBUS_PIN) == PAL_LOW) {
265  // disable all required periph to save energy and maximize chance to flush files
266  // to mass storage and avoid infamous dirty bit on filesystem
267  mcu_energy_save();
268  }
269 
270  // in case of powerloss, we should go fast and avoid to flush ram buffer
271  sdlog_chibios_finish(false);
272 
273  // Only put to deep sleep in case there is no power on the USB
274  if (palReadPad(SDLOG_USB_VBUS_PORT, SDLOG_USB_VBUS_PIN) == PAL_LOW) {
276  }
277  chThdExit(0);
278  while (true); // never goes here, only to avoid compiler warning: 'noreturn' function does return
279 }
280 #endif
281 
282 static void thd_startlog(void *arg)
283 {
284  (void) arg;
285  chRegSetThreadName("start log");
286  char tmpFilename[32];
287 
288  // Wait before starting the log if needed
289  chThdSleepSeconds(SDLOG_START_DELAY);
290  // Check if we are already in USB Storage mode
291  if (usbStorageIsItRunning()) {
292  chThdSleepSeconds(20000); // stuck here for hours FIXME stop the thread ?
293  }
294 
295  // Init sdlog struct
297 
298  // Check for init errors
299  sdOk = true;
300 
301  if (sdLogInit(NULL) != SDLOG_OK) {
302  sdOk = false;
303  } else {
305  if (sdLogOpenLog(&pprzLogFile, PPRZ_LOG_DIR,
307  SDLOG_CONTIGUOUS_STORAGE_MEM, LOG_PREALLOCATION_DISABLED, tmpFilename, sizeof(tmpFilename)) != SDLOG_OK) {
308  sdOk = false;
309  }
310  chsnprintf(chibios_sdlog_filenames, sizeof(chibios_sdlog_filenames), "%s", tmpFilename);
311 #if FLIGHTRECORDER_SDLOG
312  removeEmptyLogs(FR_LOG_DIR, FLIGHTRECORDER_LOG_NAME, 50);
313  if (sdLogOpenLog(&flightRecorderLogFile, FR_LOG_DIR, FLIGHTRECORDER_LOG_NAME,
315  SDLOG_CONTIGUOUS_STORAGE_MEM, LOG_PREALLOCATION_DISABLED, tmpFilename, sizeof(tmpFilename)) != SDLOG_OK) {
316  sdOk = false;
317  }
319 #endif
320  }
321 
322  if (sdOk) {
323 #if defined(SDLOG_BAT_ADC) && defined(SDLOG_BAT_CHAN)
324  // Create Battery Survey Thread with event
325  chEvtObjectInit(&powerOutageSource);
326  chThdCreateStatic(wa_thd_bat_survey, sizeof(wa_thd_bat_survey),
327  NORMALPRIO + 2, thd_bat_survey, NULL);
328 #endif
329 
331  } else {
333  }
334 
335  while (true) {
336 #ifdef SDLOG_LED
337  LED_TOGGLE(SDLOG_LED);
338 #endif
339  // Blink faster if init has errors
340  chThdSleepMilliseconds(sdOk == true ? 1000 : 200);
341  if (sdLogGetStorageStatus() != SDLOG_OK) {
343  sdOk = false;
344  } else {
346  sdOk = true;
347  }
348 
349 #if HAL_USE_RTC && USE_GPS
350  static uint32_t timestamp = 0;
351  // FIXME this could be done somewhere else, like in sys_time
352  // we sync gps time to rtc every 5 seconds
353  if (chVTGetSystemTime() - timestamp > TIME_S2I(5)) {
354  timestamp = chVTGetSystemTime();
355  if (gps.tow != 0) {
356  // Unix timestamp of the GPS epoch 1980-01-06 00:00:00 UTC
357  const uint32_t unixToGpsEpoch = 315964800;
358  struct tm time_tm;
359  time_t univTime = ((gps.week * 7 * 24 * 3600) + (gps.tow / 1000)) + unixToGpsEpoch;
360  gmtime_r(&univTime, &time_tm);
361  // Chibios date struct
362  RTCDateTime date;
363  rtcConvertStructTmToDateTime(&time_tm, 0, &date);
364  rtcSetTime(&RTCD1, &date);
365  }
366  }
367 #endif
368 
369  }
370 }
371 
372 
374  uint8_t ac_id = pprzlink_get_DL_INFO_MSG_UP_ac_id(buf);
375  if(ac_id != AC_ID && ac_id != 0xFF) {
376  return;
377  }
378  uint8_t fd = pprzlink_get_DL_INFO_MSG_UP_fd(buf);
379  if(pprzLogFile != -1 && (fd == DEST_INFO_MSG_ALL || fd == DEST_INFO_MSG_PPRZLOG)) {
380  uint8_t len = pprzlink_get_INFO_MSG_UP_msg_length(buf);
381  uint8_t* msg = (uint8_t*) pprzlink_get_DL_INFO_MSG_UP_msg(buf);
382  sdLogWriteRaw(pprzLogFile, msg, len);
383  sdLogWriteByte(pprzLogFile, '\n');
384  }
385 }
386 
arch independent ADC (Analog to Digital Converter) API
#define SDLOG_BAT_ADC
Definition: board.h:533
#define SDLOG_USB_VBUS_PIN
Definition: board.h:538
#define SDLOG_USB_VBUS_PORT
Definition: board.h:537
#define SDLOG_BAT_CHAN
Definition: board.h:534
#define LED_TOGGLE(i)
Definition: led_hw.h:53
struct GpsState gps
global GPS state
Definition: gps.c:74
Device independent GPS code (interface)
uint32_t tow
GPS time of week in ms.
Definition: gps.h:109
uint16_t week
GPS week.
Definition: gps.h:108
void chsnprintf(char *buffer, size_t size, const char *fmt,...)
Definition: printf.c:377
void mcu_reboot(enum reboot_state_t reboot_state)
Reboot the MCU.
Definition: mcu_arch.c:206
void mcu_energy_save(void)
Save energy for performing operations on shutdown Used for example to shutdown SD-card logging.
Definition: mcu_arch.c:230
@ MCU_REBOOT_POWEROFF
Poweroff the device.
Definition: mcu.h:44
uint8_t msg[10]
Buffer used for general comunication over SPI (out buffer)
static float p[2][2]
arch independent LED (Light Emitting Diodes) API
THD_WORKING_AREA(wa_thd_ap, THD_WORKING_AREA_MAIN)
Arch independent mcu ( Micro Controller Unit ) utilities.
#define byte
uint8_t status
void preflight_error(struct preflight_result_t *result, const char *fmt,...)
Register a preflight error used inside the preflight checking functions.
void preflight_success(struct preflight_result_t *result, const char *fmt,...)
Register a preflight success used inside the preflight checking functions.
void preflight_warning(struct preflight_result_t *result, const char *fmt,...)
Register a preflight warning used inside the preflight checking functions.
void preflight_check_register(struct preflight_check_t *check, preflight_check_f func)
Register a preflight check and add it to the linked list.
Mini printf-like functionality.
SdioError sdLogFinish(void)
unmount filesystem
Definition: sdLog.c:285
SdioError removeEmptyLogs(const char *directoryName, const char *prefix, const size_t sizeConsideredEmpty)
remove spurious log file left on sd
Definition: sdLog.c:815
SdioError sdLogInit(uint32_t *freeSpaceInKo)
initialise sdLog
Definition: sdLog.c:225
struct _SdLogBuffer SdLogBuffer
Definition: sdLog.h:127
int8_t FileDes
Definition: sdLog.h:128
#define LOG_APPEND_TAG_AT_CLOSE_DISABLED
Definition: sdLog.h:105
SdioError
Definition: sdLog.h:111
@ SDLOG_OK
Definition: sdLog.h:112
#define LOG_PREALLOCATION_DISABLED
Definition: sdLog.h:103
static void sdlog_send(struct chibios_sdlog *p, long fd)
static int null_function(struct chibios_sdlog *p)
static void send_sdlog_status(struct transport_tx *trans, struct link_device *dev)
static int sdlog_check_free_space(struct chibios_sdlog *p, long *fd, uint16_t len)
void logger_log_msg_up(uint8_t *buf)
@ SDLOG_STOPPED
Definition: sdlog_chibios.c:88
@ SDLOG_ERROR
Definition: sdlog_chibios.c:90
@ SDLOG_RUNNING
Definition: sdlog_chibios.c:89
static IN_DMA_SECTION(THD_WORKING_AREA(wa_thd_startlog, 4096))
static void thd_startlog(void *arg)
#define SDLOG_AUTO_FLUSH_PERIOD
Definition: sdlog_chibios.c:52
static const char PPRZ_LOG_DIR[]
Definition: sdlog_chibios.c:65
void sdlog_chibios_finish(const bool flush)
static void sdlog_transmit(struct chibios_sdlog *p, long fd, uint8_t byte)
FileDes pprzLogFile
Definition: sdlog_chibios.c:75
static enum @298 chibios_sdlog_status
sdlog status
#define SDLOG_START_DELAY
Definition: sdlog_chibios.c:47
static char NO_FILE_NAME[]
Definition: sdlog_chibios.c:96
static const char PPRZ_LOG_NAME[]
Definition: sdlog_chibios.c:64
#define SDLOG_CONTIGUOUS_STORAGE_MEM
Definition: sdlog_chibios.c:57
void chibios_sdlog_init(struct chibios_sdlog *sdlog, FileDes *file)
init chibios_sdlog structure
bool sdOk
Definition: sdlog_chibios.c:73
static char chibios_sdlog_filenames[68]
sdlog filenames
Definition: sdlog_chibios.c:95
static uint8_t null_byte_function(struct chibios_sdlog *p)
static void sdlog_transmit_buffer(struct chibios_sdlog *p, long fd, uint8_t *data, uint16_t len)
void sdlog_chibios_init(void)
#define DEST_INFO_MSG_PPRZLOG
Definition: sdlog_chibios.h:44
FileDes * file
Definition: sdlog_chibios.h:59
#define DEST_INFO_MSG_ALL
Definition: sdlog_chibios.h:42
struct link_device device
Generic device interface.
Definition: sdlog_chibios.h:61
chibios_sdlog structure
Definition: sdlog_chibios.h:58
int fd
Definition: serial.c:26
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition: telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition: telemetry.h:66
Dynamic memory allocation based on TLSF library.
void usbStorageStartPolling(void)
Definition: usbStorage.c:76
bool usbStorageIsItRunning(void)
Definition: usbStorage.c:163
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98