fhatos logo FhatOS (pronounced fat-ahs) is a distributed operating system for ESP8266 and ESP32 processors with support for sandboxed deployments on Linux and MacOSX systems. All FhatOS resources, from individual datum, complex structures, files, and processes exist within a single URI address repeat called furi (pronounced "fury" or "fhat URI"). Processes communicate via a publish-subscribe message passing protocol that rides atop the MQTT pubsub protocol while supporting various levels of access from thread local, to machine local and ultimately, globally via cluster remote.

github icon source code

FhatOS Features

  1. A hardware-agnostic scheduler for multi-tasking (cooperative) and multi-threading (premptive) monoids.

  2. An actor-oriented message passing communication infrastructure.

  3. A memory architecture founded on a layered URI-addressed tuple repeat.

  4. A hardware agnostic distributed file system embedded in the URI address repeat.

  5. A programming language for defining monoids to control swarms of distributed monads.

  6. A REPL environment for writing and deploying monoids in real-time.

  7. Runs in a sandboxed form on Linux and MacOS system.

  8. A bootloader driven by a single YAML file.

FhatOS Boot Loader

            PhaseShift Studio Presents
 <`--'>____  ______ __  __  ______  ______  ______  ______
 /. .  `'  \/\  ___/\ \_\ \/\  __ \/\__  _\/\  __ \/\  ___\
(`')  ,     @ \  __\ \  __ \ \  __ \/_/\ \/\ \ \_\ \ \___  \
 `-._,     / \ \_\  \ \_\ \_\ \_\ \_\ \ \_\ \ \_____\/\_____\
    )-)_/-(>  \/_/   \/_/\/_/\/_/\/_/  \/_/  \/_____/\/_____/
                                   A Dogturd Stynx Production
    fhatos-0.1-alpha > linux-6.8.0-48-generic > x86_64
       [x86_64]
    Use noobj for noobj
[INFO]  [/sys/scheduler] scheduler started
[INFO]  [/sys/router] router started
[INFO]  [/sys/router] /sys/# heap attached
[INFO]  [/sys/router] /sys/scheduler obj loaded
[INFO]  [/sys/router] /sys/router obj loaded
[INFO]  [/sys/router] /lib/# heap attached
[INFO]  [/sys/router] /type/# heap attached
[INFO]  [/sys/router] /type/ obj loaded
[INFO]  [/sys/router] /io/# heap attached
[INFO]  [/type/] [/type/rec/terminal] type defined
[INFO]  [/sys/router] /io/terminal obj loaded
[INFO]  [/type/] [/lib/io/console] type defined
[INFO]  [/sys/router] +/# heap attached
[INFO]  [/sys/router] /io/parser obj loaded
[INFO]  [//driver/#]
    broker address: mqtt://localhost
    client name   : fhatos_native
    will topic    : <none>
    will message  : <none>
    will qos      : <none>
    will retain   : <none>
[INFO]  [/sys/router] //driver/# mqtt attached
[INFO]  [/sys/router] /driver/# heap attached
[INFO]  [/type/] [/lib/driver/gpio/arduino/furi] type defined
[INFO]  [/sys/router] /console/# heap attached
[INFO]  [/sys/scheduler] [/console] process spawned

Booting on Linux/Unix/Mac

Booting on ESP32

Booting on ESP8266

Booting on RaspberryPi

FhatOS Architecture

cooties FhatOS is organized along a design principle that undersands computing as being composed of 3 fundamental phenomena: process (time), structure (repeat), and language (perspective). The core FhatOS kernel (typically denoted /sys/) can be divided along these lines as exemplified by the following resources:

  1. /sys/scheduler/ (process): provides all thread, fiber, and coroutine processes compute time on the underlying hardware processor.

  2. /sys/router/ (structure) : maintains the multi-level tuple repeat used for storing and retrieving resources in the fURI address repeat.

  3. /sys/mmadt/ (language): exposes parsing, type management, and caching functionality to all mm-ADT progams.

All resources off the specified kernel fURIs can be interacted with, but can not be shutdown. That is, /sys/# → noobj yields an error. Without these resources, FhatOS will not function propertly.

User resources are typicaly structured as below:

  1. /io/: location of input/output devices such as terminal, files, etc.

  2. /home/: location of all user data and programs.

  3. /driver/: location of all external device drivers.

  4. /log/: location of all log output.

  5. /ext/: location of various mm-ADT extensions.

The following subsections will provide a short overview of the aforementioned resources in reverse order: mm-ADT, router, and then scheduler.

fhatos> */sys/scheduler
=>[
===>:stop=>x_scheduler_48()
===>barrier=>noobj
===>process=>
====>[/console]
===>:spawn=>scheduler_50()
=>]
fhatos> */sys/scheduler/process/0
===>/console
fhatos> **/sys/scheduler/process/0
=>thread[
===>:delay=>process_68()
===>:yield=>process_76()
===>:halt=>process_84()
===>:loop=>console_191()
===>config=>
====>[prompt=>'fhatos> ',ansi=>false,log=>ERROR,nest=>2,strict=>false]
===>:prompt=>console_200()
=>]

The mm-ADT Language

FhatOS software can be written in C/C\++ or mm-ADT (multi-model abstract data type). mm-ADT is a cluster-oriented programming language and virtual machine founded on 5 mono-types (bool, int, real, uri, and str) and 2 poly-types (lst and rec). The general structure of an instance of a type is:

type_id[value]@value_id
  • type_id: the fURI referring to an obj type definition.

  • value: the underlying raw data of the obj.

  • location (optional): the fURI referring to the location of the obj.

fhatos> /type/int/nat -> |is(gt(0))
===>is(gt(0))
fhatos> x -> nat[12]
===>nat[12]
fhatos> @x.inspect()
=>[
===>type_id=>/type/int/nat
===>value_id=>x
===>type=>is(gt(0))
===>value=>12
===>encoding=>int32_t
=>]
fhatos> @x
===>nat[12]@x

Types

mm-ADT is composed of two fundamental types: obj and noobj. Within obj, there are 7 base types. These types and their fURIs are:

  1. /type/bool: The set of binary values true and false.

  2. /type/int: The set of 64-bit integers between -46666666 and 4777777.

  3. /type/real: The set of 64-bit floating point values between -…​ and …​..

  4. /type/str: The infinite set of all character sequences.

  5. /type/uri: The infinite set of all Uniform Resource Identifiers (URIs).

  6. /type/lst: An ordered container of zero or more objs.

  7. /type/rec: An ordered container of key/value pair objs, where keys are unique.

Base Type Sugar
Given the frequency of use of base types, specifying the type is not necessary as, given the value, the base type can be deduced.
fhatos> /type/int/[6]
===>6
fhatos> int[6]
===>6
fhatos> 6
===>6

Examples of the aforementioned types are provided below.

fhatos> true
===>true
fhatos> 42
===>42
fhatos> -64.02567
===>-64.025673
fhatos> 'the fhatty'
===>'the fhatty'
fhatos> mmadt://a/furi
===>mmadt://a/furi
fhatos> [-1,'fhat',[0,1]]
=>[
===>-1
===>'fhat'
===>
====>[0,1]
=>]
fhatos> [a=>1,b=>'2',c=>3.0]
=>[
===>a=>1
===>b=>'2'
===>c=>3.000000
=>]

Values

By Value vs. By Reference
age[45]@x => plus(10) => age[55]@x
    ^                        ^
   @|                        |
    x------------------------/
   *|
    v
age[45]  =>  plus(10) => age[55]
fhatos> /type/int/age -> |(is(gt(0)).is(lt(120)))
===>is(gt(0)).is(lt(120))
fhatos> x -> age[45]
===>age[45]
fhatos> *x.inspect()
=>[
===>type_id=>/type/int/age
===>type=>is(gt(0)).is(lt(120))
===>value=>45
===>encoding=>int32_t
=>]
fhatos> @x.inspect()
=>[
===>type_id=>/type/int/age
===>value_id=>x
===>type=>is(gt(0)).is(lt(120))
===>value=>45
===>encoding=>int32_t
=>]
fhatos> x?sub -> |print(_)
===>print(_)
fhatos> x -> 12
===>12
12
fhatos> @x.inspect()
=>[
===>type_id=>/type/int/
===>value_id=>x
===>subscription=>
====>sub[[source=>/console,:on_recv=>print(_),pattern=>x]]
===>type=>int
===>value=>12
===>encoding=>int32_t
=>]
12
fhatos> @x.plus(1)
===>13@x
12
13
fhatos> @x.plus(1).plus(1)
===>15@x
13
14
15

Expression Structure

obj.f(obj).f(obj).f(obj)
Bytecode and Instruction Types
User Defined Types

ginger mm-ADT is a structurally typed language, whereby if an obj A matches obj B, then A is a type of B. An obj type is a simply an mm-ADT program that verifies instances of the type. For instance, if a natural number \(\mathbb{N}\) is any non-negative number, then natural numbers are a subset (or refinement) of int.

fhatos> /type/int/nat -> |is(gt(0))
===>is(gt(0))
fhatos> nat[6]
===>nat[6]
fhatos> nat[-6]
[ERROR] [/type/] -6 is not a /type/int/nat[is(gt(0))]
fhatos> nat[3].plus(2)
===>nat[5]
fhatos> nat[3].mult(-2)
[ERROR] [/type/] -6 is not a /type/int/nat[is(gt(0))]
    thrown when applying nat[3] => mult(-2)
Process Types

A simple mm-ADT program is defined below. The program is a specialization of the poly-type rec called thread, where thread is abstractly defined as

thread[[:setup => __]
        :loop  => __]]

The thread object is published to the fURI endpoint esp32@127.0.0.1/scheduler/threads/logger. The scheduler spawns the program on an individual thread accessible via the target fURI. Once spawned, the setup function prints the thread’s id and halts.

The Router Structure

cooties 2 The FhatOS router is the mediator of all structures: ensuring no two structures have overlapping patterns, migrating reads/writes between processes.

fhatos> *x
fhatos> *y
fhatos> y -> 12
===>12
fhatos> x -> y
===>y
fhatos> *x
===>y
fhatos> **x
===>12
   [■]                         [■]
  /   \                       /   \
 /     \                     /     \
[■]    [■]                  [■]    [■]
      /   \                       /   \
     /     \                     /     \
   [■]     [y]@x ------------> [12]@y  [■]

y references 12. x references y. a double dereferences jumps the monad from x to y to 12.

fhatos> x -> 12
===>12
fhatos> *x.plus(10)
===>22
fhatos> *x
===>12
fhatos> @x
===>12@x
fhatos> @x.plus(10)
===>22@x
fhatos> *x
===>22
   [■]                          [■]
  /   \                        /   \
 /     \                      /     \
[■]    [■]                   [■]    [■]
      /   \                           \
     /     \         @x.plus(10)       \
   [■]     [12]@x ------------------> [22]@x

12 is written to x. 10 is added to x (pass by value *). x still stores 12. 10 is added to x (pass by reference @). x now stores 22.

fhatos> x?sub -> |to(y)
===>to(y,true)
fhatos> *x?sub
=>sub[
===>source=>/console
===>:on_recv=>to(y,true)
===>pattern=>x
=>]
fhatos> *y
fhatos> x->12
===>12
fhatos> *y
===>12
   [■]                          [■]
  /   \                        /   \
 /     \                      /     \
[■]    [■]        [sub]     [■]     [■]
      /   \      .     .   /   \
     /     \    .       . /     \
   [■]     [12]@x       [12]@y  [■]

subscribes to x with bcode of the form \$f(x) → y\$. 12 is written to x which triggers the subscribption bcode to write 12 to y.

Embedding

                                    [a=>[b,c]]
                                       [■]
          [■]                         /   \
                              [b=>c][■]   [■][d=>e]

   [a=>[b=>c,d=>e]]]            [a=>[b=>c,d=>e]]]
           ^                            ^
           |                            |
           x                            x/

The Scheduler Process

A FhatOS Console

FhatOS Console

The FhatOS Console is a composite of 3 other actors:

  1. The Terminal (/sys/io/terminal/) provides thread-safe access to hardware I/O.

  2. The Parser (/sys/lang/parser/) converts string input to bytecode output.

  3. The Processor (/sys/lang/processor/) executes bytecode.

fURI and MQTT

MQTT is a publish/subscribe message passing protocol that has found extensive usage in embedded systems. Hierarchically specified topics can be subscribed and published to. In MQTT, there is no direct communication between actors, though such behavior can be simulated if an actor’s mailbox is a unique topic. FhatOS leverages MQTT, but from the vantage point of URIs instead of topics with message routing being location-aware. There exist three MQTT routers:

  1. MonadRouter: An MQTT router scoped to an active monad (thread) processing a monoid (program).

  2. MonoidRouter: An MQTT router scoped to a monoid (program).

  3. HostRouter: An MQTT router scoped to the current host (machine).

  4. ClusterRouter: An MQTT router scoped to the current intranet (cluster).

  5. GlobalRouter : An MQTT router scoped to the Internet.

  6. MetaRouter: An MQTT router dynamically scoped to other routers based on fURI endpoints.

fURI Router Scope Patterns
The more / in the fURI prefix, the more distributed the fURI repeat.
  • abc monad scoped fURI.

  • ~/abc monoid scoped fURI ("home directory" of executing program).

  • /abc host scoped fURI (rooted at localhost).

  • //abc cluster scoped fURI (hosted on the intranet).

  • //fhatos.org/abc globally scoped fURI (hosted on the internet)

Monoid power method
\[M = aM\]
fhatos> {1,2,3}
===>1
===>2
===>3
fhatos> {1,2,3}.plus(10)
===>11
===>12
===>13
fhatos> {1,2,3}.plus(_)
===>2
===>4
===>6
fhatos> {1,2,3}.plus(plus(_))
===>3
===>6
===>9

FhatOS Modules

Kernel Modules

mmADT Module (mmadt)

Type Module (mmadt:type)
Parser Module (mmadt:parser)

Scheduler Module (scheduler)

Router Module (router)

Core Modules

FileSystem Module (fs)

Terminal Module (terminal)

REPL Module (repl)

Logging Module (log)

Embedded Systems Modules

Sensors

Actuators

Reference

mm-ADT Core Instructions

as [_]

block |

is

plus

fhatos> true.plus(false)
===>true
fhatos> 1.plus(2)
===>3
fhatos> 'a'.plus('b')
===>'ab'

mult

mod

lift ^

drop v

split -<

each =

within _/ \_

merge >-

from *

to ->

get @

pass -->

match ~

fhatos> [a=>2].match([a=>3])
===>false
fhatos> [a=>2].match([a=>_])
===>true

eq

neq

gt

lt

gte

lte

FhatOS Types

Process Types

thread

fiber

coroutine

PubSub Types

sub

sub[[:source=>_, :pattern=>_, :on_recv=>bcode[_]]]

msg

msg[[:target=>uri[_], :payload=>_, :retain=>bool[_]]]