rabbit-slide-hasumikin-RubyConf2019 2019.11.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.rd +24 -0
- data/Rakefile +17 -0
- data/config.yaml +24 -0
- data/images/IDE.png +0 -0
- data/images/Powerpoint Content Slide.png +0 -0
- data/images/Powerpoint Hold Slide.png +0 -0
- data/images/asahi-1.jpg +0 -0
- data/images/asahi-2.jpg +0 -0
- data/images/asahi-3.jpg +0 -0
- data/images/bytecode.png +0 -0
- data/images/co2.png +0 -0
- data/images/co2_demo.png +0 -0
- data/images/collage01.jpg +0 -0
- data/images/esp32.jpg +0 -0
- data/images/fuzz.png +0 -0
- data/images/hasumi.jpg +0 -0
- data/images/how-mrubyc-test-works.png +0 -0
- data/images/juji-asahi.jpg +0 -0
- data/images/kamos.jpg +0 -0
- data/images/mark32.png +0 -0
- data/images/mark48.png +0 -0
- data/images/mark64.png +0 -0
- data/images/mobile.png +0 -0
- data/images/monstarlab.png +0 -0
- data/images/monstarlab_webpage.png +0 -0
- data/images/mruby_and_mrubyc-mruby.png +0 -0
- data/images/mruby_and_mrubyc-mrubyc.png +0 -0
- data/images/mruby_and_mrubyc.png +0 -0
- data/images/psoc5lp_chip.jpg +0 -0
- data/images/raspberrypi.jpg +0 -0
- data/images/rubykaigi2020.png +0 -0
- data/images/rubylabel.jpg +0 -0
- data/images/rubylabeljujiasahi.jpg +0 -0
- data/images/unsoldered-2.png +0 -0
- data/images/unsoldered.jpg +0 -0
- data/images//346/235/276/346/261/237/345/237/216_Matsue.rb.jpg +0 -0
- data/mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.rab +720 -0
- data/pdf/RubyConf2019-mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.pdf +0 -0
- data/theme.rb +118 -0
- metadata +97 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 7d313e1ad0aef139cb1993d6641f9f054542121a09d0f5a88f1b18dc544871cf
|
4
|
+
data.tar.gz: 85b7b21fa455a01dfc22108f822e4dd433fe96d603a282ddcfa2949cd72dc293
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: a95f09ae99c0b83eac872d3b8af4a09c819e163708ebf79e4232bf4f296948f06e987d6b2d4c7ed63e0440149fca2c83bfad80a08eced711a8870c30ab564bdd
|
7
|
+
data.tar.gz: 075c61a9408b085f1e22aeedebf0aac3bdd608b334af8039c4b09328ee3fd680766c4483eaf5a91efc137ee741d5ee1bd649053f20edef7c8ba799621dc986d2
|
data/.rabbit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.rab
|
data/README.rd
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
= mruby/c: Running on Less Than 64KB RAM Microcontroller
|
2
|
+
|
3
|
+
A presentation slide for RubyConf 2019 at JW Marriott Nashville on Nov 18, 2019
|
4
|
+
|
5
|
+
== 作者向け
|
6
|
+
|
7
|
+
=== 表示
|
8
|
+
|
9
|
+
rake
|
10
|
+
|
11
|
+
=== 公開
|
12
|
+
|
13
|
+
rake publish
|
14
|
+
|
15
|
+
== 閲覧者向け
|
16
|
+
|
17
|
+
=== インストール
|
18
|
+
|
19
|
+
gem install rabbit-slide-hasumikin-RubyConf2019
|
20
|
+
|
21
|
+
=== 表示
|
22
|
+
|
23
|
+
rabbit rabbit-slide-hasumikin-RubyConf2019.gem
|
24
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require "rabbit/task/slide"
|
2
|
+
|
3
|
+
# Edit ./config.yaml to customize meta data
|
4
|
+
|
5
|
+
spec = nil
|
6
|
+
Rabbit::Task::Slide.new do |task|
|
7
|
+
spec = task.spec
|
8
|
+
# spec.files += Dir.glob("doc/**/*.*")
|
9
|
+
# spec.files -= Dir.glob("private/**/*.*")
|
10
|
+
# spec.add_runtime_dependency("rabbit-theme-YOUR-THEME")
|
11
|
+
end
|
12
|
+
|
13
|
+
desc "Tag #{spec.version}"
|
14
|
+
task :tag do
|
15
|
+
sh("git", "tag", "-a", spec.version.to_s, "-m", "Publish #{spec.version}")
|
16
|
+
sh("git", "push", "--tags")
|
17
|
+
end
|
data/config.yaml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
---
|
2
|
+
id: RubyConf2019
|
3
|
+
base_name: mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller
|
4
|
+
tags:
|
5
|
+
- mruby/c
|
6
|
+
- Sake
|
7
|
+
- IoT
|
8
|
+
presentation_date: '2019-11-18'
|
9
|
+
presentation_start_time:
|
10
|
+
presentation_end_time:
|
11
|
+
version: 2019.11.18.0
|
12
|
+
licenses: []
|
13
|
+
slideshare_id:
|
14
|
+
speaker_deck_id:
|
15
|
+
ustream_id:
|
16
|
+
vimeo_id:
|
17
|
+
youtube_id:
|
18
|
+
author:
|
19
|
+
markup_language: :rd
|
20
|
+
name: HASUMI Hitoshi
|
21
|
+
email: hasumikin@gmail.com
|
22
|
+
rubygems_user: hasumikin
|
23
|
+
slideshare_user:
|
24
|
+
speaker_deck_user:
|
data/images/IDE.png
ADDED
Binary file
|
Binary file
|
Binary file
|
data/images/asahi-1.jpg
ADDED
Binary file
|
data/images/asahi-2.jpg
ADDED
Binary file
|
data/images/asahi-3.jpg
ADDED
Binary file
|
data/images/bytecode.png
ADDED
Binary file
|
data/images/co2.png
ADDED
Binary file
|
data/images/co2_demo.png
ADDED
Binary file
|
Binary file
|
data/images/esp32.jpg
ADDED
Binary file
|
data/images/fuzz.png
ADDED
Binary file
|
data/images/hasumi.jpg
ADDED
Binary file
|
Binary file
|
Binary file
|
data/images/kamos.jpg
ADDED
Binary file
|
data/images/mark32.png
ADDED
Binary file
|
data/images/mark48.png
ADDED
Binary file
|
data/images/mark64.png
ADDED
Binary file
|
data/images/mobile.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,720 @@
|
|
1
|
+
= mruby/c: Running on Less Than 64KB RAM Microcontroller
|
2
|
+
|
3
|
+
# : subtitle
|
4
|
+
# サブタイトル
|
5
|
+
: author
|
6
|
+
HASUMI Hitoshi @hasumikin
|
7
|
+
# : institution
|
8
|
+
# 所属
|
9
|
+
# : content-source
|
10
|
+
# イベント名
|
11
|
+
# : date
|
12
|
+
# November 18, 2019
|
13
|
+
: allotted-time
|
14
|
+
38m
|
15
|
+
: theme
|
16
|
+
theme
|
17
|
+
|
18
|
+
= Me
|
19
|
+
* HASUMI Hitoshi\n@hasumikin
|
20
|
+
* Live in Matsue city,\na holy place of Ruby
|
21
|
+
* Sake 🍶\nSoba 🍜\nCoffee ☕
|
22
|
+
# image
|
23
|
+
# src = images/hasumi.jpg
|
24
|
+
# align = right
|
25
|
+
# relative-height = 80
|
26
|
+
# relative_margin_left = 25
|
27
|
+
|
28
|
+
= Me
|
29
|
+
# image
|
30
|
+
# src = images/monstarlab.png
|
31
|
+
# relative_width = 104
|
32
|
+
# relative_margin_top = -1
|
33
|
+
|
34
|
+
= Me
|
35
|
+
# image
|
36
|
+
# src = images/monstarlab_webpage.png
|
37
|
+
# relative_width = 104
|
38
|
+
# relative_margin_top = -2
|
39
|
+
== prop
|
40
|
+
: hide-title
|
41
|
+
true
|
42
|
+
|
43
|
+
= FUZZ
|
44
|
+
# image
|
45
|
+
# src = images/fuzz.png
|
46
|
+
# relative_width = 105
|
47
|
+
# relative_margin_top = -1
|
48
|
+
|
49
|
+
= Me
|
50
|
+
# image
|
51
|
+
# src = images/松江城_Matsue.rb.jpg
|
52
|
+
# relative_width = 105
|
53
|
+
# relative_margin_top = -7
|
54
|
+
== prop
|
55
|
+
: hide-title
|
56
|
+
true
|
57
|
+
|
58
|
+
= hide title
|
59
|
+
(('tag:center'))\n\n\n
|
60
|
+
(('tag:small:Chapter 1'))\n
|
61
|
+
(('tag:xx-large:Introduction'))
|
62
|
+
== prop
|
63
|
+
: hide-title
|
64
|
+
true
|
65
|
+
|
66
|
+
= Terminology
|
67
|
+
* mruby/c
|
68
|
+
* A language implementation I will talk about today
|
69
|
+
* I say mrubyc since ((*/c*)) [slˈæʃ síː] is hard to pronounce
|
70
|
+
* Microcontroller
|
71
|
+
* Small computer contains CPU, memory and programmable I/O peripherals
|
72
|
+
|
73
|
+
= Terminology
|
74
|
+
* RTOS
|
75
|
+
* Real-time OS. Usually used for microcontroller
|
76
|
+
* Task
|
77
|
+
* Almost equivalent to `Thread` in Linux. We say `Task` in microcontroller world
|
78
|
+
|
79
|
+
= Terminology
|
80
|
+
* 旭日酒造 (Asahi-Shuzo)
|
81
|
+
* Shuzo means `Sake brewery`
|
82
|
+
* One of the best Japanese Sake brewery
|
83
|
+
* FYI, Asahi Breweries (famous for SUPER DRY) has no concern with Asahi-Shuzo
|
84
|
+
* Asahi-Shuzo and I make an IoT system using mruby/c
|
85
|
+
|
86
|
+
= Why microcontroller?
|
87
|
+
* I don't use single board computer like Raspberry Pi for production environment.
|
88
|
+
* I use microcontroller, instead
|
89
|
+
* It starts immediately right after plugged in
|
90
|
+
* End-users, brewery workers in my case, can use it simply like home electical appliance
|
91
|
+
|
92
|
+
= Why microcontroller?
|
93
|
+
* Microcontroller can run without OS
|
94
|
+
* So-called `Bare Metal`
|
95
|
+
* You can narrow security issue list
|
96
|
+
* Many a malware aims at Linux or Windows platform as a target
|
97
|
+
* You don't need to consider unnecessary deamon
|
98
|
+
* You don't need to do `apt upgrade`
|
99
|
+
* (RasPi can be bare metal device if you want)
|
100
|
+
|
101
|
+
= Why microcontroller?
|
102
|
+
* Low energy
|
103
|
+
* Rarely overheated
|
104
|
+
* Many choices of power supply
|
105
|
+
* Mass production
|
106
|
+
* You can choose appropriate chipset (number of GPIO, memory size, etc.) for your application
|
107
|
+
* Cost advantage for parts supply and subcontractor manufacturing
|
108
|
+
|
109
|
+
= Which microcontroller?
|
110
|
+
|
111
|
+
= Which microcontroller?
|
112
|
+
# image
|
113
|
+
# src = images/psoc5lp_chip.jpg
|
114
|
+
# align = center
|
115
|
+
# relative-height = 45
|
116
|
+
* e.g. CYPRESS PSoC5LP
|
117
|
+
* 32 bit Arm Cortex-M3 CPU
|
118
|
+
* Flash: 256KB
|
119
|
+
* SRAM: 64KB (target size of mruby/c)
|
120
|
+
|
121
|
+
= Which microcontroller?
|
122
|
+
# image
|
123
|
+
# src = images/esp32.jpg
|
124
|
+
# align = center
|
125
|
+
# relative-height = 50
|
126
|
+
* e.g. Espressif ESP-WROOM-32 (ESP32)
|
127
|
+
* 32 bit dual core LX6 CPU
|
128
|
+
* Flash: 4MB
|
129
|
+
* SRAM: 520KB
|
130
|
+
|
131
|
+
= My IoT project
|
132
|
+
|
133
|
+
= My IoT project
|
134
|
+
* IoT system for Sake brewing
|
135
|
+
* PSoC5LP
|
136
|
+
* Delivered to actual brew work in January 2018
|
137
|
+
* Devices post temperature of Sake ingredient in brewing, surrounding temperature and humidity to server
|
138
|
+
* Data is displayed on mobile app
|
139
|
+
|
140
|
+
= photo
|
141
|
+
# image
|
142
|
+
# src = images/asahi-2.jpg
|
143
|
+
# relative_width = 105
|
144
|
+
# relative_margin_top = -3
|
145
|
+
== prop
|
146
|
+
: hide-title
|
147
|
+
true
|
148
|
+
|
149
|
+
= photo
|
150
|
+
# image
|
151
|
+
# src = images/asahi-3.jpg
|
152
|
+
# relative_height = 110
|
153
|
+
# relative_margin_top = -3
|
154
|
+
== prop
|
155
|
+
: hide-title
|
156
|
+
true
|
157
|
+
|
158
|
+
= photo
|
159
|
+
# image
|
160
|
+
# src = images/asahi-1.jpg
|
161
|
+
# relative_height = 110
|
162
|
+
# relative_margin_top = -3
|
163
|
+
== prop
|
164
|
+
: hide-title
|
165
|
+
true
|
166
|
+
|
167
|
+
= My IoT project
|
168
|
+
# image
|
169
|
+
# src = images/kamos.jpg
|
170
|
+
# align = center
|
171
|
+
# relative-height = 100
|
172
|
+
|
173
|
+
= My IoT project
|
174
|
+
# image
|
175
|
+
# src = images/collage01.jpg
|
176
|
+
# align = center
|
177
|
+
# relative-height = 100
|
178
|
+
|
179
|
+
= My IoT project
|
180
|
+
# image
|
181
|
+
# src = images/mobile.png
|
182
|
+
# align = center
|
183
|
+
# relative-height = 100
|
184
|
+
|
185
|
+
= IoT in field makes you hurry
|
186
|
+
* Imagine,
|
187
|
+
* You have to go back and forth between dark 5℃ (=41°F) storage cellar and humid 35℃ (=95°F) rice mold room
|
188
|
+
* Brewery workers run around
|
189
|
+
* You have to amend your firmware with your small laptop in 10 minutes
|
190
|
+
* You will thank Ruby's descriptiveness and agility
|
191
|
+
|
192
|
+
= photo
|
193
|
+
# image
|
194
|
+
# src = images/rubylabeljujiasahi.jpg
|
195
|
+
# relative_width = 105
|
196
|
+
# relative_margin_top = -7
|
197
|
+
== prop
|
198
|
+
: hide-title
|
199
|
+
true
|
200
|
+
|
201
|
+
= photo
|
202
|
+
# image
|
203
|
+
# src = images/rubykaigi2020.png
|
204
|
+
# relative_width = 105
|
205
|
+
# relative_margin_top = -1
|
206
|
+
== prop
|
207
|
+
: hide-title
|
208
|
+
true
|
209
|
+
|
210
|
+
= Demo
|
211
|
+
* CO(('sub:2')) concentration
|
212
|
+
* 400ppm : Atmospheric
|
213
|
+
* 1000ppm : Your programming speed decreases
|
214
|
+
* 1500ppm : FYI, tomatoes ((*🍅*)) may grow well
|
215
|
+
* > 2000ppm : Sleepiness, headache
|
216
|
+
* > 40000ppm : 💀
|
217
|
+
* (Please look at the screen)
|
218
|
+
|
219
|
+
= Demo
|
220
|
+
* My device is taking CO(('sub:2')) concentration
|
221
|
+
* CO(('sub:2')) may increase because of your breathing
|
222
|
+
|
223
|
+
= Demo
|
224
|
+
* My device is taking CO(('sub:2')) concentration
|
225
|
+
* CO(('sub:2')) may increase because of your breathing
|
226
|
+
* I will prove that it is due to CO(('sub:2')) if you fell asleep while I was speaking
|
227
|
+
|
228
|
+
(('tag:center'))\n
|
229
|
+
(('tag:xx-large:😴'))
|
230
|
+
|
231
|
+
= Bugaboos in IoT 👻
|
232
|
+
|
233
|
+
= Bugaboos in IoT 👻
|
234
|
+
* Peripheral equipments ...★
|
235
|
+
* Circuit, wiring and housing
|
236
|
+
* Printed circuit board = PCB
|
237
|
+
* Soldering ...★
|
238
|
+
* Firmware with C, mruby and mruby/c ...★
|
239
|
+
* Network, TCP/IP, Bluetooth, etc.
|
240
|
+
(('tag:right'))
|
241
|
+
★...I will cover these topics today
|
242
|
+
|
243
|
+
= Peripheral equipments
|
244
|
+
|
245
|
+
= Peripheral equipments
|
246
|
+
* Very important to check the part before writing application code
|
247
|
+
* Do equipments like sensor or communication module work as its spec sheets?
|
248
|
+
* Whether or not the equipment is broken (sometimes broken by soldering heat 😭)
|
249
|
+
* Combining parts is unrevertable
|
250
|
+
* We don't have a Git for hardware.
|
251
|
+
|
252
|
+
= Peripheral equipments
|
253
|
+
# image
|
254
|
+
# src = images/raspberrypi.jpg
|
255
|
+
# relative-height = 55
|
256
|
+
|
257
|
+
* Raspberry Pi & CRuby are great for pre-prototyping
|
258
|
+
* Use breadboard or make PCB for experiment
|
259
|
+
|
260
|
+
= CRuby and serial port
|
261
|
+
# enscript ruby
|
262
|
+
# Notice: This is CRuby for RasPi
|
263
|
+
require "rubyserial"
|
264
|
+
require "timeout"
|
265
|
+
sp = Serial.new "/dev/serial0", 9600, 8
|
266
|
+
loop do
|
267
|
+
puts "[command]"
|
268
|
+
command = gets
|
269
|
+
sp.write command.sub("\n", "\r") # replace LF if needed
|
270
|
+
sleep 0.1
|
271
|
+
result = ""
|
272
|
+
begin
|
273
|
+
Timeout.timeout(10) do
|
274
|
+
loop do
|
275
|
+
line = sp.read(128)
|
276
|
+
break if line == "" && result != ""
|
277
|
+
result << line
|
278
|
+
sleep 0.1
|
279
|
+
end
|
280
|
+
puts "=> " + result
|
281
|
+
end
|
282
|
+
rescue Timeout::Error
|
283
|
+
|
284
|
+
= CRuby and serial port
|
285
|
+
# enscript bash
|
286
|
+
$ serial_communication_test.rb
|
287
|
+
[command]
|
288
|
+
AT # command
|
289
|
+
=> OK # response
|
290
|
+
[command]
|
291
|
+
AT+CIMI # command
|
292
|
+
=> 123456789012 # response
|
293
|
+
[command]
|
294
|
+
AT+XXX # command
|
295
|
+
=> error # response
|
296
|
+
|
297
|
+
= Soldering
|
298
|
+
|
299
|
+
= Soldering
|
300
|
+
# image
|
301
|
+
# src = images/unsoldered.jpg
|
302
|
+
# relative-width = 30
|
303
|
+
|
304
|
+
* It often works even if you leave a pin unsoldered on surface mounting
|
305
|
+
* Because the pin touches circuit's plate
|
306
|
+
* Then, it will come not to work one day
|
307
|
+
|
308
|
+
= Soldering
|
309
|
+
# image
|
310
|
+
# src = images/unsoldered-2.png
|
311
|
+
# relative-width = 30
|
312
|
+
|
313
|
+
* Discovering this kind of bug is much more difficult than software bug
|
314
|
+
* My teacher said "All the cause of failure, it is ((*impatience*))"
|
315
|
+
|
316
|
+
= hide title
|
317
|
+
(('tag:center'))\n\n\n
|
318
|
+
(('tag:small:Chapter 2'))\n
|
319
|
+
(('tag:xx-large:mruby/c'))
|
320
|
+
== prop
|
321
|
+
: hide-title
|
322
|
+
true
|
323
|
+
|
324
|
+
= What is mruby?
|
325
|
+
|
326
|
+
= What is mruby?
|
327
|
+
* github.com/mruby/mruby
|
328
|
+
* Another implemantation of Ruby for general embedded usage
|
329
|
+
* Easily combined with system programming like C/C++
|
330
|
+
* e.g. ngx_mruby is a popular product of mruby
|
331
|
+
* Good for making command line tool as one-binary executable
|
332
|
+
|
333
|
+
= What is mruby((*/c*))?
|
334
|
+
|
335
|
+
= What is mruby((*/c*))?
|
336
|
+
* github.com/mrubyc/mrubyc
|
337
|
+
* Yet another implementation of mruby
|
338
|
+
* `/c` symbolizes compact, concurrent and capability
|
339
|
+
* Especially dedicated to one-chip microcontroller
|
340
|
+
|
341
|
+
= Bytecode is a common stuff
|
342
|
+
* They are compiled by `mrbc` (mruby compiler) and each VM execute bytecode
|
343
|
+
# image
|
344
|
+
# src = images/mruby_and_mrubyc.png
|
345
|
+
# align = center
|
346
|
+
# relative-height = 100
|
347
|
+
|
348
|
+
= Bytecode?
|
349
|
+
* A kind of intermediate representation
|
350
|
+
* mruby bytecode is designed for mruby VM
|
351
|
+
* mruby VM dynamically interprets the bytecode and processes the application
|
352
|
+
|
353
|
+
= HEX dump of bytecode
|
354
|
+
(('tag:center'))\n
|
355
|
+
Looks like this if you compile\n`puts "Hello World!"`
|
356
|
+
\n
|
357
|
+
|
358
|
+
# enscript C
|
359
|
+
5249 5445 3030 3036 9a78 0000 0062 4d41 RITE0006.x...bMA
|
360
|
+
545a 3030 3030 4952 4550 0000 0044 3030 TZ0000IREP...D00
|
361
|
+
3032 0000 0060 0001 0004 0000 0000 000c 02...`..........
|
362
|
+
1001 4f02 002e 0100 0137 0167 0000 0001 ..O......7.g....
|
363
|
+
0000 0c48 656c 6c6f 2057 6f72 6c64 2100 ...Hello World!.
|
364
|
+
0000 0100 0470 7574 7300 454e 4400 0000 .....puts.END...
|
365
|
+
0008 ..
|
366
|
+
|
367
|
+
= mruby on microcontroller
|
368
|
+
* RTOS (Real-Time OS) manages mruby VMs in order to realize multi tasking
|
369
|
+
# image
|
370
|
+
# src = images/mruby_and_mrubyc-mruby.png
|
371
|
+
# align = center
|
372
|
+
# relative-height = 100
|
373
|
+
|
374
|
+
= mruby/c on microcontroller
|
375
|
+
* mruby/c has its own mechanism to manage multi tasks: ((*rrt0*))
|
376
|
+
# image
|
377
|
+
# src = images/mruby_and_mrubyc-mrubyc.png
|
378
|
+
# align = center
|
379
|
+
# relative-height = 100
|
380
|
+
|
381
|
+
= mruby and mruby/c
|
382
|
+
# RT
|
383
|
+
|
384
|
+
mruby, mruby/c
|
385
|
+
|
386
|
+
v1.0.0 in Jan 2014, v1.0 in Jan 2017
|
387
|
+
for general embedded software, for one-chip microcontroller
|
388
|
+
mrbgems, no package manager
|
389
|
+
RAM < 200KB ...(*), RAM < 40KB ...(*)
|
390
|
+
|
391
|
+
|
392
|
+
(('tag:center'))\n
|
393
|
+
(('tag:xx-small:(*)...It depends on the situation'))
|
394
|
+
|
395
|
+
= mruby/c's Virtual Machine
|
396
|
+
* Much smaller than mruby's one
|
397
|
+
* That's why mruby/c runs on smaller RAM
|
398
|
+
* Accordingly, mruby/c has ((*less*)) functionality than mruby and CRuby
|
399
|
+
|
400
|
+
= How ((*less*))?
|
401
|
+
|
402
|
+
= How ((*less*))? - For example
|
403
|
+
* mruby/c doesn't have module, hence there is no Kernel module
|
404
|
+
* Then you must wonder how can you `#puts`?
|
405
|
+
* In mruby/c, `#puts` is implemented in Object class
|
406
|
+
* mruby/c doesn't have #send, #eval, and #method_missing, etc.
|
407
|
+
|
408
|
+
= How ((*less*))? - For example
|
409
|
+
* The full list of mruby/c's classes
|
410
|
+
* Array, FalseClass, Fixnum, Float, Hash, Math, Mutex, NilClass, Numeric, Object, Proc, Range, String, Symbol, TrueClass, VM
|
411
|
+
|
412
|
+
= Despite the fact,
|
413
|
+
* No problem in practical usage of microcontroller
|
414
|
+
* As far as IoT goes, mruby/c is enough Ruby
|
415
|
+
* We can fully develop firmwares with these features of mruby/c
|
416
|
+
|
417
|
+
= How does mruby/c work
|
418
|
+
# enscript bash
|
419
|
+
~/project/sample_project
|
420
|
+
├─ main.c
|
421
|
+
├─ mrblib
|
422
|
+
│ ├─ task_1.rb
|
423
|
+
│ └─ task_2.rb
|
424
|
+
└─ src
|
425
|
+
├─ task_1.c
|
426
|
+
└─ task_2.c
|
427
|
+
|
428
|
+
* task_*.c is compliled bytecode from task_*.rb
|
429
|
+
|
430
|
+
= How does mruby/c work
|
431
|
+
# enscript c
|
432
|
+
/* main.c */
|
433
|
+
#include "src/task_1.c"
|
434
|
+
#include "src/task_2.c"
|
435
|
+
// using 40KB RAM for VM heap in this case
|
436
|
+
#define MEMORY_SIZE (1024 * 40)
|
437
|
+
static uint8_t memory_pool[MEMORY_SIZE];
|
438
|
+
int main(void) {
|
439
|
+
mrbc_init(memory_pool, MEMORY_SIZE);
|
440
|
+
mrbc_create_task(task_1, 0);
|
441
|
+
mrbc_create_task(task_2, 0);
|
442
|
+
mrbc_run(); // 2 tasks run concurrently!
|
443
|
+
return 0;
|
444
|
+
}
|
445
|
+
|
446
|
+
= How does mruby/c work
|
447
|
+
* We can run easily multiple VMs with ((*concurrency*)) feature of ((*rrt0*))
|
448
|
+
* You might be disappointed to know you have to write C
|
449
|
+
* Yes, we have to write ((*main.c*))
|
450
|
+
* Don't worry, it's almost boilerplate code
|
451
|
+
|
452
|
+
= hide title
|
453
|
+
(('tag:center'))\n\n
|
454
|
+
(('tag:small:Chapter 3'))\n
|
455
|
+
(('tag:xx-large:Application code'))\n(('tag:xx-large:and tools'))
|
456
|
+
== prop
|
457
|
+
: hide-title
|
458
|
+
true
|
459
|
+
|
460
|
+
= Application code
|
461
|
+
(('tag:center'))\n\n\n\n
|
462
|
+
github.com/hasumikin/co2_demo
|
463
|
+
|
464
|
+
= Application code
|
465
|
+
# enscript bash
|
466
|
+
~/project/co2_demo
|
467
|
+
├─ main.c
|
468
|
+
└─ mrblib
|
469
|
+
├─ loops
|
470
|
+
│ ├─ primary.rb
|
471
|
+
│ └─ secondary.rb
|
472
|
+
└─ models
|
473
|
+
├─ co2.rb
|
474
|
+
├─ led.rb
|
475
|
+
└─ thermistor.rb
|
476
|
+
|
477
|
+
= Application code
|
478
|
+
# enscript ruby
|
479
|
+
# loops/primary.rb
|
480
|
+
$co2 = Co2.new # Makes it global so that secondary task can use it
|
481
|
+
$thermistor = $thermistor.new
|
482
|
+
led = Led.new(19) # 19 is a pin number which LED connects
|
483
|
+
while true
|
484
|
+
co2 = $co2.concentrate
|
485
|
+
if co2 > 2000 # When CO2 reaches fatal level
|
486
|
+
5.times do # Turning LED on and off
|
487
|
+
led.turn_on
|
488
|
+
sleep 0.1
|
489
|
+
led.turn_off
|
490
|
+
sleep 0.1
|
491
|
+
end
|
492
|
+
else # Safe level
|
493
|
+
led.turn_off # Turns off
|
494
|
+
sleep 1
|
495
|
+
end
|
496
|
+
end
|
497
|
+
|
498
|
+
= Application code
|
499
|
+
(('tag:center'))\n\n\n\n
|
500
|
+
How does ((*Led#trun_on*)) work?
|
501
|
+
|
502
|
+
= Application code
|
503
|
+
# enscript ruby
|
504
|
+
# models/led.rb
|
505
|
+
class Led
|
506
|
+
def initialize(pin)
|
507
|
+
@pin = pin
|
508
|
+
gpio_init_output(@pin)
|
509
|
+
turn_off
|
510
|
+
end
|
511
|
+
def turn_on
|
512
|
+
gpio_set_level(@pin, 1) # high
|
513
|
+
end
|
514
|
+
def turn_off
|
515
|
+
gpio_set_level(@pin, 0) # low
|
516
|
+
end
|
517
|
+
end
|
518
|
+
|
519
|
+
= Application code
|
520
|
+
# enscript c
|
521
|
+
/* a part of main.c */
|
522
|
+
#include "models/led.c"
|
523
|
+
static void c_gpio_init_output(mrbc_vm *vm, mrbc_value *v, int argc) {
|
524
|
+
int pin = GET_INT_ARG(1);
|
525
|
+
// Function of microcontroller's library
|
526
|
+
gpio_set_direction(pin, GPIO_MODE_OUTPUT);
|
527
|
+
}
|
528
|
+
static void c_gpio_set_level(mrbc_vm *vm, mrbc_value *v, int argc){
|
529
|
+
int pin = GET_INT_ARG(1);
|
530
|
+
int level = GET_INT_ARG(2);
|
531
|
+
gpio_set_level(pin, level); // Function of microcontroller's library
|
532
|
+
}
|
533
|
+
int main(void){
|
534
|
+
...
|
535
|
+
mrbc_define_method(0, mrbc_class_object, "gpio_init_output",
|
536
|
+
c_gpio_init_output);
|
537
|
+
mrbc_define_method(0, mrbc_class_object, "gpio_set_level",
|
538
|
+
c_gpio_set_level);
|
539
|
+
...
|
540
|
+
}
|
541
|
+
|
542
|
+
= Application code
|
543
|
+
# enscript c
|
544
|
+
/* a part of main.c */
|
545
|
+
#include "models/co2.c"
|
546
|
+
static void c_get_co2(struct VM *vm, mrbc_value v[], int argc){
|
547
|
+
uint8_t command[] = { // Command to take CO2
|
548
|
+
0xFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79
|
549
|
+
};
|
550
|
+
uart_write_bytes(uart_num, (const char*)command, 9);
|
551
|
+
// ↑Write then ↓Read data
|
552
|
+
uint8_t data[10];
|
553
|
+
int length = 0;
|
554
|
+
length = uart_read_bytes(uart_num, data, length, 10);
|
555
|
+
mrbc_value array = mrbc_array_new( vm, 9 ); // mrubyc's variable
|
556
|
+
for( int i = 0; i < 9; i++ ) {
|
557
|
+
mrbc_value value = mrbc_fixnum_value(data[i]);
|
558
|
+
mrbc_array_set( &array, i, &value ); // Adding a value to array
|
559
|
+
}
|
560
|
+
SET_RETURN(array); // Returning the array object to mruby
|
561
|
+
}
|
562
|
+
int main(void){
|
563
|
+
...
|
564
|
+
mrbc_define_method(0, mrbc_class_object, "get_co2", c_get_co2);
|
565
|
+
...
|
566
|
+
}
|
567
|
+
|
568
|
+
= Application code
|
569
|
+
# enscript ruby
|
570
|
+
# models/co2.rb
|
571
|
+
class Co2
|
572
|
+
def concentrate
|
573
|
+
res = get_co2
|
574
|
+
# checks if the sensor works
|
575
|
+
if res[0] == 255 && res[1] == 134
|
576
|
+
res[2] * 256 + res[3]
|
577
|
+
else
|
578
|
+
0
|
579
|
+
end
|
580
|
+
end
|
581
|
+
end
|
582
|
+
|
583
|
+
= Application code
|
584
|
+
* Trivial tip to reduce memory usage
|
585
|
+
* C function can return String instead of Array
|
586
|
+
* `mrbc_array_new` will allocate larger memory than `mrbc_string_new`
|
587
|
+
* So, you can use String instead of Array if memory becomes short
|
588
|
+
* Remember STRING of C is just an array of char and '\0'
|
589
|
+
|
590
|
+
= Application code
|
591
|
+
# enscript ruby
|
592
|
+
# loops/secondary.rb
|
593
|
+
http_client = HttpClient.new("http://data.server")
|
594
|
+
while true
|
595
|
+
co2 = $co2.concentrate
|
596
|
+
temperature = $thermistor.temperature
|
597
|
+
if co2 > 0 # No trouble
|
598
|
+
data = "co2=#{co2}&temperature=#{temperature}"
|
599
|
+
http_client.post(data)
|
600
|
+
sleep 180
|
601
|
+
else # A trouble happens?
|
602
|
+
sleep 3 # Or you can retry
|
603
|
+
end
|
604
|
+
end
|
605
|
+
|
606
|
+
= Dev tools for mruby/c
|
607
|
+
|
608
|
+
= Dev tools for mruby/c
|
609
|
+
* mrubyc-utils
|
610
|
+
* mrubyc-test
|
611
|
+
* mrubyc-debugger
|
612
|
+
|
613
|
+
= Dev tools for mruby/c
|
614
|
+
(('tag:center'))\n\n\n
|
615
|
+
I am trying to make mruby/c development ((*Rubyish*))
|
616
|
+
|
617
|
+
= Rubyish? - IMHO
|
618
|
+
* Unix/Linux
|
619
|
+
* Command line
|
620
|
+
* No-IDE (as far as possible)
|
621
|
+
|
622
|
+
= Rubyish? - IMHO
|
623
|
+
* Unix/Linux
|
624
|
+
* Command line
|
625
|
+
* No-IDE (as far as possible)
|
626
|
+
|
627
|
+
(('tag:center'))\n
|
628
|
+
Taking full advantage of\nour Laptop and Ruby World
|
629
|
+
|
630
|
+
= mrubyc-utils
|
631
|
+
* github.com/hasumikin/mrubyc-utils
|
632
|
+
* One-binary tool made with mruby
|
633
|
+
* Helps to install boilerplate of application
|
634
|
+
* Utility subcommands like...
|
635
|
+
|
636
|
+
= mrubyc-utils
|
637
|
+
$ mrubyc-utils classes
|
638
|
+
- Array
|
639
|
+
- FalseClass
|
640
|
+
- Fixnum
|
641
|
+
- Float
|
642
|
+
- Hash
|
643
|
+
- Math
|
644
|
+
- Mutex
|
645
|
+
- NilClass
|
646
|
+
- Numeric
|
647
|
+
- Object
|
648
|
+
- Proc
|
649
|
+
- Range
|
650
|
+
- String
|
651
|
+
- Symbol
|
652
|
+
- TrueClass
|
653
|
+
- VM
|
654
|
+
|
655
|
+
= mrubyc-utils
|
656
|
+
$ mrubyc-utils methods --class=array
|
657
|
+
Array
|
658
|
+
- + - inspect
|
659
|
+
- << - join
|
660
|
+
- [] - last
|
661
|
+
- []= - length
|
662
|
+
- at - max
|
663
|
+
- clear - min
|
664
|
+
- collect - minmax
|
665
|
+
- collect! - new
|
666
|
+
- count - pop
|
667
|
+
- delete_at - push
|
668
|
+
- dup - shift
|
669
|
+
- each - size
|
670
|
+
- each_index - to_s
|
671
|
+
- each_with_index - unshift
|
672
|
+
- empty? < Object
|
673
|
+
- first - !
|
674
|
+
- index ...
|
675
|
+
|
676
|
+
= mrubyc-test
|
677
|
+
* github.com/mrubyc/mrubyc-test
|
678
|
+
* Unit testing framework
|
679
|
+
* A RubyGem implemented with CRuby
|
680
|
+
* Supports stub and mock
|
681
|
+
* Official test tool of mruby/c dev team
|
682
|
+
|
683
|
+
= mrubyc-test
|
684
|
+
* Gathers information from app and test code
|
685
|
+
* Internally generates stub and mock methods
|
686
|
+
* Makes all-in-one script: ((*test.rb*))
|
687
|
+
# image
|
688
|
+
# src = images/how-mrubyc-test-works.png
|
689
|
+
# align = center
|
690
|
+
# relative-width = 100
|
691
|
+
|
692
|
+
= mrubyc-debugger
|
693
|
+
* github.com/hasumikin/mrubyc-debugger
|
694
|
+
* Debugger for mutiple infinite loops
|
695
|
+
|
696
|
+
= DEMO
|
697
|
+
(('tag:center'))\n\n\n\n
|
698
|
+
github.com/hasumikin/\nmrubyc-debugger
|
699
|
+
|
700
|
+
= DEMO
|
701
|
+
(('tag:center'))\n\n\n\n
|
702
|
+
How is CO(('sub:2')) going?
|
703
|
+
|
704
|
+
= DEMO (added after the Conf)
|
705
|
+
# image
|
706
|
+
# src = images/co2.png
|
707
|
+
# align = center
|
708
|
+
# relative-width = 100
|
709
|
+
|
710
|
+
= Conclusion
|
711
|
+
|
712
|
+
= Conclusion
|
713
|
+
(('tag:center'))\n\n
|
714
|
+
(('tag:xx-large:You should refresh air 💨'))
|
715
|
+
|
716
|
+
= Thank you!
|
717
|
+
# image
|
718
|
+
# src = images/rubylabel.jpg
|
719
|
+
# align = center
|
720
|
+
# relative-height = 110
|
data/theme.rb
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
# puts font_families.sort
|
2
|
+
@xx_large_font_size = screen_size(12 * Pango::SCALE)
|
3
|
+
@x_large_font_size = screen_size(8 * Pango::SCALE)
|
4
|
+
@large_font_size = screen_size(7 * Pango::SCALE)
|
5
|
+
@normal_font_size = screen_size(4.5 * Pango::SCALE)
|
6
|
+
@small_font_size = screen_size(4 * Pango::SCALE)
|
7
|
+
@x_small_font_size = screen_size(3.5 * Pango::SCALE)
|
8
|
+
@xx_small_font_size = screen_size(3 * Pango::SCALE)
|
9
|
+
|
10
|
+
@font_family = find_font_family('Roboto Slab')
|
11
|
+
@monospace_font_family = 'Ricty Discord'
|
12
|
+
|
13
|
+
@default_headline_line_color = '#FFB400'
|
14
|
+
@default_headline_line_width = 8
|
15
|
+
@default_headline_line_expand = false
|
16
|
+
|
17
|
+
set_graffiti_color "#FF2B22"
|
18
|
+
set_graffiti_line_width 10
|
19
|
+
|
20
|
+
#@table_frame_color = "#ffffff"
|
21
|
+
#@table_fill_color = "#0f0428"
|
22
|
+
#@table_body_frame_color = "#ffffff"
|
23
|
+
#@table_body_fill_color = "#3f3468"
|
24
|
+
#@table_head_frame_color = "#ffffff"
|
25
|
+
#@table_head_fill_color = "#rf0428"
|
26
|
+
|
27
|
+
#@preformatted_fill_color = '#000000'
|
28
|
+
# @preformatted_centering = true
|
29
|
+
@space = screen_y(1)
|
30
|
+
|
31
|
+
@margin_left = 300
|
32
|
+
|
33
|
+
@image_slide_number_start_flag_color = "#FFB400"
|
34
|
+
@image_slide_number_goal_flag_color = "#FF2B22"
|
35
|
+
|
36
|
+
include_theme('default')
|
37
|
+
|
38
|
+
match(Slide, HeadLine) do |heads|
|
39
|
+
heads.prop_set("size", @large_font_size)
|
40
|
+
heads.prop_set("weight", "normal")
|
41
|
+
set_font_family(heads)
|
42
|
+
end
|
43
|
+
match(Slide) do |slides|
|
44
|
+
#slides.prop_set("foreground", "#FF2B22")
|
45
|
+
slides.prop_set("foreground", "black")
|
46
|
+
end
|
47
|
+
|
48
|
+
@slide_headline_hide = true
|
49
|
+
match TitleSlide do |slides|
|
50
|
+
slides.margin_left = @margin_right
|
51
|
+
end
|
52
|
+
match TitleSlide, Title do |titles|
|
53
|
+
#titles.prop_set "foreground", "#FF2B22"
|
54
|
+
titles.prop_set "foreground", "#FFB400"
|
55
|
+
titles.margin_top = -80
|
56
|
+
end
|
57
|
+
match TitleSlide, Author do |authors|
|
58
|
+
#authors.prop_set "foreground", "white"
|
59
|
+
authors.prop_set "foreground", "#FFB400"
|
60
|
+
authors.margin_top = 540
|
61
|
+
end
|
62
|
+
|
63
|
+
@title_slide_background_image = 'images/Powerpoint Hold Slide.png'
|
64
|
+
include_theme("title-slide-background-image")
|
65
|
+
|
66
|
+
@slide_background_image = 'images/Powerpoint Content Slide.png'
|
67
|
+
include_theme("slide-background-image")
|
68
|
+
|
69
|
+
#@slide_logo_image = 'images/mark48.png'
|
70
|
+
#include_theme('slide-logo')
|
71
|
+
|
72
|
+
@item_image = 'images/mark48.png'
|
73
|
+
|
74
|
+
include_theme("default-item-mark")
|
75
|
+
|
76
|
+
add_image_path("rabbit-images")
|
77
|
+
|
78
|
+
slide_body = [Slide, Body]
|
79
|
+
item_list_item = [ItemList, ItemListItem]
|
80
|
+
|
81
|
+
indent = 70
|
82
|
+
|
83
|
+
match(*(slide_body + (item_list_item * 1))) do |items|
|
84
|
+
name = "item1"
|
85
|
+
items.delete_pre_draw_proc_by_name(name)
|
86
|
+
items.delete_post_draw_proc_by_name(name)
|
87
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
88
|
+
end
|
89
|
+
|
90
|
+
match(*(slide_body + (item_list_item * 2))) do |items|
|
91
|
+
name = "item2"
|
92
|
+
items.delete_pre_draw_proc_by_name(name)
|
93
|
+
items.delete_post_draw_proc_by_name(name)
|
94
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
95
|
+
end
|
96
|
+
|
97
|
+
match(*(slide_body + (item_list_item * 3))) do |items|
|
98
|
+
name = "item3"
|
99
|
+
items.delete_pre_draw_proc_by_name(name)
|
100
|
+
items.delete_post_draw_proc_by_name(name)
|
101
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
102
|
+
end
|
103
|
+
|
104
|
+
enum_list_item = [EnumList, EnumListItem]
|
105
|
+
|
106
|
+
match(*(slide_body + enum_list_item + item_list_item)) do |items|
|
107
|
+
name = "enum-item1"
|
108
|
+
items.delete_pre_draw_proc_by_name(name)
|
109
|
+
items.delete_post_draw_proc_by_name(name)
|
110
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
111
|
+
end
|
112
|
+
|
113
|
+
match(*(slide_body + enum_list_item + (item_list_item * 2))) do |items|
|
114
|
+
name = "enum-item2"
|
115
|
+
items.delete_pre_draw_proc_by_name(name)
|
116
|
+
items.delete_post_draw_proc_by_name(name)
|
117
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
118
|
+
end
|
metadata
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbit-slide-hasumikin-RubyConf2019
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2019.11.18.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- HASUMI Hitoshi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-11-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rabbit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.0.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.0.2
|
27
|
+
description: A presentation slide for RubyConf 2019 at JW Marriott Nashville on Nov
|
28
|
+
18, 2019
|
29
|
+
email:
|
30
|
+
- hasumikin@gmail.com
|
31
|
+
executables: []
|
32
|
+
extensions: []
|
33
|
+
extra_rdoc_files: []
|
34
|
+
files:
|
35
|
+
- ".rabbit"
|
36
|
+
- README.rd
|
37
|
+
- Rakefile
|
38
|
+
- config.yaml
|
39
|
+
- images/IDE.png
|
40
|
+
- images/Powerpoint Content Slide.png
|
41
|
+
- images/Powerpoint Hold Slide.png
|
42
|
+
- images/asahi-1.jpg
|
43
|
+
- images/asahi-2.jpg
|
44
|
+
- images/asahi-3.jpg
|
45
|
+
- images/bytecode.png
|
46
|
+
- images/co2.png
|
47
|
+
- images/co2_demo.png
|
48
|
+
- images/collage01.jpg
|
49
|
+
- images/esp32.jpg
|
50
|
+
- images/fuzz.png
|
51
|
+
- images/hasumi.jpg
|
52
|
+
- images/how-mrubyc-test-works.png
|
53
|
+
- images/juji-asahi.jpg
|
54
|
+
- images/kamos.jpg
|
55
|
+
- images/mark32.png
|
56
|
+
- images/mark48.png
|
57
|
+
- images/mark64.png
|
58
|
+
- images/mobile.png
|
59
|
+
- images/monstarlab.png
|
60
|
+
- images/monstarlab_webpage.png
|
61
|
+
- images/mruby_and_mrubyc-mruby.png
|
62
|
+
- images/mruby_and_mrubyc-mrubyc.png
|
63
|
+
- images/mruby_and_mrubyc.png
|
64
|
+
- images/psoc5lp_chip.jpg
|
65
|
+
- images/raspberrypi.jpg
|
66
|
+
- images/rubykaigi2020.png
|
67
|
+
- images/rubylabel.jpg
|
68
|
+
- images/rubylabeljujiasahi.jpg
|
69
|
+
- images/unsoldered-2.png
|
70
|
+
- images/unsoldered.jpg
|
71
|
+
- images/松江城_Matsue.rb.jpg
|
72
|
+
- mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.rab
|
73
|
+
- pdf/RubyConf2019-mrubyc-Running-on-Less-Than-64KB-RAM-Microcontroller.pdf
|
74
|
+
- theme.rb
|
75
|
+
homepage: https://slide.rabbit-shocker.org/authors/hasumikin/RubyConf2019/
|
76
|
+
licenses: []
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubygems_version: 3.0.3
|
94
|
+
signing_key:
|
95
|
+
specification_version: 4
|
96
|
+
summary: 'mruby/c: Running on Less Than 64KB RAM Microcontroller'
|
97
|
+
test_files: []
|