嵌入式世界中的 C 文件函数

C file functions in embedded world

我有一个嵌入式系统和一个库的问题。

我目前正在使用名为 Ambiq [3] 的设备,该设备使用 Cortex M-4,我想在其上使用 FANN(快速人工神经网络)库 [2]。 我能够编译 link 一切,但问题是 FANN 库在启动时需要读取 2 个文件。

现在,我有一个嵌入式系统,所以我没有任何文件系统,也没有操作系统。 我很确定我可以通过某种方式将该文件的内容写入闪存,但我真的不知道如何 link C 文件功能的第一个文件地址,例如"fopen" 需要文件名作为输入。我只需要文件名和文件物理地址之间的某种联系,如果它退出(或接受不同于文件名的 C 函数),我就完成了。

我已经尝试过的一件事是使用 xxd -i [filename] [1] 将文件的内容硬编码到 C 数组中,但我不知道我应该怎么做 link FANN 库使用的 fopen。我也开始了一些切肉刀解析器,但它似乎真的很耗时。

如果你能给我一些建议,请告诉我。 先感谢您。 最好的祝福。 贾斯基拉特

附加信息: - 编译软件:Eclipse with makefile。 - 编译器:eabi-none-gcc 工具箱 - 我正在使用应该在 Cortex M4 上 运行 的 Ambiq 微控制器应用程序直接编译 FANN 库源代码。

参考资料: [1] Read a file into a string at compile-time [2] 范恩图书馆官方网站 http://leenissen.dk/fann/wp/ [3] AMBIQ 微型:http://ambiqmicro.com/

假设您拥有 FANN 库的源代码,最简单的解决方案是修改它以直接访问您的数据数组,而不是使用文件系统模型。

但是,如果您真的必须对静态数据实施文件系统访问模型,那么,您将需要实施这些功能,或者在提供的情况下实施库重新定位存根。例如,如果您使用的是 newlib,则可以通过实现较低级别的系统调用来启用较高级别的 stdio 文件功能。例如,open() 的最小存根什么也不做,看起来像:

int open(const char *name, int flags, int mode) {
  return -1;
}

读取函数使用 open 返回的句柄来访问您根据需要定义的控制结构。因此,让我们假设您已经从文件数据生成静态数据数组:

static const char file1[] = { '\x00`, `\x01`, ... } ;
static const char file2[] = { '\x00`, `\x01`, ... } ;
static struct
{
    const char* file ;
    int size ;
    int index ;
} files[] = { {file1, sizeof(file1), -1}, {file2, sizeof(file2), -1} } ;

然后 open() 变成这样:

int open(const char *name, int flags, int mode) 
{ 
    static const char* file_to_handle[] = { "file1", "file2", 0 } ;  // change names to match the FANN library names.

    int handle = -1 ;
    for( int h = 0; file_to_handle[h] != 0 && handle == -1; h++ )
    {
        if( strcmp( file_to_handle[h], name ) == 0 && files[h].index == -1 )
        {
            handle = h ;
            files[h].index = 0 ;
        }
    }
}

read() 实现:

int read(int file, char *ptr, int len) 
{
    int i = -1 ;
    if( files[file].index > 0 )
    {
        i = 0 ;
        while( files[file].index < files[file].size && i < len)
        {
            ptr[i] = files[file].index ;
            i++ ;
            files[file].index++ ;
        }
    }    
    return i ;
}

close()

int close(int file) 
{
    files[file].index = -1 ;
    return -1;
}

如果 FANN 使用随机访问文件,您可能还需要实施 lseek()。这只是一个操纵 files[file].index.

的问题

那应该给你一个最小的只读 "hard-coded" 文件系统。请注意,为清楚起见,我省略了检查句柄是否有效以及其他稳健性和安全性代码。鉴于实现的只读性质,您可能会或可能不会觉得有必要。此外,该代码旨在作为大纲并且未经测试 - 将其视为伪代码。

如果您不使用 newlib,毫无疑问,该库会有类似的重定向存根,或者您可以以类似的方式简单地覆盖或实现更高级别的功能 fopen() 等。

文件模型可能会占用大量内存,因为它会将 ROM 内存块复制到 RAM 中,否则您可以通过修改 FANN 库本身直接访问 ROM。

查看FANN源码,有一个函数需要重写,把fscanf换成sscanf,传入训练数据指针....

struct fann_train_data *fann_read_train_from_fd(FILE * file, const char *filename)
{
    unsigned int num_input, num_output, num_data, i, j;
    unsigned int line = 1;
    struct fann_train_data *data;

    if(fscanf(file, "%u %u %u\n", &num_data, &num_input, &num_output) != 3)
    {
        fann_error(NULL, FANN_E_CANT_READ_TD, filename, line);
        return NULL;
    }
    line++;

    data = fann_create_train(num_data, num_input, num_output);
    if(data == NULL)
    {
        return NULL;
    }

    for(i = 0; i != num_data; i++)
    {
        for(j = 0; j != num_input; j++)
        {
            if(fscanf(file, FANNSCANF " ", &data->input[i][j]) != 1)
            {
                fann_error(NULL, FANN_E_CANT_READ_TD, filename, line);
                fann_destroy_train(data);
                return NULL;
            }
        }
        line++;

        for(j = 0; j != num_output; j++)
        {
            if(fscanf(file, FANNSCANF " ", &data->output[i][j]) != 1)
            {
                fann_error(NULL, FANN_E_CANT_READ_TD, filename, line);
                fann_destroy_train(data);
                return NULL;
            }
        }
        line++;
    }
    return data;
}