diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 579d0a34..fb75cb60 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: check_mode: "compile" no_compile_flag: false exclude_dirs: '["failing", "experiments"]' - compiler_ref: ${{ needs.find-latest-release.outputs.ref }} + compiler_ref: "master" # ${{ needs.find-latest-release.outputs.ref }} check-format: runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index dbf48c1d..4d594143 100644 --- a/.gitignore +++ b/.gitignore @@ -14,9 +14,9 @@ **/src-gen/ **/fed-gen/ C/include -Cpp/include -Cpp/share -Cpp/lib +Cpp/**/include +Cpp/**/share +Cpp/**/lib # Created by https://www.toptal.com/developers/gitignore/api/intellij,gradle,eclipse,maven,visualstudiocode # Edit at https://www.toptal.com/developers/gitignore?templates=intellij,gradle,eclipse,maven,visualstudiocode diff --git a/README.md b/README.md index 3ac79ed5..1cc03d58 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,25 @@ [![CI](https://github.com/lf-lang/examples-lingua-franca/actions/workflows/ci.yml/badge.svg)](https://github.com/lf-lang/examples-lingua-franca/actions/workflows/ci.yml) ## 🛝 Lingua Franca Playground -Get to know the language and tinker with some example Lingua Franca programs! +Get to know the [Lingua Franca coordination language](https://lf-lang.org) and browse [example programs](examples/README.md). +To view, edit, and run the programs, you can either run locally on your computer or run in the cloud using either GitHub Codespaces or Gitpod. -### :rocket: Cloud-based dev environment +## 💻 Running Locally +Quick start: + +1. Clone this repo (`git clone git@github.com:lf-lang/playground-lingua-franca.git`) +2. Open with [VS Code](https://code.visualstudio.com) (`code playground-lingua-franca`) +3. Install the [Lingua Franca extension](https://github.com/lf-lang/vscode-lingua-franca) (Ctrl+P and enter `ext install lf-lang.vscode-lingua-franca`). + +Once in VSCode, navigate to [./examples](./examples) and click on any of the `.lf` files to open them into your editor. To build and run, use Ctrl+Shift+P and select `Lingua Franca: Build and Run`. Note: You might need not install additional dependencies in order to successfully build some of the code you find in this repository. For more information, see the [setup-env.bash](./utils/scripts/setup-env.bash) script that we use to configure our Docker-based environments. + + +## :rocket: Running in the Cloud Spin up a fully configured dev environment in the cloud that start in seconds. Any dependencies required for building or running any of the examples are preinstalled. A web-based VS Code editor, preloaded with the Lingua Franca extension, is accessible through either **GitHub Codespaces** or **GitPod**. Simply click on either of the links below to get started. -[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&repo=477928779&ref=main&skip_quickstart=true&devcontainer_path=.devcontainer%2Fnightly%2Fdevcontainer.json) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&repo=477928779&ref=main&skip_quickstart=true&devcontainer_path=.devcontainer%2Fnightly%2Fdevcontainer.json) (NOTE: This can be quite slow to start.) [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/new#https://github.com/lf-lang/playground-lingua-franca/tree/main) @@ -32,9 +43,3 @@ bash ./utils/scripts/setup-lf.bash dev Please note that running these commands will remove the current lingua-franca directory. -## 💻 Local dev environment -1. Clone this repo (`git clone git@github.com:lf-lang/playground-lingua-franca.git`) -2. Open with VS Code (`code playground-lingua-franca`) -3. Install the [Lingua Franca extension](https://github.com/lf-lang/vscode-lingua-franca) (Ctrl+P and enter `ext install lf-lang.vscode-lingua-franca`). - -Once in VSCode, navigate to [./examples](./examples) and click on any of the `.lf` files to open them into your editor. To build and run, use Ctrl+Shift+P and select `Lingua Franca: Build and Run`. Note: You might need not install additional dependencies in order to successfully build some of the code you find in this repository. For more information, see the [setup-env.bash](./utils/scripts/setup-env.bash) script that we use to configure our Docker-based environments. diff --git a/examples/C/README.md b/examples/C/README.md index e9fd4742..50e9ed67 100644 --- a/examples/C/README.md +++ b/examples/C/README.md @@ -1,13 +1,20 @@ # C Examples -* [Patterns](src/patterns/README.md): Common communication patterns. + +(in alphabetical order) + +* [Browser UIs](src/browser-ui/README.md): How to create a browser-based UI for an LF program. +* [Car Brake](src/car-brake/README.md): Sketch of ADAS system illustrating the CAL theorem. * [Deadlines](src/deadlines/README.md): Uses of deadlines in Lingua Franca. -* [Car Brake](src/car-brake/README.md): Sketch of ADAS system illustrating CAL theorem. -* [Rosace](src/rosace/README.md): Aircraft controller illustrating periodic systems with multiple periods. -* [Simulation](src/simulation/README.md): Using Lingua Franca for simulation. +* [Distributed](src/distributed/README.md): Basic federated hello-world examples. +* [Furuta Pendulum](src/modal_models/FurutaPendulum/README.md): A controller and simulation illustrating a modal reactor. * [Keyboard](src/keyboard/README.md): Responding to keyboard input using ncurses. +* [Leader Election](src/leader-election/README.md): Federated fault-tolerant system with leader election. * [MQTT](src/mqtt/README.md): Interacting with MQTT-based services. -* [Furuta Pendulum](src/modal_models/FurutaPendulum/README.md): A controller and simulation illustrating a modal reactor. +* [Patterns](src/patterns/README.md): Common communication patterns. * [Rhythm](src/rhythm/README.md): Sound generation and terminal user interface demos. +* [Rosace](src/rosace/README.md): Aircraft controller illustrating periodic systems with multiple periods. * [SDV](src/sdv/README.md): Software defined vehicle sketch integrating user input, a web display, and sound. +* [Shared Memory](src/shared-memory/README.md): Using shared memory to exchange large data objects between federates. +* [Simulation](src/simulation/README.md): Using Lingua Franca for simulation. * [Train Door](src/train-door/README.md): Train door controller from a verification paper. -* [Distributed](src/distributed/README.md): Basic federated hello-world examples. \ No newline at end of file +* [Watchdog](src/watchdog/README.md): Federated illustration of watchdogs. diff --git a/examples/C/src/ReflexGame/ReflexGame.lf b/examples/C/src/ReflexGame/ReflexGame.lf index 78ef6c3d..e776b5ff 100644 --- a/examples/C/src/ReflexGame/ReflexGame.lf +++ b/examples/C/src/ReflexGame/ReflexGame.lf @@ -13,10 +13,6 @@ target C { keepalive: true } -preamble {= - #include "include/core/platform.h" -=} - /** * Produce a counting sequence at random times with a minimum and maximum time between outputs * specified as parameters. diff --git a/examples/C/src/ReflexGame/ReflexGameTest.lf b/examples/C/src/ReflexGame/ReflexGameTest.lf index 8621be15..f46ef52b 100644 --- a/examples/C/src/ReflexGame/ReflexGameTest.lf +++ b/examples/C/src/ReflexGame/ReflexGameTest.lf @@ -12,10 +12,6 @@ target C { timeout: 5 sec } -preamble {= - #include "include/core/platform.h" -=} - main reactor { preamble {= // Specify a thread that sends all keyboard characters diff --git a/examples/C/src/SleepingBarber.lf b/examples/C/src/SleepingBarber.lf index b1d211b4..ecc6c741 100644 --- a/examples/C/src/SleepingBarber.lf +++ b/examples/C/src/SleepingBarber.lf @@ -26,7 +26,7 @@ */ target C { fast: true, - threading: false, + single-threaded: true, cmake-include: "/lib/c/reactor-c/util/deque.cmake", files: ["/lib/c/reactor-c/util/deque.h", "/lib/c/reactor-c/util/deque.c"] } diff --git a/examples/C/src/browser-ui/README.md b/examples/C/src/browser-ui/README.md new file mode 100644 index 00000000..f41ae0b3 --- /dev/null +++ b/examples/C/src/browser-ui/README.md @@ -0,0 +1,23 @@ +# Browser UI + +These examples show how to create user interfaces for a Lingua Franca program. +The UI runs in the browser and connects to the program via either HTTP or via a web socket. + +
+ | BrowserUI.lf: This version starts a web server that serves a specified web page and enables implementing an HTTP-based API to control your LF program. When the program is running, you can point your browser to http://localhost:8080 to get a page. Adding a path to the URL, as in for example, http://localhost:8080/count, will cause the ServerUI reactor to produce an output that your LF program can react to and send a (text) response. | +
+ | WebSocket.lf: This example uses the much more versatile WebSocketServer reactor. When the program is running, you can open an HTML page that includes JavaScript that connects to the server. Messages can be sent in both directions over the web socket, from the LF program to the browser and vice versa. | +
+ | WebSocketString.lf: This version uses the simpler WebSocketServerString reactor, which is simpler in that it restricts the messages transported over the web socket to be of string types and it allows only one client to connect. | +
+ | Uptime.lf: This version combines ServerUI with WebSocketServer to serve a web page and then feed it data continuously through a web socket. The application displays the total time that application has been running and updates this time once per second. | +
brew install libwebsockets + *This puts the compiled libraries in {@code /usr/local/lib}, and these libraries can be + * linked to using the {@code -lwebsockets} compile option or the {@code WebSocketCmake.txt} Cmake + * include file. + * + * @author Edward A. Lee + */ +target C { + build-type: debug, + keepalive: true +} + +import WebSocketServer from "../lib/WebSocketServer.lf" + +main reactor { + timer seconds(0, 1 s) + + w = new WebSocketServer( + hostport=8080, + initial_file = {= LF_SOURCE_DIRECTORY LF_FILE_SEPARATOR "Uptime.html" =}) + + reaction(startup) {= + lf_print("Point your browser to http://localhost:8080"); + =} + + reaction(seconds) -> w.send {= + instant_t uptime = lf_time_logical_elapsed(); + // Truncate to the nearest second. + uptime = (uptime / SEC(1)) * SEC(1); + char* message = (char*)malloc(LF_TIME_BUFFER_LENGTH * sizeof(char)); + size_t length = lf_readable_time(message, uptime) + 1; // +1 to add a null character. + message[length] = '\0'; + + // Broadcast to all connected sockets. This is accomplished by providing a NULL wsi. + web_socket_message_t* to_send = (web_socket_message_t*)malloc(sizeof(web_socket_message_t)); + to_send->wsi = NULL; + to_send->length = length; + to_send->message = message; + to_send->binary = false; + lf_set(w.send, to_send); + =} +} diff --git a/examples/C/src/browser-ui/WebSocket.html b/examples/C/src/browser-ui/WebSocket.html index 80e0299f..8d9a1f78 100644 --- a/examples/C/src/browser-ui/WebSocket.html +++ b/examples/C/src/browser-ui/WebSocket.html @@ -9,11 +9,12 @@ // Get references to elements on the page. var form = document.getElementById('message-form'); var messageField = document.getElementById('message'); - var messagesList = document.getElementById('messages'); + var incoming = document.getElementById('messages'); + var outgoing = document.getElementById('outgoing'); var socketStatus = document.getElementById('status'); var closeBtn = document.getElementById('close'); - const socket = new WebSocket('ws://localhost:8000', 'ws'); + const socket = new WebSocket('ws://localhost:8080', 'ws'); socket.addEventListener('open', (event) => { console.log('WebSocket connection established'); @@ -38,9 +39,9 @@ // Send the message through the WebSocket. if (socket.readyState == WebSocket.OPEN) { socket.send(message); - messagesList.innerHTML = '