-
Notifications
You must be signed in to change notification settings - Fork 14
lib shell
jmattsson edited this page Jan 19, 2012
·
3 revisions
Patch for lib/shell for future reference.
GitHub's wiki is really ticking me off... it shows up fine on the preview, but hit Save and it all shrinks up to a single-line. /facepalm
diff --git a/apps/tests/TestSerialShell/BusyShellCmdC.nc b/apps/tests/TestSerialShell/BusyShellCmdC.nc
new file mode 100644==
index 0000000..2c3b3eb
--- /dev/null
+++ b/apps/tests/TestSerialShell/BusyShellCmdC.nc
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module BusyShellCmdC
+{
+ provides interface ShellExecute;
+ uses interface ShellOutput;
+}
+implementation
+{
+ command error_t ShellExecute.execute (uint8_t argc, const char *argv[])
+ {
+ return EBUSY;
+ }
+
+ command void ShellExecute.abort () {}
+
+ event void ShellOutput.outputDone () {}
+}
diff --git a/apps/tests/TestSerialShell/CancelmeShellCmdC.nc b/apps/tests/TestSerialShell/CancelmeShellCmdC.nc
new file mode 100644
index 0000000..cfaf7f1
--- /dev/null
+++ b/apps/tests/TestSerialShell/CancelmeShellCmdC.nc
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module CancelmeShellCmdC
+{
+ provides interface ShellExecute;
+ uses interface ShellOutput;
+}
+implementation
+{
+ command error_t ShellExecute.execute (uint8_t argc, const char *argv[])
+ {
+ return SUCCESS;
+ }
+
+ command void ShellExecute.abort ()
+ {
+ signal ShellExecute.executeDone (ECANCEL);
+ }
+
+ event void ShellOutput.outputDone () {}
+}
diff --git a/apps/tests/TestSerialShell/Makefile b/apps/tests/TestSerialShell/Makefile
new file mode 100644
index 0000000..a31f900
--- /dev/null
+++ b/apps/tests/TestSerialShell/Makefile
@@ -0,0 +1,5 @@
+COMPONENT=TestSerialShellC
+
+CFLAGS += -I$(TOSDIR)/lib/shell -I$(TOSDIR)/lib/shell/preconf
+
+include $(MAKERULES)
diff --git a/apps/tests/TestSerialShell/README b/apps/tests/TestSerialShell/README
new file mode 100644
index 0000000..7b0c661
--- /dev/null
+++ b/apps/tests/TestSerialShell/README
@@ -0,0 +1,4 @@
+A small application demonstrating how to use lib/shell to put together
+a serial command line shell easily.
+
+Also see tos/lib/shell for examples on how to implement actual shell commands.
diff --git a/apps/tests/TestSerialShell/TestSerialShellC.nc b/apps/tests/TestSerialShell/TestSerialShellC.nc
new file mode 100644
index 0000000..912a86f
--- /dev/null
+++ b/apps/tests/TestSerialShell/TestSerialShellC.nc
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ShellCommand.h"
+
+configuration TestSerialShellC
+{
+}
+implementation
+{
+ components TestSerialShellP as App, MainC, PlatformSerialC;
+ App.Boot -> MainC;
+ App.UartStream -> PlatformSerialC;
+
+ // Pre-configured serial commands
+ components HelpSerialCmdC, UptimeSerialCmdC;
+
+
+ // Custom commands with hand-wiring. Note naming of PlatformSerialShellC.
+ components PlatformSerialShellC as SerialShell;
+ components BusyShellCmdC, CancelmeShellCmdC;
+
+ WIRE_SHELL_COMMAND("busy", BusyShellCmdC, SerialShell);
+ WIRE_SHELL_COMMAND("cancelme", CancelmeShellCmdC, SerialShell);
+}
diff --git a/apps/tests/TestSerialShell/TestSerialShellP.nc b/apps/tests/TestSerialShell/TestSerialShellP.nc
new file mode 100644
index 0000000..816ac9d
--- /dev/null
+++ b/apps/tests/TestSerialShell/TestSerialShellP.nc
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+module TestSerialShellP
+{
+ uses interface Boot;
+ uses interface UartStream;
+}
+implementation
+{
+ event void Boot.booted ()
+ {
+ const char msg[] = "TestSerialShell Booted\r\n";
+ call UartStream.send ((uint8_t *)msg, sizeof(msg) -1);
+ }
+
+ async event void UartStream.receivedByte (uint8_t byte) {}
+ async event void UartStream.sendDone (uint8_t *buf, uint16_t len, error_t res) {}
+ async event void UartStream.receiveDone (uint8_t *buf, uint16_t len, error_t res) {}
+}
diff --git a/apps/tests/TestVariantPool/Makefile b/apps/tests/TestVariantPool/Makefile
new file mode 100644
index 0000000..cdf021e
--- /dev/null
+++ b/apps/tests/TestVariantPool/Makefile
@@ -0,0 +1,4 @@
+COMPONENT=TestAppC
+PFLAGS += -I$(TOSDIR)/lib/printf
+#CFLAGS += -DVARIANT_POOL_DEBUG
+include $(MAKERULES)
diff --git a/apps/tests/TestVariantPool/TestAppC.nc b/apps/tests/TestVariantPool/TestAppC.nc
new file mode 100644
index 0000000..1f12281
--- /dev/null
+++ b/apps/tests/TestVariantPool/TestAppC.nc
@@ -0,0 +1,12 @@
+configuration TestAppC {
+} implementation {
+ components TestP;
+ components MainC;
+
+ TestP.Boot -> MainC;
+
+ components new VariantPoolC (64) as VPool;
+ TestP.VPool -> VPool;
+
+#include <unittest/config_impl.h>
+}
diff --git a/apps/tests/TestVariantPool/TestP.nc b/apps/tests/TestVariantPool/TestP.nc
new file mode 100644
index 0000000..4062f79
--- /dev/null
+++ b/apps/tests/TestVariantPool/TestP.nc
@@ -0,0 +1,76 @@
+#include <stdio.h>
+
+module TestP {
+ uses interface Boot;
+ uses interface VariantPool as VPool;
+#include <unittest/module_spec.h>
+} implementation {
+#include <unittest/module_impl.h>
+
+#define POOL_SIZE (64 - 2)
+
+ void assert_available (size_t size)
+ {
+ void *t;
+ size_t lt = 0;
+ t = call VPool.reserve (<);
+ ASSERT_TRUE(t != NULL);
+ ASSERT_TRUE(lt = size);
+ call VPool.release (t);
+ }
+
+ event void Boot.booted () {
+ void *a1, *a2, *a3;
+ size_t l1, l2, l3;
+
+ // Reserve full pool
+ a1 = call VPool.reserve (&l1);
+ ASSERT_TRUE(a1 != NULL);
+ ASSERT_EQUAL(l1, POOL_SIZE);
+
+ // Reserve from empty pool
+ l2 = 0xfade;
+ a2 = call VPool.reserve (&l2);
+ ASSERT_TRUE(!a2);
+ ASSERT_EQUAL(l2, 0xfade); // a failed reserve should not touch len ptr
+
+ // Alloc from empty pool
+ a2 = call VPool.alloc (1);
+ ASSERT_TRUE(!a2);
+ ASSERT_EQUAL(l2, 0xfade); // a failed alloc should not touch len ptr
+
+ // Reduce reservation
+ l1 = 4;
+ call VPool.reduce (a1, l1);
+ a2 = call VPool.reserve (&l2);
+ ASSERT_TRUE(a2 != NULL);
+ ASSERT_EQUAL(l2, POOL_SIZE - l1 - 2);
+
+ // Alloc from empty pool
+ l3 = 1;
+ a3 = call VPool.alloc (l3);
+ ASSERT_TRUE(!a3);
+
+ // Reduce reservation
+ l2 = 15;
+ call VPool.reduce (a2, l2);
+
+ // Alloc from pool
+ l3 = 34;
+ a3 = call VPool.alloc (l3);
+ ASSERT_TRUE(a3 != NULL);
+
+ // Release in order a3, a1, a2 to exercise most merge scenarios
+ call VPool.release (a3);
+ assert_available (POOL_SIZE - l1 - l2 - 2*2);
+
+ call VPool.release (a1);
+ // a1 was only a small unmerged chunk, should have no impact on reserve
+ assert_available (POOL_SIZE - l1 - l2 - 2*2);
+
+ call VPool.release (a2);
+ assert_available (POOL_SIZE);
+
+ ALL_TESTS_PASSED();
+ }
+}
diff --git a/tos/interfaces/VariantPool.nc b/tos/interfaces/VariantPool.nc
new file mode 100644
index 0000000..e0be2a4
--- /dev/null
+++ b/tos/interfaces/VariantPool.nc
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * The VariantPool is an alternative to Pool and malloc(). It provides access
+ * to a compile-time bounded memory area (unlike malloc), but unlike Pool
+ * it allows allocations of varying sizes.
+ *
+ * Additionally, it provides the capability for allocations of unknown size
+ * via the reserve() function. Calling reserve() allocates as much contiguous
+ * memory in the pool that it can, and returns it and the actual size
+ * allocated. When the desired size is learnt, the allocation can (and should)
+ * then be reduced to said size by calling reduce(). This releases the excess
+ * memory back into the pool. A typical use case for this is for formatting
+ * buffers, where temporary memory is desired for short periods of time.
+ *
+ * Any memory obtained from alloc() or reserve() MUST be released back to the
+ * pool through release(). Calling reduce(p, 0) is NOT a substitute.
+ */
+interface VariantPool
+{
+ /**
+ * Allocates memory of the requested size from the pool, if possible.
+ * Any memory allocated MUST Be returned to the pool by calling release().
+ *
+ * @param len The length (in bytes) of memory requested.
+ * @return A pointer to the allocated memory, or zero if the allocation
+ * request could not be satisfied.
+ */
+ command void *alloc (size_t len);
+
+ /**
+ * Allocates as much contiguous memory from the pool as it can, possibly
+ * the entirety of the pool. Memory allocated this way SHOULD be reduced
+ * to the minimum required as soon as said minimum is discovered. This
+ * SHOULD happen before the current task completes (as doing otherwise
+ * might leave other tasks starved).
+ *
+ * @param actual_len A pointer to a length field where the actual allocation
+ * length will be stored. Only updated if memory is actually reserved.
+ * @return A pointer to the allocated memory, or zero if the request could
+ * not be satisfied.
+ */
+ command void *reserve (size_t *actual_len);
+
+ /**
+ * Reduces previously reserved (or allocated) memory to a smaller size,
+ * returning the excess memory to the pool.
+ *
+ * @param p Pointer to memory previously obtained from alloc() or reserve().
+ * @param newlen The size to reduce the allocation to. It is not possible
+ * to increase the allocation by supplying a larger size than originally
+ * allocated.
+ */
+ command void reduce (void *p, size_t newlen);
+
+ /**
+ * Returns previously allocated memory to the pool.
+ *
+ * @param p The memory to return to the pool. MUST have been previously
+ * returned from alloc() or reserve().
+ */
+ command void release (void *p);
+}
diff --git a/tos/lib/shell/CommandLineParser.nc b/tos/lib/shell/CommandLineParser.nc
new file mode 100644
index 0000000..4b3daa6
--- /dev/null
+++ b/tos/lib/shell/CommandLineParser.nc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface CommandLineParser
+{
+ /**
+ * Parses the contents of a zero-terminated character buffer, splitting it
+ * into arguments and building up an argc/argv pair.
+ *
+ * @param str Pointer to the string to parse. MUST be zero-terminated.
+ * @param argc In: contains the length of the argv array.
+ * Out: number of entries used in argv.
+ * @param argv The argv array, to receive the argument pointers.
+ * @return SUCCESS if the string could be parsed.
+ */
+ command error_t parse (char *str, uint8_t *argc, char *argv[]);
+}
diff --git a/tos/lib/shell/HelpShellCmdC.nc b/tos/lib/shell/HelpShellCmdC.nc
new file mode 100644
index 0000000..48bdddf
--- /dev/null
+++ b/tos/lib/shell/HelpShellCmdC.nc
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+generic configuration HelpShellCmdC()
+{
+ provides interface ShellExecute;
+ uses interface ShellCommand as CommandList[uint8_t id];
+ uses interface ShellOutput;
+}
+implementation
+{
+ components new HelpShellCmdP() as Cmd, ScratchAreaC;
+
+ Cmd.Scratch -> ScratchAreaC;
+
+ ShellExecute = Cmd;
+ ShellOutput = Cmd;
+ CommandList = Cmd;
+}
diff --git a/tos/lib/shell/HelpShellCmdP.nc b/tos/lib/shell/HelpShellCmdP.nc
new file mode 100644
index 0000000..0a8ac24
--- /dev/null
+++ b/tos/lib/shell/HelpShellCmdP.nc
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+generic module HelpShellCmdP()
+{
+ provides interface ShellExecute;
+ uses interface ShellOutput;
+ uses interface ShellCommand[uint8_t id];
+ uses interface VariantPool as Scratch;
+}
+implementation
+{
+ char *buf = 0;
+
+ command error_t ShellExecute.execute (uint8_t argc, const char *argv[])
+ {
+ size_t len = 0;
+ uint8_t id = 0;
+ char *p;
+ int ret;
+
+ if (buf)
+ return EBUSY;
+
+ buf = p = call Scratch.reserve (&len);
+
+ while (len)
+ {
+ const char *str = call ShellCommand.getCommandString[id++] ();
+ if (!str || !*str)
+ break;
+
+ ret = snprintf (p, len, "%s\r\n", str);
+ if (ret <= 0 || (ret > len))
+ break;
+
+ len -= ret;
+ p += ret;
+ }
+
+ call Scratch.reduce (buf, p - buf);
+ return call ShellOutput.output (buf, p - buf);
+ }
+
+ command void ShellExecute.abort () {}
+
+ event void ShellOutput.outputDone ()
+ {
+ call Scratch.release (buf);
+ buf = 0;
+ signal ShellExecute.executeDone (SUCCESS);
+ }
+}
diff --git a/tos/lib/shell/README b/tos/lib/shell/README
new file mode 100644
index 0000000..060ce48
--- /dev/null
+++ b/tos/lib/shell/README
@@ -0,0 +1,57 @@
+The lib/shell components provide a (hopefully) convenient way of implementing
+simple command shells.
+
+It was inspired by lib/net/blip/shell, but differs in the following ways:
+
+ * Command execution is split-phase. Long running commands are easy to
+ implement, as executeDone() must be signalled to allow the next command
+ to be processed by the shell.
+
+ * Commands may be interrupted/aborted. Long running commands can thus
+ stop reposting themselves, and signal early completion (ECANCEL).
+
+ * Command output is split-phase. Commands wishing to return lots of
+ information can simply wait to be told when it's possible to output
+ the next chunk of data. Obtaining the maximum chunk of output possible
+ in each go is also supported, allowing commands to optimize their
+ output (e.g. to maximize payload/headers ratio for network shells).
+
+ * Support for different types of shells are possible, e.g. serial, UDP.
+ A command does not need to know what type of shell it will be used with.
+
+ * With care, commands can be shared across multiple shells (just be
+ careful to either support reentrancy or disallow it altogether).
+
+ * The output interface is separate from the command interface, and can be
+ wired to support diagnostics/snooping of command activity, or even
+ support blind terminals.
+
+ * Command line parsing is delegated to its own module, allowing for easy
+ extension of features if so desired (environment vars, loops, etc).
+
+ * Limited interactive line editing supported in the SerialShellC.
+ Non-interactive shell types (e.g. UDP-based ones) don't need this,
+ and don't incur the overhead of this support.
+
+Of course, there are some downsides:
+
+ * Increased wiring requirements. As there can be more than one shell,
+ commands cannot auto-wire themselves to The One True Shell.
+ To alleviate this, the macros in ShellCommand.h abstract away the
+ intricacies, and pre-configured components can be provided for the
+ typical use case (e.g. single UDP shell or serial interface using
+ PlatformSerialC).
+
+ * To support multiple concurrent shells, the commands must be written
+ to handle reentrancy. For long-running/posting commands, this involves
+ keeping extra state around, or alternatively they can simply detect
+ attempts at reentrancy and return EBUSY.
+
+ * If the output is fanned out, a lot of care must be taken to not send
+ multiple outputDone() signals, or to reference the output string after
+ an outputDone() event has been signalled. Diagnostic/snoop wiring
+ should be passive (not signal outputDone()), and copy the output into
+ its own buffers straight away.
+
+For an example of how to make use of lib/shell, have a look at the
+TestSerialShell application in apps/tests/TestSerialShell.
diff --git a/tos/lib/shell/SerialShellC.nc b/tos/lib/shell/SerialShellC.nc
new file mode 100644
index 0000000..1024850
--- /dev/null
+++ b/tos/lib/shell/SerialShellC.nc
@@ -0,0 +1,266 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+generic module SerialShellC(uint8_t num_cmds)
+{
+ provides interface Init;
+ provides interface ShellOutput[uint8_t id];
+ provides interface ShellCommand as CommandList[uint8_t id];
+
+ uses interface ShellCommand[uint8_t id];
+ uses interface ShellExecute[uint8_t id];
+ uses interface CommandLineParser;
+ uses interface UartStream;
+}
+implementation
+{
+ enum { NO_CMD = 0xff };
+ enum { ABORT_KEY = 0x03 }; // ctrl-c
+
+ typedef enum {
+ PROMPT_BARE, PROMPT_OK, PROMPT_BUSY, PROMPT_FAIL, PROMPT_ABORT,
+ PROMPT_UNKNOWN, PROMPT_SYNTAX
+ } prompt_t;
+
+ prompt_t new_prompt;
+
+ uint8_t cur_cmd = NO_CMD;
+ bool printing_prompt = FALSE;
+ volatile bool buffer_locked = FALSE;
+
+ #ifndef SERIAL_SHELL_BUFFER_SIZE
+ #define SERIAL_SHELL_BUFFER_SIZE 80
+ #endif
+
+ char recv_buf[SERIAL_SHELL_BUFFER_SIZE] = { 0 };
+ char *rx = recv_buf;
+
+ #ifndef SERIAL_SHELL_MAX_ARGS
+ #define SERIAL_SHELL_MAX_ARGS 9
+ #endif
+
+ char *argv[SERIAL_SHELL_MAX_ARGS];
+
+ void print_prompt (prompt_t type)
+ {
+ static const char *prompts[] = {
+ "# ",
+ "OK\r\n# ",
+ "BUSY\r\n# ",
+ "FAILED\r\n# ",
+ "^C\r\n# ",
+ "UNKNOWN\r\n# ",
+ "SYNTAX ERROR\r\n# "
+ };
+ const char *prompt = prompts[type];
+
+ printing_prompt =
+ (call UartStream.send ((uint8_t *)prompt, strlen (prompt)) == SUCCESS) ?
+ TRUE : FALSE;
+ }
+
+ inline prompt_t error_to_prompt (error_t result)
+ {
+ switch (result)
+ {
+ case SUCCESS: return PROMPT_OK;
+ case EBUSY: return PROMPT_BUSY;
+ case ECANCEL: return PROMPT_ABORT;
+ default: return PROMPT_FAIL;
+ }
+ }
+
+ task void cmd_exit ()
+ {
+ print_prompt (new_prompt);
+ if (!printing_prompt)
+ {
+ post cmd_exit ();
+ return;
+ }
+ }
+
+ command error_t Init.init ()
+ {
+ return call UartStream.enableReceiveInterrupt ();
+ }
+
+
+ command error_t ShellOutput.output[uint8_t id] (const char *str, size_t len)
+ {
+ if (id != cur_cmd)
+ return SUCCESS; // Note: use SUCCESS to work with ecombine nicely
+ else
+ return call UartStream.send ((uint8_t *)str, len);
+ }
+
+ command size_t ShellOutput.limit[uint8_t id] ()
+ {
+ // We don't need to buffer/packetize the output, so no real limit
+ return (size_t)-1;
+ }
+
+ event void ShellExecute.executeDone[uint8_t id] (error_t result)
+ {
+ if (id != cur_cmd)
+ return; // not our execute
+
+ new_prompt = error_to_prompt (result);
+ post cmd_exit ();
+ }
+
+
+ task void abort_requested ()
+ {
+ if (cur_cmd != NO_CMD)
+ call ShellExecute.abort[cur_cmd] ();
+ else
+ print_prompt (PROMPT_ABORT);
+ }
+
+ task void output_done ()
+ {
+ if (printing_prompt)
+ {
+ printing_prompt = FALSE;
+ cur_cmd = NO_CMD;
+ atomic buffer_locked = FALSE;
+ }
+ else
+ if (cur_cmd != NO_CMD)
+ signal ShellOutput.outputDone[cur_cmd] ();
+ }
+
+ task void parse_command ()
+ {
+ uint8_t argc = SERIAL_SHELL_MAX_ARGS;
+ error_t res =
+ call CommandLineParser.parse (recv_buf, &argc, argv);
+
+ if (res == SUCCESS)
+ {
+ uint8_t i;
+
+ if (!argc || !*argv[0]) // no command, just reprint prompt
+ {
+ new_prompt = PROMPT_BARE;
+ goto no_run;
+ }
+
+ for (i = 0; i < num_cmds; ++i)
+ {
+ if (strcmp (argv[0], call ShellCommand.getCommandString[i] ()) == 0)
+ break;
+ }
+
+ if (i == num_cmds)
+ new_prompt = PROMPT_UNKNOWN; // command not found
+ else
+ {
+ error_t result;
+ cur_cmd = i;
+ result = call ShellExecute.execute[i] (argc, (const char **)argv);
+ if (result == SUCCESS)
+ return; // now running a command
+ new_prompt = error_to_prompt (result);
+ }
+ }
+ else
+ new_prompt = PROMPT_SYNTAX;
+
+ no_run:
+ post cmd_exit ();
+ }
+
+
+ async event void UartStream.sendDone (uint8_t *buf, uint16_t len, error_t res)
+ {
+ post output_done ();
+ }
+
+ async event void UartStream.receiveDone (uint8_t *buf, uint16_t len, error_t res) {}
+
+ async event void UartStream.receivedByte (uint8_t byte)
+ {
+ if (byte == ABORT_KEY)
+ {
+ rx = recv_buf;
+ post abort_requested ();
+ return;
+ }
+
+ if (buffer_locked)
+ return;
+
+ if (byte < ' ' || byte == 0x7f)
+ {
+ switch (byte)
+ {
+ case 0x08: // Backspace
+ case 0x7f: // Delete
+ if (rx > recv_buf)
+ --rx;
+ break;
+ case '\r':
+ case '\n':
+ *rx = 0;
+ rx = recv_buf;
+ buffer_locked = TRUE;
+ post parse_command ();
+ break;
+ default: break;
+ }
+ return;
+ }
+
+ if (rx < (recv_buf + sizeof (recv_buf) -1))
+ *rx++ = byte;
+ }
+
+ command const char *CommandList.getCommandString[uint8_t id] ()
+ {
+ return call ShellCommand.getCommandString[id] ();
+ }
+
+ default command const char *ShellCommand.getCommandString[uint8_t id] ()
+ {
+ return "";
+ }
+
+ default command error_t ShellExecute.execute[uint8_t id] (uint8_t argc, const char *argv_[])
+ {
+ return FAIL;
+ }
+
+ default command void ShellExecute.abort[uint8_t id] () {}
+ default event void ShellOutput.outputDone[uint8_t id] () {}
+}
diff --git a/tos/lib/shell/ShellCommand.h b/tos/lib/shell/ShellCommand.h
new file mode 100644
index 0000000..b35b6cb
--- /dev/null
+++ b/tos/lib/shell/ShellCommand.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SHELL_COMMAND_H_
+#define _SHELL_COMMAND_H_
+
+#define WIRE_SHELL_COMMAND(cmdstring, component, shell) \
+ enum { SHELL_CMD_ ## component = unique("shell.cmd." #shell) }; \
+ components new ShellCommandC (cmdstring) as ShellCommand_ ## component; \
+ shell.ShellCommand[SHELL_CMD_ ## component] -> ShellCommand_ ## component; \
+ shell.ShellExecute[SHELL_CMD_ ## component] -> component; \
+ shell.ShellOutput[SHELL_CMD_ ## component] <- component
+
+#define NUM_COMMANDS_FOR_SHELL(shell) uniqueCount("shell.cmd." #shell)
+
+#endif
diff --git a/tos/lib/shell/ShellCommand.nc b/tos/lib/shell/ShellCommand.nc
new file mode 100644
index 0000000..38396e3
--- /dev/null
+++ b/tos/lib/shell/ShellCommand.nc
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface ShellCommand
+{
+ command const char *getCommandString ();
+}
diff --git a/tos/lib/shell/ShellCommandC.nc b/tos/lib/shell/ShellCommandC.nc
new file mode 100644
index 0000000..65d3c13
--- /dev/null
+++ b/tos/lib/shell/ShellCommandC.nc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+generic module ShellCommandC(const char commandString[])
+{
+ provides interface ShellCommand;
+}
+implementation
+{
+ command const char *ShellCommand.getCommandString ()
+ {
+ return commandString;
+ }
+}
diff --git a/tos/lib/shell/ShellExecute.nc b/tos/lib/shell/ShellExecute.nc
new file mode 100644
index 0000000..ee36c86
--- /dev/null
+++ b/tos/lib/shell/ShellExecute.nc
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface ShellExecute
+{
+ command error_t execute (uint8_t argc, const char *argv[]);
+
+ // note: must still signal executeDone()
+ command void abort ();
+
+ event void executeDone (error_t result);
+}
diff --git a/tos/lib/shell/ShellOutput.nc b/tos/lib/shell/ShellOutput.nc
new file mode 100644
index 0000000..3d8b034
--- /dev/null
+++ b/tos/lib/shell/ShellOutput.nc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+interface ShellOutput
+{
+ command error_t output (const char *str, size_t len);
+
+ // note: only signalled if outputn returned SUCCESS
+ event void outputDone ();
+
+ // maximum length output which can be successfully submitted
+ command size_t limit ();
+}
diff --git a/tos/lib/shell/SimpleCommandParserC.nc b/tos/lib/shell/SimpleCommandParserC.nc
new file mode 100644
index 0000000..5604e83
--- /dev/null
+++ b/tos/lib/shell/SimpleCommandParserC.nc
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * A simple command line parser, supporting double-quotes and backslash
+ * escapes. Only the <space> character is considered a delimiter.
+ */
+generic module SimpleCommandParserC()
+{
+ provides interface CommandLineParser;
+}
+implementation
+{
+
+ command error_t CommandLineParser.parse (char *str, uint8_t *argc, char *argv[])
+ {
+ uint8_t max_args = *argc;
+ char *p;
+ bool escaped = FALSE, inquote = FALSE, inspace = TRUE;
+
+ *argc = 0;
+
+ for (p = str; *p && *argc < max_args; ++p)
+ {
+ if (escaped)
+ {
+ escaped = FALSE;
+ continue;
+ }
+ if (*p == ' ' && !inquote && !escaped)
+ {
+ inspace = TRUE;
+ *p = 0;
+ continue;
+ }
+ if (inspace && !escaped && *p != ' ')
+ {
+ inspace = FALSE;
+ argv[(*argc)++] = p;
+ continue;
+ }
+ if (*p == '\\')
+ {
+ escaped = TRUE;
+ continue;
+ }
+ if (*p == '"')
+ {
+ inquote = TRUE;
+ continue;
+ }
+ }
+
+ if (escaped || inquote)
+ return EINVAL;
+ else if (*p)
+ return ENOMEM;
+ else
+ return SUCCESS;
+ }
+
+}
diff --git a/tos/lib/shell/UptimeShellCmdC.nc b/tos/lib/shell/UptimeShellCmdC.nc
new file mode 100644
index 0000000..a1f67d0
--- /dev/null
+++ b/tos/lib/shell/UptimeShellCmdC.nc
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+configuration UptimeShellCmdC
+{
+ provides interface ShellExecute;
+ uses interface ShellOutput;
+}
+implementation
+{
+ components UptimeShellCmdP as Cmd, LocalTimeMilliC, ScratchAreaC;
+
+ Cmd.LocalTime -> LocalTimeMilliC;
+ Cmd.Scratch -> ScratchAreaC;
+
+ ShellExecute = Cmd;
+ ShellOutput = Cmd;
+}
diff --git a/tos/lib/shell/UptimeShellCmdP.nc b/tos/lib/shell/UptimeShellCmdP.nc
new file mode 100644
index 0000000..6e2e505
--- /dev/null
+++ b/tos/lib/shell/UptimeShellCmdP.nc
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+
+module UptimeShellCmdP
+{
+ provides interface ShellExecute;
+ uses interface ShellOutput;
+ uses interface LocalTime<TMilli>;
+ uses interface VariantPool as Scratch;
+}
+implementation
+{
+ char *buf = 0;
+
+ command error_t ShellExecute.execute (uint8_t argc, const char *argv[])
+ {
+ size_t len = 0;
+ int ret;
+
+ if (buf)
+ return EBUSY;
+
+ buf = call Scratch.reserve (&len);
+ ret = snprintf (buf, len, "Uptime: %lus\r\n", call LocalTime.get () >> 10);
+ if (ret <= 0)
+ {
+ call Scratch.release (buf);
+ return FAIL;
+ }
+
+ call Scratch.reduce (buf, ret);
+ return call ShellOutput.output (buf, ret);
+ }
+
+ command void ShellExecute.abort () {}
+
+ event void ShellOutput.outputDone ()
+ {
+ call Scratch.release (buf);
+ buf = 0;
+ signal ShellExecute.executeDone (SUCCESS);
+ }
+}
diff --git a/tos/lib/shell/preconf/HelpSerialCmdC.nc b/tos/lib/shell/preconf/HelpSerialCmdC.nc
new file mode 100644
index 0000000..4308dc9
--- /dev/null
+++ b/tos/lib/shell/preconf/HelpSerialCmdC.nc
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ShellCommand.h"
+
+configuration HelpSerialCmdC
+{
+}
+implementation
+{
+ components PlatformSerialShellC as SerialShell, new HelpShellCmdC();
+ WIRE_SHELL_COMMAND("help", HelpShellCmdC, SerialShell);
+ HelpShellCmdC.CommandList -> SerialShell;
+}
diff --git a/tos/lib/shell/preconf/PlatformSerialShellC.nc b/tos/lib/shell/preconf/PlatformSerialShellC.nc
new file mode 100644
index 0000000..857ad02
--- /dev/null
+++ b/tos/lib/shell/preconf/PlatformSerialShellC.nc
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * Provides a pre-wired serial shell, using PlatformSerialC.
+ *
+ * The name to register commands against is SerialShell, e.g.:
+ * components PlatformSerialShellC as SerialShell;
+ * WIRE_SHELL_COMMAND("mycmd", MyCmdC, SerialShell);
+ */
+configuration PlatformSerialShellC
+{
+ provides interface ShellOutput[uint8_t id];
+ provides interface ShellCommand as CommandList[uint8_t id];
+
+ uses interface ShellCommand[uint8_t id];
+ uses interface ShellExecute[uint8_t id];
+}
+implementation
+{
+ components
+ new SerialShellC(NUM_COMMANDS_FOR_SHELL(SerialShell)) as SerialShell,
+ new SimpleCommandParserC(),
+ PlatformSerialC,
+ MainC;
+
+ SerialShell.UartStream -> PlatformSerialC;
+ SerialShell.CommandLineParser -> SimpleCommandParserC;
+ SerialShell.Init <- MainC.SoftwareInit;
+
+ ShellOutput = SerialShell.ShellOutput;
+ CommandList = SerialShell.CommandList;
+
+ ShellCommand = SerialShell.ShellCommand;
+ ShellExecute = SerialShell.ShellExecute;
+}
diff --git a/tos/lib/shell/preconf/UptimeSerialCmdC.nc b/tos/lib/shell/preconf/UptimeSerialCmdC.nc
new file mode 100644
index 0000000..73a6735
--- /dev/null
+++ b/tos/lib/shell/preconf/UptimeSerialCmdC.nc
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "ShellCommand.h"
+
+configuration UptimeSerialCmdC
+{
+}
+implementation
+{
+ components PlatformSerialShellC as SerialShell, UptimeShellCmdC;
+ WIRE_SHELL_COMMAND("uptime", UptimeShellCmdC, SerialShell);
+}
diff --git a/tos/system/ScratchAreaC.nc b/tos/system/ScratchAreaC.nc
new file mode 100644
index 0000000..f59073d
--- /dev/null
+++ b/tos/system/ScratchAreaC.nc
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+configuration ScratchAreaC
+{
+ provides interface VariantPool;
+}
+implementation
+{
+ components new VariantPoolC(128) as Scratch;
+ VariantPool = Scratch;
+}
diff --git a/tos/system/VariantPoolC.nc b/tos/system/VariantPoolC.nc
new file mode 100644
index 0000000..05ecf58
--- /dev/null
+++ b/tos/system/VariantPoolC.nc
@@ -0,0 +1,216 @@
+/*
+ * Copyright (c) 2012 Johny Mattsson
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * - Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the
+ * distribution.
+ * - Neither the name of the copyright holders nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+generic module VariantPoolC(size_t pool_size)
+{
+ provides interface VariantPool;
+}
+implementation
+{
+ typedef struct list_node
+ {
+ size_t len; // space available to user (i.e. excluding this field)
+ struct list_node *next; // link field, also start of user data when alloc'd
+ } list_node_t;
+
+ union {
+ list_node_t first_node;
+ char raw[pool_size];
+ } pool = { { pool_size - sizeof (size_t), 0 } };
+
+ list_node_t *free_list = &pool.first_node;
+
+
+#ifdef VARIANT_POOL_DEBUG
+ void dump_free_list (const char *where)
+ {
+ list_node_t *node = free_list;
+ printf("free_list[%s]: ", where);
+ for (; node; node = node->next)
+ {
+ printf("%u@%p->%p ", node->len, node, node->next);
+ }
+ printf("\r\n");
+ }
+#else
+ #define dump_free_list(x)
+#endif
+
+
+ inline bool can_split (list_node_t *node, size_t newlen)
+ {
+ size_t min_size = sizeof (list_node_t *);
+ return (newlen < node->len) &&
+ (newlen > min_size) &&
+ (node->len - newlen) > min_size;
+ }
+
+ inline void *node_to_data (list_node_t *node)
+ {
+ return &node->next;
+ }
+
+ inline list_node_t *data_to_node (void *p)
+ {
+ return (list_node_t *)(((char *)p) - sizeof (size_t));
+ }
+
+ inline void *end_of_node (list_node_t *node)
+ {
+ return (char *)node + node->len + sizeof (size_t);
+ }
+
+ void unlink (list_node_t *node)
+ {
+ list_node_t **where = &free_list;
+
+ while (*where)
+ {
+ list_node_t *cur = *where;
+ if (cur == node)
+ {
+ *where = cur->next;
+ return;
+ }
+ else
+ where = &cur->next;
+ }
+ }
+
+ void merge_with_next (list_node_t *node)
+ {
+ if (node && end_of_node (node) == node->next)
+ {
+ node->len += node->next->len + sizeof (size_t);
+ node->next = node->next->next;
+ }
+ }
+
+ void link (list_node_t *node)
+ {
+ list_node_t **where = &free_list, *prev = 0;
+
+ while (*where && node > *where)
+ {
+ prev = *where;
+ where = &(*where)->next;
+ }
+
+ node->next = *where;
+ *where = node;
+
+ merge_with_next (node);
+ merge_with_next (prev);
+ }
+
+ command void *VariantPool.alloc (size_t len)
+ {
+ list_node_t *cur, *best;
+
+ if (!free_list)
+ return 0;
+
+ dump_free_list("alloc-in");
+
+ best = free_list;
+ for (cur = free_list->next; cur; cur = cur->next)
+ {
+ if (cur->len >= len && cur->len < best->len)
+ best = cur;
+ }
+
+ if (best->len < len)
+ return 0;
+
+ unlink (best);
+
+ // don't return unnecessarily large chunks
+ call VariantPool.reduce (&best->next, len);
+
+ dump_free_list("alloc-out");
+
+ return node_to_data (best);
+ }
+
+ command void *VariantPool.reserve (size_t *actual_len)
+ {
+ list_node_t *cur, *best;
+ if (!actual_len || !free_list)
+ return 0;
+
+ dump_free_list("reserve-in");
+
+ best = free_list;
+ for (cur = free_list->next; cur; cur = cur->next)
+ {
+ if (cur->len > best->len)
+ best = cur;
+ }
+
+ unlink (best);
+
+ dump_free_list("reserve-out");
+
+ *actual_len = best->len;
+ return node_to_data (best);
+ }
+
+ command void VariantPool.reduce (void *p, size_t newlen)
+ {
+ list_node_t *node = data_to_node (p);
+
+ dump_free_list("reduce-in");
+
+ // if we can't split this block, reduce is a no-op
+ if (can_split (node, newlen))
+ {
+ list_node_t *fragment = (list_node_t *)((char *)p + newlen);
+ fragment->len = node->len - newlen - sizeof (size_t);
+ node->len = newlen;
+ call VariantPool.release (node_to_data (fragment));
+ }
+
+ dump_free_list("reduce-out");
+ }
+
+ command void VariantPool.release (void *p)
+ {
+ list_node_t *node = data_to_node (p);
+
+ dump_free_list("release-in");
+
+ if (node)
+ link (node);
+
+ dump_free_list("release-out");
+ }
+}