* apps/examples/configdata/configdata_main.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
* Included Files
****************************************************************************/
#include <nuttx/config.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <nuttx/crc32.h>
#include <nuttx/mtd/mtd.h>
#include <nuttx/mtd/configdata.h>
#include <nuttx/fs/ioctl.h>
#include <sys/ioctl.h>
* Pre-processor Definitions
****************************************************************************/
* an architecture-specific MTD driver can be used instead by defining
* CONFIG_EXAMPLES_CONFIGDATA_ARCHINIT. In this case, the initialization
* logic will call configdata_archinitialize() to obtain the MTD driver
* instance.
*/
#ifndef CONFIG_EXAMPLES_CONFIGDATA_ARCHINIT
* drivers/mtd/rammtd.c
*/
# ifndef CONFIG_RAMMTD_ERASESIZE
# define CONFIG_RAMMTD_ERASESIZE 4096
# endif
# ifndef CONFIG_EXAMPLES_CONFIGDATA_NEBLOCKS
# define CONFIG_EXAMPLES_CONFIGDATA_NEBLOCKS (256)
# endif
# define EXAMPLES_CONFIGDATA_BUFSIZE \
(CONFIG_RAMMTD_ERASESIZE * CONFIG_EXAMPLES_CONFIGDATA_NEBLOCKS)
#endif
#ifndef CONFIG_EXAMPLES_CONFIGDATA_MAXSIZE
# define CONFIG_EXAMPLES_CONFIGDATA_MAXSIZE 512
#endif
#ifndef CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES
# define CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES 3000
#endif
#ifndef CONFIG_EXAMPLES_CONFIGDATA_NLOOPS
# define CONFIG_EXAMPLES_CONFIGDATA_NLOOPS 100
#endif
#define EXAMPLES_CONFIGDATA_REPORT (CONFIG_EXAMPLES_CONFIGDATA_NLOOPS / 20)
#if EXAMPLES_CONFIGDATA_REPORT == 0
# undef EXAMPLES_CONFIGDATA_REPORT
# define EXAMPLES_CONFIGDATA_REPORT 1
#endif
#ifndef CONFIG_EXAMPLES_CONFIGDATA_VERBOSE
# define CONFIG_EXAMPLES_CONFIGDATA_VERBOSE 0
#endif
* Private Types
****************************************************************************/
struct configdata_entrydesc_s
{
uint16_t id;
uint8_t instance;
uint16_t len;
uint32_t crc;
uint8_t deleted;
uint8_t changed;
};
* Private Data
****************************************************************************/
#ifndef CONFIG_EXAMPLES_CONFIGDATA_ARCHINIT
static uint8_t g_simflash[EXAMPLES_CONFIGDATA_BUFSIZE << 1];
#endif
static uint8_t g_entryimage[CONFIG_EXAMPLES_CONFIGDATA_MAXSIZE];
static struct configdata_entrydesc_s
g_entries[CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES];
static int g_nentries;
static int g_ndeleted;
static int g_fd;
static int g_ntests;
static int g_nverified;
static int g_ntotalalloc;
static int g_ntotaldelete;
static struct mallinfo g_mmbefore;
static struct mallinfo g_mmafter;
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
static struct mallinfo g_mmprevious;
#endif
* External Functions
****************************************************************************/
#ifdef CONFIG_EXAMPLES_CONFIGDATA_ARCHINIT
extern FAR struct mtd_dev_s *configdata_archinitialize(void);
#endif
* Private Functions
****************************************************************************/
* Name: configdata_memusage
****************************************************************************/
static void configdata_showmemusage(struct mallinfo *mmbefore,
struct mallinfo *mmafter)
{
printf("VARIABLE BEFORE AFTER\n");
printf("======== ======== ========\n");
printf("arena %8x %8x\n", mmbefore->arena, mmafter->arena);
printf("ordblks %8d %8d\n", mmbefore->ordblks, mmafter->ordblks);
printf("mxordblk %8x %8x\n", mmbefore->mxordblk, mmafter->mxordblk);
printf("uordblks %8x %8x\n", mmbefore->uordblks, mmafter->uordblks);
printf("fordblks %8x %8x\n", mmbefore->fordblks, mmafter->fordblks);
}
* Name: configdata_loopmemusage
****************************************************************************/
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
static void configdata_loopmemusage(void)
{
g_mmafter = mallinfo();
printf("\nEnd of loop memory usage:\n");
configdata_showmemusage(&g_mmprevious, &g_mmafter);
g_mmprevious = g_mmafter;
}
#endif
* Name: configdata_endmemusage
****************************************************************************/
static void configdata_endmemusage(void)
{
g_mmafter = mallinfo();
printf("\nFinal memory usage:\n");
configdata_showmemusage(&g_mmbefore, &g_mmafter);
printf("\nTotal adds: %d Total deletes : %d\n",
g_ntotalalloc, g_ntotaldelete);
printf("Total tests: %d Number passed: %d Failed: %d\n",
g_ntests, g_nverified, g_ntests - g_nverified);
}
* Name: configdata_randid
****************************************************************************/
static inline uint16_t configdata_randid(void)
{
int x;
int value;
retry:
value = rand() & 0x7fff;
if (value == 0)
{
value = 100;
}
for (x = 0; x < g_nentries; x++)
{
if (value == g_entries[x].id)
{
goto retry;
}
}
return value;
}
* Name: configdata_randlen
****************************************************************************/
static inline uint16_t configdata_randlen(void)
{
int value = rand() % CONFIG_EXAMPLES_CONFIGDATA_MAXSIZE;
if (value == 0)
{
return 1;
}
return value;
}
* Name: configdata_randinstance
****************************************************************************/
static inline uint8_t configdata_randinstance(void)
{
return rand() & 0xff;
}
* Name: configdata_freefile
****************************************************************************/
#if 0
static void configdata_freeentry(FAR struct configdata_entrydesc_s *entry)
{
memset(entry, 0, sizeof(struct configdata_entrydesc_s));
}
#endif
* Name: configdata_wrentry
****************************************************************************/
static inline int
configdata_wrentry(FAR struct configdata_entrydesc_s *entry)
{
size_t x;
int ret;
struct config_data_s config;
entry->id = configdata_randid();
entry->instance = configdata_randinstance();
entry->len = configdata_randlen();
for (x = 0; x < entry->len; x++)
{
g_entryimage[x] = rand() & 0xff;
}
entry->crc = crc32(g_entryimage, entry->len);
config.id = entry->id;
config.instance = entry->instance;
config.len = entry->len;
config.configdata = g_entryimage;
ret = ioctl(g_fd, CFGDIOC_SETCONFIG, (unsigned long)&config);
if (ret < 0)
{
entry->id = 0;
entry->len = 0;
return ERROR;
}
return OK;
}
* Name: configdata_fillconfig
****************************************************************************/
static int configdata_fillconfig(void)
{
FAR struct configdata_entrydesc_s *entry;
int ret;
int i;
for (i = 0; i < CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES; i++)
{
entry = &g_entries[i];
if (entry->id == 0)
{
ret = configdata_wrentry(entry);
if (ret < 0)
{
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" /dev/config full\n");
#endif
return ERROR;
}
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" Created entry %04X, %d Len=%d\n",
entry->id, entry->instance, entry->len);
#endif
g_nentries++;
g_ntotalalloc++;
}
}
return OK;
}
* Name: configdata_rdentry
****************************************************************************/
static inline int
configdata_rdentry(FAR struct configdata_entrydesc_s *entry)
{
struct config_data_s config;
uint32_t crc;
int ret;
config.id = entry->id;
config.instance = entry->instance;
config.len = entry->len;
config.configdata = g_entryimage;
ret = ioctl(g_fd, CFGDIOC_GETCONFIG, (unsigned long)&config);
if (ret < 0)
{
return ERROR;
}
crc = crc32(g_entryimage, entry->len);
if (crc != entry->crc)
{
printf("ERROR: Bad CRC: %" PRIu32 " vs %" PRIu32 "\n",
crc, entry->crc);
printf(" Entry id: %04X\n", entry->id);
printf(" Entry size: %d\n", entry->len);
return ERROR;
}
return OK;
}
* Name: configdata_verifyconfig
****************************************************************************/
static int configdata_verifyconfig(void)
{
FAR struct configdata_entrydesc_s *entry;
int ret;
int errcode = OK;
int i;
for (i = 0; i < CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES; i++)
{
entry = &g_entries[i];
if (entry->id != 0)
{
g_ntests++;
ret = configdata_rdentry(entry);
if (ret < 0)
{
if (entry->deleted)
{
g_nverified++;
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" Verified delete %04X, %d\n", entry->id,
entry->instance);
#endif
}
else
{
printf("ERROR: Failed to read an entry: %d\n", i);
printf(" Entry id: %04X\n", entry->id);
printf(" Entry size: %d\n", entry->len);
errcode = ERROR;
}
}
else
{
* error.
*/
if (entry->deleted)
{
printf("ERROR: Succesffully read a deleted entry\n");
printf(" Entry id: %04X\n", entry->id);
printf(" Entry size: %d\n", entry->len);
errcode = ERROR;
}
else
{
g_nverified++;
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" Verifed entry %04X, %d\n",
entry->id, entry->instance);
#endif
}
}
}
}
return errcode;
}
* Name: configdata_delentries
****************************************************************************/
static int configdata_delentries(void)
{
FAR struct configdata_entrydesc_s *entry;
struct config_data_s hdr;
int ndel;
int ret;
int i;
int j;
int nentries = g_nentries - g_ndeleted;
if (nentries < 1)
{
return 0;
}
ndel = (rand() % nentries) + 1;
for (i = 0; i < ndel; i++)
{
int ndx = (rand() % (g_nentries - g_ndeleted));
for (j = ndx + 1; j != ndx; )
{
entry = &g_entries[j];
if (entry->id && !entry->deleted)
{
hdr.id = entry->id;
hdr.instance = entry->instance;
hdr.len = 0;
ret = ioctl(g_fd, CFGDIOC_SETCONFIG, (unsigned long) &hdr);
if (ret < 0)
{
printf("ERROR: Delete %d failed: %d\n", i + 1, errno);
printf(" Entry id: %04X\n", entry->id);
printf(" Entry size: %d\n", entry->len);
printf(" Entry index: %d\n", j);
}
else
{
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" Deleted entry %04X\n", entry->id);
#endif
entry->deleted = true;
g_ndeleted++;
g_ntotaldelete++;
break;
}
}
if (++j >= CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES)
{
j = 0;
}
}
}
return OK;
}
* Name: configdata_getnextdeleted
****************************************************************************/
static int configdata_getnextdeleted(void)
{
int x;
int nextdeleted = -1;
for (x = 0; x < CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES; x++)
{
if (g_entries[x].deleted)
{
nextdeleted = x;
break;
}
}
return nextdeleted;
}
* Name: configdata_cleardeleted
****************************************************************************/
static void configdata_cleardeleted(void)
{
int nextdeleted;
int x;
while ((nextdeleted = configdata_getnextdeleted()) != -1)
{
for (x = nextdeleted + 1;
x < CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES;
x++)
{
if (g_entries[x].id && !g_entries[x].deleted)
{
break;
}
}
if (x < CONFIG_EXAMPLES_CONFIGDATA_MAXENTRIES)
{
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf(" Overwrite entry %d, OLD=%04X NEW=%04X\n",
nextdeleted, g_entries[nextdeleted].id, g_entries[x].id);
#endif
g_entries[nextdeleted] = g_entries[x];
g_entries[x].id = 0;
}
else
{
g_entries[nextdeleted].id = 0;
g_entries[nextdeleted].deleted = FALSE;
}
}
g_nentries -= g_ndeleted;
g_ndeleted = 0;
}
* Public Functions
****************************************************************************/
* Name: configdata_main
****************************************************************************/
int main(int argc, FAR char *argv[])
{
unsigned int i;
int ret;
FAR struct mtd_dev_s *mtd;
srand(0x93846);
#ifdef CONFIG_EXAMPLES_CONFIGDATA_ARCHINIT
mtd = configdata_archinitialize();
#else
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf("Creating %d byte RAM drive\n", EXAMPLES_CONFIGDATA_BUFSIZE);
#endif
mtd = rammtd_initialize(g_simflash, EXAMPLES_CONFIGDATA_BUFSIZE);
#endif
if (!mtd)
{
printf("ERROR: Failed to create RAM MTD instance\n");
fflush(stdout);
exit(1);
}
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf("Registering /dev/config device\n");
#endif
MTD_IOCTL(mtd, MTDIOC_BULKERASE, 0);
ret = mtdconfig_register(mtd);
if (ret < 0)
{
printf("ERROR: /dev/config registration failed: %d\n", -ret);
fflush(stdout);
exit(2);
}
memset(g_entries, 0, sizeof(g_entries));
g_fd = open("/dev/config", O_RDOK);
if (g_fd == -1)
{
printf("ERROR: Failed to open /dev/config %d\n", -errno);
fflush(stdout);
exit(2);
}
g_mmbefore = mallinfo();
* randomly, verify them randomly, add new config items.
*/
g_ntests = g_nverified = 0;
g_ntotaldelete = g_ntotalalloc = 0;
#if CONFIG_EXAMPLES_CONFIGDATA_NLOOPS == 0
for (i = 0; ; i++)
#else
for (i = 1; i <= CONFIG_EXAMPLES_CONFIGDATA_NLOOPS; i++)
#endif
{
* the open file structures are utilized or until (2) CONFIGDATA
* reports an error (hopefully that the /dev/config device is full)
*/
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
printf("\n=== FILLING %u =============================\n", i);
#endif
configdata_fillconfig();
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
printf("Filled /dev/config\n");
printf(" Number of entries: %d\n", g_nentries);
#endif
ret = configdata_verifyconfig();
if (ret < 0)
{
printf("ERROR: Failed to verify partition\n");
printf(" Number of entries: %d\n", g_nentries);
}
else
{
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf("Verified!\n");
printf(" Number of entries: %d\n", g_nentries);
#endif
#endif
}
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
printf("\n=== DELETING %u ============================\n", i);
#endif
ret = configdata_delentries();
if (ret < 0)
{
printf("ERROR: Failed to delete enries\n");
printf(" Number of entries: %d\n", g_nentries);
printf(" Number deleted: %d\n", g_ndeleted);
}
else
{
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
printf("Deleted some enries\n");
printf(" Number of entries: %d\n", g_nentries);
printf(" Number deleted: %d\n", g_ndeleted);
#endif
}
ret = configdata_verifyconfig();
if (ret < 0)
{
printf("ERROR: Failed to verify partition\n");
printf(" Number of entries: %d\n", g_nentries);
printf(" Number deleted: %d\n", g_ndeleted);
}
else
{
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
#if CONFIG_EXAMPLES_CONFIGDATA_VERBOSE != 0
printf("Verified!\n");
printf(" Number of entries: %d\n", g_nentries);
printf(" Number deleted: %d\n", g_ndeleted);
#endif
#endif
}
configdata_cleardeleted();
#ifndef CONFIG_EXAMPLES_CONFIGDATA_SILENT
configdata_loopmemusage();
fflush(stdout);
#else
if ((i % EXAMPLES_CONFIGDATA_REPORT) == 0)
{
printf("%u\n", i);
fflush(stdout);
}
#endif
}
#if 0
configdata_delallfiles();
#endif
configdata_endmemusage();
fflush(stdout);
return 0;
}