LPCOpen Platform  v1.03
LPCOpen Platform for NXP LPC Microcontrollers
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
lwip_fs.c
Go to the documentation of this file.
1 /*
2  * @brief lwIP Filesystem implementation module
3  *
4  * @note
5  * Copyright(C) NXP Semiconductors, 2012
6  * All rights reserved.
7  *
8  * @par
9  * Software that is described herein is for illustrative purposes only
10  * which provides customers with programming information regarding the
11  * LPC products. This software is supplied "AS IS" without any warranties of
12  * any kind, and NXP Semiconductors and its licensor disclaim any and
13  * all warranties, express or implied, including all implied warranties of
14  * merchantability, fitness for a particular purpose and non-infringement of
15  * intellectual property rights. NXP Semiconductors assumes no responsibility
16  * or liability for the use of the software, conveys no license or rights under any
17  * patent, copyright, mask work right, or any other intellectual property rights in
18  * or to any products. NXP Semiconductors reserves the right to make changes
19  * in the software without notification. NXP Semiconductors also makes no
20  * representation or warranty that such application will be suitable for the
21  * specified use without further testing or modification.
22  *
23  * @par
24  * Permission to use, copy, modify, and distribute this software and its
25  * documentation is hereby granted, under NXP Semiconductors' and its
26  * licensor's relevant copyrights in the software, without fee, provided that it
27  * is used in conjunction with NXP Semiconductors microcontrollers. This
28  * copyright, permission, and disclaimer notice must appear in all copies of
29  * this code.
30  */
31 
32 #include <stdio.h>
33 #include <string.h>
34 #include <stdlib.h>
35 
36 #include "lwip/mem.h"
37 #include "lwip/memp.h"
38 #include "board.h"
39 #include "ff.h"
40 #include "fs_mem.h"
41 #include "lwip_fs.h"
42 #include "httpd_structs.h"
43 
49 /*****************************************************************************
50  * Private types/enumerations/variables
51  ****************************************************************************/
52 
53 /* Default html file */
54 const static char http_index_html[] =
55  "<html><head><title>Congrats!</title></head>"
56  "<body><h1>Welcome to our lwIP HTTP server!</h1>"
57  "<p>This is a small test page, served by httpd of "
58  "lwip.</p></body></html>";
59 
60 static FATFS Fatfs; /* File system object */
61 
62 /* Internal File descriptor structure */
63 struct file_ds {
64  uint8_t scratch[SECTOR_SZ];
65  FIL fi;
66  struct fs_file fs;
67  int fi_valid;
68 };
69 static volatile int32_t sdio_wait_exit = 0;
70 
71 /*****************************************************************************
72  * Public types/enumerations/variables
73  ****************************************************************************/
74 /* SDMMC card info structure */
76 
77 /*****************************************************************************
78  * Private functions
79  ****************************************************************************/
80 
81 #ifdef OS_FREE_RTOS
82 #include "FreeRTOS.h"
83 #include "semphr.h"
84 static xSemaphoreHandle open_lock;
85 /* FreeRTOS mutex lock */
86 static int mutex_lock(xSemaphoreHandle *mx)
87 {
88  if (xSemaphoreTake(*mx, 500) != pdTRUE) {
89  return 1;
90  }
91  return 0;
92 }
93 
94 /* FreeRTOS mutex unlock */
95 static void mutex_unlock(xSemaphoreHandle *mx)
96 {
97  xSemaphoreGive(*mx);
98 }
99 
100 /* FreeRTOS mutex init */
101 static int mutex_init(void)
102 {
103  open_lock = xSemaphoreCreateMutex();
104  return open_lock == NULL;
105 }
106 
107 #elif defined(OS_UCOS_III)
108 
109 #include "os.h"
110 #include "cpu.h"
111 #include "os_cfg_app.h"
112 
113 static OS_MUTEX *open_lock;
114 
115 /* mutex lock function for ucos-iii */
116 static int mutex_lock(OS_MUTEX **mx)
117 {
118  CPU_TS ts;
119  OS_ERR os_err;
120  OSMutexPend(*mx, 500, OS_OPT_PEND_BLOCKING, &ts, &os_err);
121  if (os_err != OS_ERR_NONE) {
122  return 1;
123  }
124 
125  return 0;
126 }
127 
128 /* Mutex unlock function for ucos-iii */
129 static void mutex_unlock(OS_MUTEX **mx)
130 {
131  OS_ERR os_err;
132  OSMutexPost(*mx, OS_OPT_POST_NONE, &os_err);
133 }
134 
135 /* Mutex init function for ucos-iii */
136 static int mutex_init(void)
137 {
138  static OS_MUTEX fsmutex;
139  OS_ERR os_err;
140  OSMutexCreate(&fsmutex, "DOS_FS_Mutex", &os_err);
141  if (os_err == OS_ERR_NONE) {
142  open_lock = &fsmutex;
143  return 0;
144  }
145  else {
146  return 1;
147  }
148 }
149 
150 #else
151 static int open_lock;
152 /* Mutex lock function for standalone */
153 static int mutex_lock(int *mx)
154 {
155  return 0;
156 }
157 
158 /* Mutex init for standalone */
159 static int mutex_init(void)
160 {
161  open_lock = 1;
162  return 0;
163 }
164 
165 /* Mutex lock for standalone */
166 static void mutex_unlock(int *mx)
167 {}
168 
169 #endif
170 
175 static int
176 get_http_headers(const char *fName, char *buff)
177 {
178  unsigned int iLoop;
179  const char *pszExt = NULL;
180  const char *hdrs[4];
181 
182  /* Ensure that we initialize the loop counter. */
183  iLoop = 0;
184 
185  /* In all cases, the second header we send is the server identification
186  so set it here. */
187  hdrs[1] = g_psHTTPHeaderStrings[HTTP_HDR_SERVER];
188 
189  /* Is this a normal file or the special case we use to send back the
190  default "404: Page not found" response? */
191  if (( fName == NULL) || ( *fName == 0) ) {
192  hdrs[0] = g_psHTTPHeaderStrings[HTTP_HDR_NOT_FOUND];
193  hdrs[2] = g_psHTTPHeaderStrings[DEFAULT_404_HTML];
194  goto end_fn;
195  }
196  /* We are dealing with a particular filename. Look for one other
197  special case. We assume that any filename with "404" in it must be
198  indicative of a 404 server error whereas all other files require
199  the 200 OK header. */
200  if (strstr(fName, "404")) {
201  iLoop = HTTP_HDR_NOT_FOUND;
202  }
203  else if (strstr(fName, "400")) {
204  iLoop = HTTP_HDR_BAD_REQUEST;
205  }
206  else if (strstr(fName, "501")) {
207  iLoop = HTTP_HDR_NOT_IMPL;
208  }
209  else {
210  iLoop = HTTP_HDR_OK;
211  }
212  hdrs[0] = g_psHTTPHeaderStrings[iLoop];
213 
214  /* Get a pointer to the file extension. We find this by looking for the
215  last occurrence of "." in the filename passed. */
216  pszExt = strrchr(fName, '.');
217 
218  /* Does the FileName passed have any file extension? If not, we assume it
219  is a special-case URL used for control state notification and we do
220  not send any HTTP headers with the response. */
221  if (pszExt == NULL) {
222  return 0;
223  }
224 
225  pszExt++;
226  /* Now determine the content type and add the relevant header for that. */
227  for (iLoop = 0; (iLoop < NUM_HTTP_HEADERS); iLoop++)
228  /* Have we found a matching extension? */
229  if (!strcmp(g_psHTTPHeaders[iLoop].extension, pszExt)) {
230  hdrs[2] =
231  g_psHTTPHeaderStrings[g_psHTTPHeaders[iLoop].headerIndex];
232  break;
233  }
234 
235  /* Did we find a matching extension? */
236  if (iLoop == NUM_HTTP_HEADERS) {
237  /* No - use the default, plain text file type. */
238  hdrs[2] = g_psHTTPHeaderStrings[HTTP_HDR_DEFAULT_TYPE];
239  }
240 
241 end_fn:
242  iLoop = strlen(hdrs[0]);
243  strcpy(buff, hdrs[0]);
244  strcat(buff, hdrs[1]);
245  strcat(buff, hdrs[2]);
246  return strlen(buff);
247 }
248 /* Delay callback for timed SDIF/SDMMC functions */
249 static void sdmmc_waitms(uint32_t time)
250 {
251  /* In an RTOS, the thread would sleep allowing other threads to run.
252  For standalone operation, we just spin on RI timer */
253  int32_t curr = (int32_t) Chip_RIT_GetCounter(LPC_RITIMER);
254  int32_t final = curr + ((SystemCoreClock / 1000) * time);
255 
256  if (final == curr) return;
257 
258  if ((final < 0) && (curr > 0)) {
259  while (Chip_RIT_GetCounter(LPC_RITIMER) < (uint32_t) final) {}
260  }
261  else {
262  while ((int32_t) Chip_RIT_GetCounter(LPC_RITIMER) < final) {}
263  }
264 
265  return;
266 }
267 
273 static void sdmmc_setup_wakeup(void *bits)
274 {
275  uint32_t bit_mask = *((uint32_t *)bits);
276  /* Wait for IRQ - for an RTOS, you would pend on an event here with a IRQ based wakeup. */
277  NVIC_ClearPendingIRQ(SDIO_IRQn);
278  sdio_wait_exit = 0;
279  Chip_SDIF_SetIntMask(LPC_SDMMC, bit_mask);
280  NVIC_EnableIRQ(SDIO_IRQn);
281 }
282 
288 {
290 
291  /* Wait for event, would be nice to have a timeout, but keep it simple */
292  while (sdio_wait_exit == 0) {}
293 
294  /* Get status and clear interrupts */
296 
297  return status;
298 }
299 
300 /* Initialize SD/MMC */
301 static void App_SDMMC_Init()
302 {
303  memset(&sdcardinfo, 0, sizeof(sdcardinfo));
306  sdcardinfo.card_info.msdelay_func = sdmmc_waitms;
307 
308  /* SD/MMC initialization */
310 
311  /* The SDIO driver needs to know the SDIO clock rate */
313 }
314 
315 /*****************************************************************************
316  * Public functions
317  ****************************************************************************/
318 
319 /* Read http header information into a string */
320 int GetHTTP_Header(const char *fName, char *buff)
321 {
322  return get_http_headers(fName, buff);
323 }
324 
325 /* Initialize the file system */
326 int fs_init(void)
327 {
328  void rtc_initialize(void);
329  App_SDMMC_Init();
330  rtc_initialize();
331 
332  NVIC_DisableIRQ(SDIO_IRQn);
333  /* Enable SD/MMC Interrupt */
334  NVIC_EnableIRQ(SDIO_IRQn);
335 
336  f_mount(0, &Fatfs); /* Register volume work area (never fails) */
337 
338  /* Initialize the mutex if not done already */
339  if (mutex_init()) {
340  LWIP_DEBUGF(HTTPD_DEBUG, ("DFS: ERROR: Mutex Init!\r\n"));
341  return 1;
342  }
343  return 0;
344 }
345 
346 /* Opens the default index html file */
347 struct fs_file *fs_open_default(void) {
348  int hlen;
349 
350  struct file_ds *fds;
351 
352  struct fs_file *fs;
353 
354  fds = (struct file_ds *)mem_malloc(sizeof(*fds));
355  if (fds == NULL) {
356  DEBUGSTR("Malloc Failure, Out of Memory!\r\n");
357  return NULL;
358  }
359  memset(fds, 0, sizeof(*fds));
360  fs = &fds->fs;
361  fs->pextension = (void *) fds; /* Store this for later use */
362  hlen = get_http_headers("default.htm", (char *) fds->scratch);
363  fs->data = (const char *) fds->scratch;
364  memcpy((void *) &fs->data[hlen], (void *) http_index_html, sizeof(http_index_html) - 1);
365  fs->len = hlen + sizeof(http_index_html) - 1;
366  fs->index = fs->len;
367  fs->http_header_included = 1;
368  return fs;
369 }
370 
371 /* File open function */
372 struct fs_file *fs_open(const char *name) {
373  FRESULT res;
374  int hlen;
375  struct file_ds *fds;
376  struct fs_file *fs;
377 
378  /* Too huge to keep in stack, must be protected with mutex */
379  static struct file_ds tmpds;
380 
381  if (mutex_lock(&open_lock)) {
382  LWIP_DEBUGF(HTTPD_DEBUG, ("DFS: ERROR: Mutex Timeout!\r\n"));
383  return NULL;
384  }
385  memset(&tmpds, 0, sizeof(tmpds));
386  fds = &tmpds;
387 
388  res = f_open(&fds->fi, name, FA_READ);
389  if (res) {
390  LWIP_DEBUGF(HTTPD_DEBUG, ("DFS: OPEN: File %s does not exist\r\n", name));
391  mutex_unlock(&open_lock);
392  return NULL;
393  }
394 
395  fds = (struct file_ds *)mem_malloc(sizeof(*fds));
396  if (fds == NULL) {
397  DEBUGSTR("Malloc Failure, Out of Memory!\r\n");
398  mutex_unlock(&open_lock);
399  return NULL;
400  }
401  memcpy(fds, &tmpds, sizeof(*fds));
402  mutex_unlock(&open_lock);
403 
404  fs = &fds->fs;
405  fds->fi_valid = 1;
406  fs->pextension = (void *) fds; /* Store this for later use */
407  hlen = get_http_headers(name, (char *) fds->scratch);
408  fs->data = (const char *) fds->scratch;
409  fs->index = hlen;
410  fs->len = f_size(&fds->fi) + hlen;
411  fs->http_header_included = 1;
412 
413  return fs;
414 }
415 
416 /* File close function */
417 void fs_close(struct fs_file *file)
418 {
419  struct file_ds *fds;
420 
421  if(file == NULL)
422  return;
423 
424  fds = (struct file_ds *) file->pextension;
425 
427  if (fds->fi_valid)
428  f_close(&fds->fi);
429 #endif
430 
431  mem_free(fds);
432 }
433 
434 /* File read function */
435 int fs_read(struct fs_file *file, char *buffer, int count)
436 {
437  uint32_t i = 0;
438  struct file_ds *fds = (struct file_ds *) file->pextension;
439  if (f_read(&fds->fi, (uint8_t *) buffer, count, &i))
440  return 0; /* Error in reading file */
441  file->index += i;
442  return i;
443 }
444 
445 /* Number of bytes left in the file */
446 int fs_bytes_left(struct fs_file *file)
447 {
448  return file->len - file->index;
449 }
450 
455 void SDIO_IRQHandler(void)
456 {
457  /* All SD based register handling is done in the callback
458  function. The SDIO interrupt is not enabled as part of this
459  driver and needs to be enabled/disabled in the callbacks or
460  application as needed. This is to allow flexibility with IRQ
461  handling for applicaitons and RTOSes. */
462  /* Set wait exit flag to tell wait function we are ready. In an RTOS,
463  this would trigger wakeup of a thread waiting for the IRQ. */
464  NVIC_DisableIRQ(SDIO_IRQn);
465  sdio_wait_exit = 1;
466 }
467 
468 
469 #ifdef LWIP_DEBUG
470 #if 0
471 /* Assert print function */
472 void assert_printf(char *msg, int line, char *file)
473 {
474  DEBUGOUT("ASSERT: %s at %s:%d\r\n", msg, file, line);
475 }
476 #endif
477 
478 /* LWIP str err function */
479 const char *lwip_strerr(err_t eno)
480 {
481  return "";
482 }
483 
484 #endif
485