Skip to content
Snippets Groups Projects

Ponyo

Ponyo is a modular, graph-based, remotely-reconfigurable embedded operating system and a member of the squidworks project, an effort to develop a distributed dataflow computing protocol.

ponyo

How it Works

Hunks: Modular Code Blocks

Ponyo, the queen of the seas, is written in cpp. Code blocks aka hunks are cpp classes that can be remotely instantiated on-the-fly. Code blocks have dataflow interfaces: these are typed inputs, outputs, and state objects.

#ifndef HUNK_ADDER_H_
#define HUNK_ADDER_H_

#include <arduino.h>
#include "hunks/hunks.h"
#include "states/state_uint32.h"
#include "transports/net_uint32.h"

class Adder : public Hunk {
private:
public:
  Adder();
  void init(void);
  void loop(void);
  // in, out
  Inp_uint32* numA = new Inp_uint32("numA");
  Inp_uint32* numB = new Inp_uint32("numB");
  Outp_uint32* numC = new Outp_uint32("numC");
};

#endif
/*

simple addition of unsigned ints, take a, b, make c, be exemplary

*/

#include "hunk_adder.h"
#include "trunk.h"

Adder::Adder(){
  // we have some setup to do,
  type_ = "math/adder";
  // inputs,
  inputs[0] = numA;
  inputs[1] = numB;
  numInputs = 2;
  // outputs,
  outputs[0] = numC;
  numOutputs = 1;
}

void Adder::init(void){
  // this has no setup desires
}

void Adder::loop(void){
  // we check flow control: we can only take data
  // from inputs that are occupied, [->io() is true]
  // and we can only put to ports that are not occupied
  if(numA->io() && numB->io() && !(numC->io())){
    uint32_t result = numA->get() + numB->get();
    numC->put(result);
  }
}

Flowcontrolled Runtime

Inputs and Outputs are just like physical data ports: they are subject to data flows, and we need to do some flow control in order to avoid overwriting unread data downstream. As it turns out, flow control can also be a powerful tool for coordinating distributed program execution.

This is why the example above makes calls to input->io() or output->io(); to check the ports' states prior to any attempt to pull data from them, or put data to them.

State Devices

State exists. Ponyo wraps state objects in data structures very similar to Inputs and Outputs: these are also explicitly typed (we're out here in cpp, so this is probably obvious). State objects can be remotely manipulated, i.e. with cuttlefish. By default, requests to update state variables are pushed through automatically, but we can attach callbacks to these events as well, by overriding the hunk default functions for the respective states' index.

#ifndef HUNK_MODULO_H_
#define HUNK_MODULO_H_

#include <arduino.h>
#include "hunks/hunks.h"
#include "states/state_uint32.h"
#include "transports/net_uint32.h"

class Modulo : public Hunk {
private:
public:
  Modulo();
  void init(void);
  void loop(void);
  // in, out
  Inp_uint32* numA = new Inp_uint32("numA");
  Outp_uint32* numC = new Outp_uint32("numC");
  // ah change w/ override callback,
  State_uint32* modulator = new State_uint32("modulator", 64);
  boolean stateChangeCallback_0(void) override;
  // and a plain change
  State_uint32* numAdd = new State_uint32("numAdd", 64);
};

#endif
/*

static modulo, compares one val against state item

*/

#include "hunk_modulo.h"
#include "trunk.h"

Modulo::Modulo(){
  // pls name self,
  type_ = "math/modulo";
  // inputs,
  inputs[0] = numA;
  numInputs = 1;
  // outputs,
  outputs[0] = numC;
  numOutputs = 1;
  // we'll modulo against this state item,
  states[0] = modulator;
  numStates = 1;
}

void Modulo::init(void){
  // nothing to setup here,
}

void Modulo::loop(void){
  // check flowcontrol conditions, then op
  if(numA->io() && !(numC->io())){
    uint32_t result = numA->get() % modulator->value();
    numC->put(result);
  }
}

// these are virtual functions that we override, so
// they're just indexed by the state's location in states[i] ...
boolean Modulo::stateChangeCallback_0(void){
  // when we define a state change callback,
  // the requested value appears in a swap,
  uint32_t option = modulator->swapValue();
  // if we like it, we can set:
  if(option < 1200){
    modulator->set(option);
    return true;
  } else {
    // or we reject it, and walk on
    return false;
  }
}

Usage

To build and run Ponyo, you should be able to use the methods outlined here. To connect and interface with Ponyo, you can acquaint yourself with cuttlefish, which is a dataflow-manipulating browser environment.