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
                                       Running on Linux
    Use noobj for noobj
    Use :help for console commands
[INFO]  [/sys/scheduler/] scheduler started
[INFO]  [/sys/router/#] router started
[INFO]  [/sys/router/#] +/# local attached
[INFO]  [/sys/router/#] /type/# local attached
[INFO]  [/sys/scheduler/] /type/ coroutine spawned
[INFO]  [/sys/router/#] /terminal/# local attached
[INFO]  [/sys/router/#] /parser/# local attached
[INFO]  [/sys/scheduler/] /parser/ coroutine spawned
[INFO]  [/io/fs/#] /home/killswitch/software/fhatos/data/ directory mounted
[INFO]  [/sys/router/#] /io/fs/# ephemeral attached
[INFO]  [//+/#]
    broker address: localhost
    client name   : client_1905515073
    will topic    : <none>
    will message  : <none>
    will qos      : <none>
    will retain   : <none>
[INFO]  [/sys/router/#] //+/# network attached
[INFO]  [/type/] /type/rec/thread[[:setup=>_,:loop=>_,:stop=>_]] type defined
[INFO]  [/type/] /type/rec/fiber[[:setup=>_,:loop=>_,:stop=>_]] type defined
[INFO]  [/type/] /type/rec/coroutine[[:setup=>_,:loop=>_,:stop=>_]] type defined
[INFO]  [/type/] /type/rec/local[[:setup=>_,:loop=>_,:stop=>_]] type defined
[INFO]  [/type/] /type/rec/network[[:setup=>_,:loop=>_,:stop=>_]] type defined
[INFO]  [/type/] /type/rec/external[[:setup=>_,:loop=>_,:stop=>_]] type defined
[INFO]  [/type/] /type/inst/stop[map(noobj).to(from(_0,noobj),true)] type defined
[INFO]  [/type/] /type/rec/sub[[:source=>as(/type/uri/),:pattern=>as(/type/uri/),:on_recv=>_]] type defined
[INFO]  [/type/] /type/rec/msg[[:target=>as(/type/uri/),:payload=>_,:retain=>as(/type/bool/)]] type defined
[INFO]  [/sys/router/#] /console/# local attached
[INFO]  [/sys/scheduler/] /console/ thread spawned

Booting on Linux/Unix/Mac

Booting on ESP32

Booting on ESP8266

FhatOS Architecture

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/#
==>[/sys/router/structure/0=>+/#,/sys/router/structure/1=>/type/#,/sys/router/structure/2=>/terminal/#,/sys/router/structure/3=>/parser/#,/sys/router/structure/4=>/io/fs/#,/sys/router/structure/5=>//+/#,/sys/router/structure/6=>/console/#]
==>[/sys/scheduler/process/0=>/type/,/sys/scheduler/process/1=>/parser/,/sys/scheduler/process/2=>/console/]

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).

Expression Structure

obj.f(obj).f(obj).f(obj)

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.

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]
Bytecode and Instruction Types
User Defined Types

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))]
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  => __]]
fhatos> abc/ ->
  thread[[:setup=>|(x->0),
          :loop=>|(*x.[is(gt(10))=>abc/->noobj,_=>plus(1).print(_)]>-().to(x)),
          :stop=>|print('done')]]
1
2
3
4
5
6
7
8
9
10
11
'done'
12
fhatos> define(/type/int/nat,|is(gt(0)))
[ERROR] Unknown instruction: /type/inst/definefhatos> define(/type/rec/person,|[name=>as(/str/),age=>as(/int/nat)])
[ERROR] Unknown instruction: /type/inst/definefhatos> person[[name=>'fhatty',age=>0]]
[ERROR] [/type/] /type/rec/person is an undefined typefhatos> person[[name=>'fhatty',age=>1]]
[ERROR] [/type/] /type/rec/person is an undefined type

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.

fhatos> thread[[setup => print('setup complete'),
                loop  => stop(/abc/)]].to(/abc/)
fhatos> */abc/
==> thread[[setup => print('setup complete'),
            loop  => stop(/abc/)]]

The Router Structure

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

fhatos> /console/config/nest -> true
==>true
fhatos> */sys/router/#
==>[/sys/router/structure/0=>+/#,/sys/router/structure/1=>/type/#,/sys/router/structure/2=>/terminal/#,/sys/router/structure/3=>/parser/#,/sys/router/structure/4=>/io/fs/#,/sys/router/structure/5=>//+/#,/sys/router/structure/6=>/console/#]

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.

terminal/in =[str]=> console
  =[str]=> parser =bcode<~/abc>=>
    processor =[objs]=> ~/abc
      <=[objs]= console
        =[str]=> terminal/out

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[_]]]