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.
FhatOS Features
-
A hardware-agnostic scheduler for multi-tasking (cooperative) and multi-threading (premptive) monoids.
-
An actor-oriented message passing communication infrastructure.
-
A memory architecture founded on a layered URI-addressed tuple repeat.
-
A hardware agnostic distributed file system embedded in the URI address repeat.
-
A programming language for defining monoids to control swarms of distributed monads.
-
A REPL environment for writing and deploying monoids in real-time.
-
Runs in a sandboxed form on Linux and MacOS system.
-
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:
-
/sys/scheduler/
(process): provides all thread, fiber, and coroutine processes compute time on the underlying hardware processor. -
/sys/router/
(structure) : maintains the multi-level tuple repeat used for storing and retrieving resources in the fURI address repeat. -
/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:
-
/io/
: location of input/output devices such as terminal, files, etc. -
/home/
: location of all user data and programs. -
/driver/
: location of all external device drivers. -
/log/
: location of all log output. -
/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:
-
/type/bool
: The set of binary valuestrue
andfalse
. -
/type/int
: The set of 64-bit integers between-46666666
and4777777
. -
/type/real
: The set of 64-bit floating point values between-…
and….
. -
/type/str
: The infinite set of all character sequences. -
/type/uri
: The infinite set of all Uniform Resource Identifiers (URIs). -
/type/lst
: An ordered container of zero or moreobjs
. -
/type/rec
: An ordered container of key/value pairobjs
, 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
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:
-
MonadRouter
: An MQTT router scoped to an active monad (thread) processing a monoid (program). -
MonoidRouter
: An MQTT router scoped to a monoid (program). -
HostRouter
: An MQTT router scoped to the current host (machine). -
ClusterRouter
: An MQTT router scoped to the current intranet (cluster). -
GlobalRouter
: An MQTT router scoped to the Internet. -
MetaRouter
: An MQTT router dynamically scoped to other routers based on fURI endpoints.
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[_]]]