summaryrefslogtreecommitdiff
path: root/ucoo
diff options
context:
space:
mode:
authorNicolas Schodet2015-10-09 15:25:15 +0200
committerNicolas Schodet2019-10-07 00:44:50 +0200
commit9b163537e83eea2c65358135dc180e7bf2da1a51 (patch)
tree7e9a66b57c868e5c1c82e42b8145cba7eed892cc /ucoo
parentf0c9501ae7945cbc3f20b0d92dddc3da0a99d280 (diff)
ucoo/base/fs/romfs: add ROM FS
Diffstat (limited to 'ucoo')
-rw-r--r--ucoo/base/fs/romfs/Module1
-rwxr-xr-xucoo/base/fs/romfs/mkromfs.py76
-rw-r--r--ucoo/base/fs/romfs/romfs.cc137
-rw-r--r--ucoo/base/fs/romfs/romfs.hh87
-rw-r--r--ucoo/base/fs/romfs/test/Makefile15
-rw-r--r--ucoo/base/fs/romfs/test/hello.txt6
-rw-r--r--ucoo/base/fs/romfs/test/test_romfs.cc75
7 files changed, 397 insertions, 0 deletions
diff --git a/ucoo/base/fs/romfs/Module b/ucoo/base/fs/romfs/Module
new file mode 100644
index 0000000..bfe39f6
--- /dev/null
+++ b/ucoo/base/fs/romfs/Module
@@ -0,0 +1 @@
+ucoo_base_fs_romfs_SOURCES = romfs.cc
diff --git a/ucoo/base/fs/romfs/mkromfs.py b/ucoo/base/fs/romfs/mkromfs.py
new file mode 100755
index 0000000..889d953
--- /dev/null
+++ b/ucoo/base/fs/romfs/mkromfs.py
@@ -0,0 +1,76 @@
+#!/usr/bin/python
+#
+"""Generate a ROM file system."""
+#
+# Copyright (C) 2015 Nicolas Schodet
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+# IN THE SOFTWARE.
+#
+import argparse
+import struct
+import sys
+
+p = argparse.ArgumentParser(description=__doc__)
+p.add_argument('-o', '--output', type=argparse.FileType('w'),
+ default=sys.stdout,
+ metavar='FILE', help='output file')
+p.add_argument('-i', '--header', metavar='VARNAME',
+ help='generate C header file')
+p.add_argument('file', nargs='*', help='file to put in file system')
+options = p.parse_args()
+
+files = options.file
+files.sort()
+
+magic = 0x466d6f52
+h = struct.pack('<II', magic, len(files))
+indexes = [0]
+contents = []
+
+index = 0
+for f in files:
+ index += len(f)
+ indexes.append(index)
+for f in files:
+ with open(f) as fd:
+ content = fd.read()
+ index += len(content)
+ indexes.append(index)
+ contents.append(content)
+
+indexes = struct.pack('<%dI' % len(indexes), *indexes)
+names = ''.join(files)
+contents = ''.join(contents)
+fs = ''.join((h, indexes, names, contents))
+
+if options.header:
+ pad = (len(fs) + 3) / 4 * 4 - len(fs)
+ if pad:
+ fs += struct.pack('B', 0) * pad
+ words = struct.unpack('<%dI' % (len(fs) / 4), fs)
+ lines = [ '/* Auto-generated ROM FS from:' ]
+ lines += [ ' * - %s' % f for f in files ]
+ lines += [ ' */', '', 'static const uint32_t %s[] = {' % options.header ]
+ for i in xrange(0, len(words), 4):
+ w = [ '0x%08x,' % i for i in words[i:i+4] ]
+ lines.append(' ' + ' '.join (w))
+ lines += [ '};' ]
+ options.output.write('\n'.join(lines))
+else:
+ options.output.write(fs)
diff --git a/ucoo/base/fs/romfs/romfs.cc b/ucoo/base/fs/romfs/romfs.cc
new file mode 100644
index 0000000..02b7603
--- /dev/null
+++ b/ucoo/base/fs/romfs/romfs.cc
@@ -0,0 +1,137 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2015 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/base/fs/romfs/romfs.hh"
+
+#include <algorithm>
+#include <cstring>
+
+namespace ucoo {
+
+
+RomFS::RomFSStream::RomFSStream (const char *begin, const char *end)
+ : begin_ (begin), end_ (end)
+{
+}
+
+int
+RomFS::RomFSStream::read (char *buf, int count)
+{
+ int l = std::min<int> (count, end_ - begin_);
+ if (!l)
+ return -2;
+ else
+ {
+ std::copy (begin_, begin_ + l, buf);
+ begin_ += l;
+ return l;
+ }
+}
+
+int
+RomFS::RomFSStream::write (const char *buf, int count)
+{
+ return -1;
+}
+
+int
+RomFS::RomFSStream::poll ()
+{
+ return end_ - begin_;
+}
+
+RomFS::RomFS (const uint32_t *addr, int size)
+{
+ ucoo::assert (size >= 12);
+ ucoo::assert (addr[0] == 0x466d6f52); // RomF
+ files_count_ = addr[1];
+ ucoo::assert (size >= 12 + 8 * files_count_);
+ filenames_ = &addr[2];
+ filecontents_ = &addr[2 + files_count_];
+ ucoo::assert (size >= 12 + 8 * files_count_
+ + static_cast<int> (filecontents_[files_count_]));
+ data_ = reinterpret_cast<const char *> (&addr[3 + 2 * files_count_]);
+}
+
+static int
+filename_compare (const char *a, int a_len, const char *b, int b_len)
+{
+ int bcmp = std::memcmp (a, b, std::min (a_len, b_len));
+ if (bcmp == 0)
+ return a_len - b_len;
+ else
+ return bcmp;
+}
+
+Stream *
+RomFS::open (const char *filename, Mode mode, Error &error)
+{
+ if (mode == Mode::WRITE)
+ {
+ error = Error::READ_ONLY;
+ return nullptr;
+ }
+ int filename_len = std::strlen (filename);
+ // Dichotomy search.
+ int begin = 0;
+ int end = files_count_;
+ while (begin != end)
+ {
+ int i = begin + (end - begin) / 2;
+ // Compare file name.
+ const char *i_name = data_ + filenames_[i];
+ int i_len = filenames_[i + 1] - filenames_[i];
+ int cmp = filename_compare (filename, filename_len, i_name, i_len);
+ if (cmp < 0)
+ end = i;
+ else if (cmp > 0)
+ begin = i + 1;
+ else
+ {
+ // Match.
+ const char *begin = data_ + filecontents_[i];
+ const char *end = data_ + filecontents_[i + 1];
+ RomFSStream *s = pool_.construct (begin, end);
+ if (!s)
+ error = Error::TOO_MANY_OPEN_FILES;
+ return s;
+ }
+ }
+ // Not found.
+ error = Error::NO_SUCH_FILE;
+ return nullptr;
+}
+
+void
+RomFS::close (Stream *file)
+{
+ pool_.destroy (static_cast<RomFSStream *> (file));
+}
+
+void
+RomFS::unlink (const char *filename)
+{
+ // This space is left intentionally blank.
+}
+
+} // namespace ucoo
diff --git a/ucoo/base/fs/romfs/romfs.hh b/ucoo/base/fs/romfs/romfs.hh
new file mode 100644
index 0000000..203e596
--- /dev/null
+++ b/ucoo/base/fs/romfs/romfs.hh
@@ -0,0 +1,87 @@
+#ifndef ucoo_base_fs_romfs_romfs_hh
+#define ucoo_base_fs_romfs_romfs_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2015 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/file_system.hh"
+#include "ucoo/utils/pool.hh"
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// Read only file system, read data from a buffer.
+///
+/// Buffer structure, little endian:
+/// u32: 'RomF'
+/// u32: number of files
+/// u32[n]: indexes in data buffer of file names, sorted by file names
+/// u32[n]: indexes in data buffer of file content
+/// u32: index in data buffer to first unused byte
+/// char[][n]: file names, not zero terminated
+/// char[][n]: file contents
+class RomFS : public FileSystem
+{
+ /// Stream from a romfs.
+ class RomFSStream : public Stream
+ {
+ public:
+ /// Constructor from a memory chunk.
+ RomFSStream (const char *begin, const char *end);
+ /// See Stream::read.
+ int read (char *buf, int count) override;
+ /// See Stream::write.
+ int write (const char *buf, int count) override;
+ /// See Stream::poll.
+ int poll () override;
+ private:
+ const char *begin_, *end_;
+ };
+ public:
+ /// Constructor, takes romfs address and size.
+ RomFS (const uint32_t *addr, int size);
+ /// See FileSystem::open.
+ Stream *open (const char *filename, Mode mode, Error &error) override;
+ Stream *open (const char *filename, Mode mode = Mode::READ)
+ {
+ return FileSystem::open (filename, mode);
+ }
+ /// See FileSystem::close.
+ void close (Stream *file) override;
+ /// See FileSystem::unlink, this is a no-op.
+ void unlink (const char *filename) override;
+ private:
+ /// Number of files.
+ int files_count_;
+ /// File names indexes.
+ const uint32_t *filenames_;
+ /// File contents indexes.
+ const uint32_t *filecontents_;
+ /// Byte array with file names and contents.
+ const char *data_;
+ /// Pool of stream.
+ Pool<RomFSStream, 5> pool_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_base_fs_romfs_romfs_hh
diff --git a/ucoo/base/fs/romfs/test/Makefile b/ucoo/base/fs/romfs/test/Makefile
new file mode 100644
index 0000000..c4ec6bc
--- /dev/null
+++ b/ucoo/base/fs/romfs/test/Makefile
@@ -0,0 +1,15 @@
+BASE = ../../../../..
+
+TARGETS = host stm32f4
+PROGS = test_romfs
+test_romfs_SOURCES = test_romfs.cc
+
+MODULES = ucoo/base/test ucoo/base/fs/romfs ucoo/hal/usb
+
+COMPILE_DEPS = $(OBJDIR)/test_fs.h
+EXTRA_CLEAN = $(OBJDIR)/test_fs.h
+
+include $(BASE)/build/top.mk
+
+$(OBJDIR)/test_fs.h: ../mkromfs.py hello.txt
+ $< -o $@ -i test_fs $(wordlist 2,$(words $^),$^)
diff --git a/ucoo/base/fs/romfs/test/hello.txt b/ucoo/base/fs/romfs/test/hello.txt
new file mode 100644
index 0000000..ad59a4f
--- /dev/null
+++ b/ucoo/base/fs/romfs/test/hello.txt
@@ -0,0 +1,6 @@
+Hello world!
+ Hello world!
+ Hello world!
+ Hello world!
+ Hello world!
+ Hello world!
diff --git a/ucoo/base/fs/romfs/test/test_romfs.cc b/ucoo/base/fs/romfs/test/test_romfs.cc
new file mode 100644
index 0000000..9328bc9
--- /dev/null
+++ b/ucoo/base/fs/romfs/test/test_romfs.cc
@@ -0,0 +1,75 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2015 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/base/fs/romfs/romfs.hh"
+#include "ucoo/arch/arch.hh"
+#include "ucoo/base/test/test.hh"
+
+#include "test_fs.h"
+#include <cstdio>
+
+int
+main (int argc, const char **argv)
+{
+ ucoo::arch_init (argc, argv);
+ ucoo::test_stream_setup ();
+ ucoo::RomFS romfs (test_fs, sizeof (test_fs));
+ romfs.enable ();
+ ucoo::Stream *s = romfs.open ("hello.txt");
+ if (s)
+ {
+ while (1)
+ {
+ char buf[32];
+ int r = s->read (buf, sizeof (buf));
+ if (r <= 0)
+ {
+ if (r != -2)
+ printf ("\nread error\n");
+ break;
+ }
+ else
+ fwrite (buf, r, 1, stdout);
+ }
+ printf ("\ndone\n");
+ romfs.close (s);
+ }
+ else
+ printf ("open error\n");
+ FILE *f = fopen ("hello.txt", "r");
+ if (f)
+ {
+ while (1)
+ {
+ int c = fgetc (f);
+ if (c == EOF)
+ break;
+ else
+ putchar (c);
+ }
+ printf ("\ndone\n");
+ fclose (f);
+ }
+ else
+ printf ("fopen error\n");
+}