Text
Page: 1
pico
ruby
Episode Ⅲ
REVENGE OF THE STDIN
RubyWorld Conference 2022
hasumikin>&Monstarlab
Nov. 10, 2022
Page: 2
Episode Ⅱ
ATTACK OF THE RAKE
find on the internet
Page: 3
This slot has Q&A time
PicoRuby@SUZURI
Page: 5
PicoRuby: An alternative mruby
puts "Hello World"
mruby = mruby VM + mruby compiler
=> 136 KB
MicroRuby = mruby VM + PicoRuby compiler
=> 88 KB
PicoRuby = mruby/c VM + PicoRuby compiler
=> 11 KB
All measurement on 64-bit Ubuntu
Page: 6
PicoRuby: An alternative mruby
github.com/picoruby/picoruby
Page: 7
PRK Firmware: Keyboard firmware
Displayed in Large exhibition hall (1F)
Page: 8
PRK Firmware: Keyboard firmware
github.com/picoruby/prk_firmware
Page: 9
Raspberry Pi Pico
RP2040
Arm Cortex-M0+ (dual)
264 KB RAM
2 MB ROM
(RP2040 supports upto 16 MB)
$4~ (¥600~)
"Pi Pico W" supports WiFi
Got 技適 (new!)
Page: 11
Serial port terminal emulator
Traditional CUI/TUI tools have fallen to
the dark side (apparently CR/LF issue)
cu
screen
minicom
Linux -> GTKTerm
Windows -> Tera Term? (not sure)
macOS -> PuTTY?
Page: 12
Summary: It's still a PoC, though...
An integrated Micon programming environment
Ruby compiler inside
Shell ready
Text editor equipped
Your own commands available
Accelerates developing an IoT system with Ruby
Page: 14
Command: builtin and executable
Builtin commands are implemented in shell
cd, echo, export, pwd, type, etc.
Executable commands are located in storage
cat, ls, rm, vim, etc.
Page: 15
Command: builtin
# picoruby/mrbgems/picoruby-shell/mrblib/command.rb
def exec(params)
args = params[1, params.length - 1]
case params[0]
when "echo"
_echo(*args)
when "type"
_type(*args)
when "pwd"
puts Dir.pwd
when "cd"
puts if Dir.chdir(args[0] || ENV['HOME']) != 0
when "free"
Object.memory_statistics.each do |k, v|
print "#{k.to_s.ljust(5)}: #{v.to_s.rjust(8)}", @feed
end
Page: 16
Command: executable
picoruby/mrbgems/picoruby-shell/
├─ mrbgem.rake
├─ mrblib
│
├─ command.rb
│
└─ shell.rb
├─ shell_executables
│
├─ cat.rb
│
├─ hello.rb
│
├─ ls.rb
│
├─ rm.rb
│
└─ vim.rb
└─ src
└─ shell.c
# Search path
ENV["PATH"] => ["/bin"]
Page: 17
Command: executable
You can write your own executable in PicoRuby
$ vim hello_ruby.rb
```
puts "Hello RubyWorld"
```
$ install hello_ruby.rb /bin/hello_ruby
$ hello_ruby
Hello RubyWorld
Page: 18
Filesystem
Computer has filesystem(s)
MS-DOS: Microsoft Disk Operating System
NTFS, ext{2,3,4}, etc.
Micon generally doesn't have a filesystem
Page: 19
FAT filesystem
File Allocation Table (FAT)
Developed by Microsoft along with MS-DOS
8-bit FAT, FAT12, FAT16, FAT32, exFAT
Under construction for Flash ROM
Today's demo is working on RAM disk
Page: 20
VFS (Virtual File System)
VFS-like system written in PicoRuby
Different devices and even different filesystems
can mount under the root
VFS.mount(FAT.new(:flash), "/")
"/ram")
VFS.mount(FAT.new(:ram),
VFS.mount(FAT.new(:sdcard), "/sdcard")
/
├─
├─
├─
│
├─
│
bin/
home/
ram/
└─ tmp/
sdcard/ # SPI not impemented yet
└─ data.sqlite
Page: 21
mruby's build system
mrbgems is a library management system for
mruby
You can freely host your own gem
Matz says it's an advanced one (than MicroPython?)
Bundled mgems are automatically loaded
Page: 22
mruby's build system
mruby
├─ Rakefile
├─ bin/
├─ build/
├─ build_config/
├─ include/
├─ lib/
│
└─ mruby/
# MRuby module
├─ mrbgems/
├─ mrblib/
├─ src/
├─ tasks/
│
├─
│
├─ mrbgems.rake
│
├─
Page: 23
PicoRuby's build system
picoruby
├─ Rakefile
├─ bin/
├─ build/
├─ build_config/
├─ include/
├─ lib/
│
├─ mruby/
│
└─ picoruby/
│
└─ build.rb
├─ mrbgems/
├─ mrblib/
├─ src/
├─ tasks/
│
├─
│
├─ mrbgems.rake
│
├─
│
├─ picogems.rake
│
├─
modified
# `module MRuby`
MRuby overridden
MRuby.each_target overridden
Page: 24
PicoRuby's build system
picoruby
├─ build/repos/host/
│
├─ mruby-bin-picorbc/
│
└─ mruby-pico-compiler/
├─
├─ mrbgems/
├─ default.gembox
├─ picoruby-bin-picoirb/
├─ picoruby-bin-picoruby/
├─ picoruby-bin-prsh/
├─ picoruby-filesystem-fat/
├─ picoruby-io/
├─ picoruby-mrubyc/
├─ picoruby-sandbox/
├─ picoruby-shell/
├─ picoruby-terminal/
├─ picoruby-vfs/
└─ picoruby-vim/
# picorbc
#
#
#
#
#
#
picoirb
picoruby
prsh [pəːrʃ]
FAT filesystem
io gem
mruby/c VM
Page: 25
PicoRuby's build system
# picoruby/mrbgems/default.gembox
MRuby::GemBox.new do |conf|
conf.gem github: 'picoruby/mruby-pico-compiler'
conf.gem github: 'picoruby/mruby-bin-picorbc'
conf.gem core: 'picoruby-bin-picoruby'
conf.gem core: 'picoruby-bin-picoirb'
conf.gem core: 'picoruby-mrubyc'
end
`mruby-pico-compiler` and `mruby-bin-picorbc`
can be bundled in mruby (MicroRuby)
Page: 26
A typical picogem
picoruby/
└─ mrbgems/picoruby-io/
├─ mrbgem.rake
├─ mrblib
│ └─ io.rb
└─ src/
├─ hal/
│ ├─ hal.h
│ └─ posix
│
└─ hal.c
└─ io.c
Page: 27
`require`
mruby doesn't have `require` out of the box
Neither does mruby/c
PicoRuby has introduced `require`
Bundled Picogem code already consumed ROM, but
It isn't loaded onto RAM automatically
Consumes RAM only after `require`
Page: 28
Making a PicoRuby app elegantly
CRuby code compatible with PicoRuby
PicoRuby for PC (MRBC_USE_HAL_POSIX)
Write minimum HAL for POSIX
Extend PicoRuby's builtin class if necessary
Keep the app code independent from Picoruby
Do not copy and paste files any longer
Page: 29
Keep the app code independent
example-IoT-app
├─ CMakeLists.txt
# Just link src/*.c and libmruby.a
├─ Rakefile
├─ build
│ ├─ ...
├─ include
│ ├─ ...
├─ lib
│ └─ picoruby
# libmruby.a created by `rake`
├─ mrblib
│ ├─ main_task.rb
│ └─ temperature_sensor_task.rb
├─ pico_sdk_import.cmake
└─ src
├─ hal.c
# Micon dependent hal
├─ temperature_sensor.c
├─ main.c
├─ ...
Page: 30
Compatible CRuby with PicoRuby
# picoruby-vim/mrblib/vim.rb
case RUBY_ENGINE
when "ruby", "jruby"
require_relative "../../picoruby-terminal/mrblib/terminal"
when "mruby/c"
require "terminal"
else
raise "Unknown RUBY_ENGINE: #{RUBY_ENGINE}"
end
class Vim
(...)
end
Page: 31
Compatible CRuby with PicoRuby
Run with CRuby on your PC, then
$ ruby -r./mrbgems/picoruby-vim/mrblib/vim.rb \
-e 'Vim.new("myfile.txt").start'
You can easily implement and debug
a "Pure" PicoRuby app with CRuby
Page: 33
back to
implementation
Page: 34
Shell and text editor
Without Curses and Readline
Pure Ruby just like Reline (irb of CRuby3.0+)
Page: 35
Shell and text editor
Without Curses and Readline
Pure Ruby just like Reline (irb of CRuby3.0+)
STDIN confuses you
Page: 36
Standard INPUT
Cooked mode (by default on Unix-like OS)
Blocked until submit (recall Kernel#gets)
"a" "b" "c" "[BSPACE]" "d" "[ENTER]" => "abd"
Raw mode (obviously by default on bare metals)
Immediately receives any input
"a" "b" "c" "[BSPACE]" "d" => "abc[BSPACE]d"
Really confusing in making compatible code
Page: 37
Standard INPUT
static struct termios save_settings;
static int save_flags;
/* Turn into raw mode on Linux (Windows has another solution) */
struct termios settings;
tcgetattr(fileno(stdin), &save_settings);
settings = save_settings;
settings.c_iflag = ~(BRKINT | ISTRIP | IXON);
settings.c_lflag = ~(ICANON | IEXTEN | ECHO | ECHOE | ECHOK | ECHONL);
settings.c_cc[VMIN] = 1;
settings.c_cc[VTIME] = 0;
tcsetattr(fileno(stdin), TCSANOW, &settings);
save_flags = fcntl(fileno(stdin), F_GETFL, 0);
fcntl(fileno(stdin), F_SETFL, save_flags | O_NONBLOCK);
/* Turn back to cooked mode */
fcntl(fileno(stdin), F_SETFL, save_flags);
tcsetattr(fileno(stdin), TCSANOW, &save_settings);
Page: 38
Standard INPUT
# picoruby/mrbgems/picoruby-terminal/mrblib/terminal.rb
case RUBY_ENGINE
when "ruby", "jruby"
require "io/console"
def IO.get_nonblock(max)
STDIN.noecho{ |input| input.read_nonblock(max) }
rescue IO::EAGAINWaitReadable => e
nil
end
when "mruby/c"
require "io"
def IO.get_nonblock(max)
str = read_nonblock(max) # calls C implementation
str&.length == 0 ? nil : str
end
end
Page: 39
C object in RVALUE: mruby
#define MRB_VTYPE_FOREACH(f)
/* mrb_vtype */ /* c type
f(MRB_TT_FALSE,
void,
...
struct
f(MRB_TT_OBJECT,
...
struct
f(MRB_TT_DATA,
...
\
*/
/* ruby class */ \
"false") \
RObject, "Object") \
RData,
"Data") \ //
struct RData {
MRB_OBJECT_HEADER;
struct iv_tbl *iv;
const mrb_data_type *type;
void *data; //
You can pin any object here
};
Page: 40
C object in RVALUE: mruby/c
typedef struct RInstance {
MRBC_OBJECT_HEADER;
struct RClass *cls;
struct RKeyValueHandle ivar;
The last member can extend
uint8_t data[]; //
} mrbc_instance;
// File.new
mrbc_value obj = mrbc_instance_new(vm, v->cls, sizeof(FIL));
//
^^^^^^^^^^^
//
extend RVALUE
FIL *file_stream_ptr = (FIL *)obj.instance->data;
SET_RETURN(obj); // File.new => #<File:200098a0>
No need to `free(file_stream_ptr);`
Page: 41
Finally, the shell works
Page: 43
How should I name
this product
Page: 44
Ruby on Raspberry Pi Pico
Page: 45
Ruby on Raspberry Pi Pico
Page: 49
“It is said that (account) names
should not contain
hyphens or underscores.”
[cited from `@kakutani']
Page: 52
Be one the first stargazers of
github.com/picoruby/R2P2
(turned public repo today!)
Page: 53
Wrap-up
R2P2 is an all-in-one programming Micon
Page: 54
Wrap-up
R2P2 is an all-in-one programming Micon
Runs on Raspi Pico which has 264 KB RAM and
2 MB ROM
Page: 55
Wrap-up
R2P2 is an all-in-one programming Micon
Runs on Raspi Pico which has 264 KB RAM and
2 MB ROM
Picogem ecosystem easily builds your app
Page: 56
Wrap-up
R2P2 is an all-in-one programming Micon
Runs on Raspi Pico which has 264 KB RAM and
2 MB ROM
Picogem ecosystem easily builds your app
Filesystem ly makes you happy
Filesystem will make you happy
Page: 57
Wrap-up
R2P2 is an all-in-one programming Micon
Runs on Raspi Pico which has 264 KB RAM and
2 MB ROM
Picogem ecosystem easily builds your app
Filesystem will make you happy
STDIN is evil
Page: 58
Future work
PicoRuby and Shell
More functionality of vim and the name
UTF-8 support
Multi-task controll on the fly
Redirect and pipeline
Peripherals
FAT filesystem with SD card (SPI)
Real-time clock (RTC)
WiFi and TCP/IP on Raspberry Pi Pico W
Page: 59
q and a
github.com/picoruby/r2p2
Page: 60
may the
source
be with you