Browse files

first readme

  • Loading branch information...
1 parent ecbaba1 commit ca42446262107a67afc1c6526c7d7e40fee65a87 @txus committed Oct 3, 2012
Showing with 150 additions and 6 deletions.
  1. +0 −1 Makefile
  2. +148 −3
  3. +2 −2 src/staat/staat.h
@@ -27,7 +27,6 @@ $(SO_TARGET): $(TARGET) $(OBJECTS)
@mkdir -p build
- @mkdir -p bin
# The Unit Tests
.PHONY: tests
@@ -1,10 +1,149 @@
-# C project
+# Staat
-TODO: Write a project description
+Staat is a State Machine library in C.
+## Basic concepts
+A state machine is just a series of states (let's say `Sleeping`, `Awake`,
+`Eating`) and a set of possible transitions among them (`Sleeping->Awake`,
+`Awake->Eating`, etc...).
+Additionally, transitions in a state machine may have guards, which are like
+preconditions that get executed before transitioning, and have the ability to
+do something and ultimately decide if the transition should be aborted or
+carried out successfully.
+Staat implements these concepts in an easy to use way for your C programs!
## Usage
-TODO: Write usage instructions here
+State Machines in Staat are modeled as blueprints with their states and
+transitions, normally as static variables.
+For example, let's assume we want to model different cats with the same state
+machine, defining states such as Sleeping, Awake, and Eating, and transitions
+between those. Ideally we model the Cat state machine **once**, and then, we
+__instantiate__ different cat state machines, each of those with their own
+state at a given moment, but sharing the transition behavior.
+That's why the Cat State Machine will live in a static variable and be
+ideally initialized **at load time**, and then each different cat will be born
+and die **at runtime**.
+Let's start modeling the possible states of a cat:
+typedef enum {
+ Sleeping,
+ Awake,
+ Eating
+} State;
+Now we set a static Cat State Machine blueprint (from which we'll initialize
+all the cats of the program) and configure it:
+#include <staat/blueprint.h>
+static StaatBlueprint *CatBlueprint = NULL;
+ * At load time, we model the Cat State Machine with the StaatBlueprint_new
+ * macro and all possible states, then add the transitions, and then any
+ * needed guards.
+ */
+CatBlueprint = StaatBlueprint_new(Sleeping, Awake, Eating);
+StaatBlueprint_add_transition(CatBlueprint, "wake_up", Sleeping, Awake);
+StaatBlueprint_add_transition(CatBlueprint, "eat", Awake, Eating);
+StaatBlueprint_add_transition(CatBlueprint, "sleep", Awake, Sleeping);
+StaatBlueprint_add_transition(CatBlueprint, "sleep", Eating, Sleeping);
+Let's also add a guard that will be executed every time we hit the "sleep"
+transition. The guard will be called "purr" and will make the cat purr before
+going to sleep only if it was eating.
+To do that we will have previously defined the purr guard function, which
+receives a **from** parameter (from which state it came), a **to** (to which
+state it is transitioning), and an **object** (which is the object that we'll
+pass to the state machine constructor later on, namely the container of the
+state machine, we'll see that in a moment).
+Remember that guards must return 0 if everything went well and they allow the
+transition, or 1 otherwise (and that will prevent them from transitioning).
+int purr_guard(int from, int to, void *object) {
+ if (from == Eating) {
+ ((Cat*)object)->purr();
+ }
+ return 0;
+StaatBlueprint_add_guard(CatBlueprint, "sleep", purr_guard);
+Good. Now we're ready to instantiate our first cat state machine. Our program
+will consist of Cat objects (structs) with various properties, one of which
+will be their state (an instantiated cat state machine). Let's see how we
+model the cats:
+#include <staat/machine.h>
+typedef struct {
+ StaatMachine *state;
+ /* The two things below are irrelevant */
+ int mood;
+ CatFn purr;
+} Cat;
+Cat* Cat_new() {
+ Cat *cat = calloc(1, sizeof(Cat));
+ cat->purr = default_purr_fn; // whatever
+ cat->mood = 0;
+ /*
+ We initialize a Cat State Machine with an initial "sleeping" state **and a
+ reference to the cat object**, so that guards have access to it and can
+ manipulate / query it.
+ */
+ cat->state = StaatMachine_new(CatBlueprint, cat, Sleeping);
+ return cat;
+Now we have a way to create cats that start sleeping. Let's try it out!
+Cat *cat = Cat_new();
+int current_state = cat->state->current; // Sleeping
+StaatMachine_transition(cat->state, "wake_up"); // returns 0 = OK
+current_state = cat->state->current; // Awake
+StaatMachine_transition(cat->state, "eat"); // returns 0 = OK
+current_state = cat->state->current; // Eating
+But what if the transition doesn't work? For example, let's try transitioning
+to the current state (nonsense):
+StaatMachine_transition(cat->state, "eat"); // returns 1 = wrong!
+Okay, now let's go to sleep:
+StaatMachine_transition(cat->state, "sleep"); // returns 0 = OK
+As we defined in the guard, the `cat->purr()` function will be called before
+transitioning. Guards are useful to define preconditions to the transition,
+and abort it altogether if at least one of them fails.
## Contributing
@@ -13,3 +152,9 @@ TODO: Write usage instructions here
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request
+## Who's this
+This was made by [Josep M. Bach (Txus)]( under the MIT
+license. I'm [@txustice]( on twitter (where you
+should probably follow me!).
@@ -1,4 +1,4 @@
-#ifndef __staat_h__
-#define __staat_h__
+#ifndef _staat_staat_h__
+#define _staat_staat_h__

0 comments on commit ca42446

Please sign in to comment.