rabbit-slide-hasumikin-RubyKaigi-2019 2019.04.19.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rabbit +1 -0
- data/README.rd +24 -0
- data/Rakefile +17 -0
- data/RubyKaigi-2019--Practical-mrubyc-firmware-development-with-CRuby.rab +624 -0
- data/RubyKaigi-2019--Practical-mrubyc-firmware-development-with-CRuby.rab.pdf +0 -0
- data/config.yaml +23 -0
- data/images/NEW_ML_LOGO.png +0 -0
- data/images/bytecode.png +0 -0
- data/images/collage01.jpg +0 -0
- data/images/esp32.jpg +0 -0
- data/images/fuga.jpg +0 -0
- data/images/hasumi.jpg +0 -0
- data/images/how-mrubyc-test-works.png +0 -0
- data/images/kamos.jpg +0 -0
- data/images/kamos_2019.png +0 -0
- data/images/loops.png +0 -0
- data/images/mark32.png +0 -0
- data/images/mark48.png +0 -0
- data/images/mark64.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/rubykaigi2018.png +0 -0
- data/images/rubykaigi2019_keynote_sample-289.png +0 -0
- data/images/rubykaigi_bg_title-296.png +0 -0
- data/images/rubykaigi_keynote_bg-239.png +0 -0
- data/images/shinjiko.jpg +0 -0
- data/images/three_parts.png +0 -0
- data/images/three_parts_loop.png +0 -0
- data/images/three_parts_model.png +0 -0
- data/images/three_parts_peripheral.png +0 -0
- data/images/three_sources_0.png +0 -0
- data/images/three_sources_1.png +0 -0
- data/images/three_sources_2.png +0 -0
- data/images/three_sources_2_fuga_1.png +0 -0
- data/images/three_sources_2_fuga_2.png +0 -0
- data/images/three_sources_2_fuga_3.png +0 -0
- data/images/three_sources_2_fuga_4.png +0 -0
- data/images/three_sources_3.png +0 -0
- data/images/three_sources_4.png +0 -0
- data/images//346/235/276/346/261/237/345/237/216_Matsue.rb.16x9.jpg +0 -0
- data/images//346/235/276/346/261/237/345/237/216_Matsue.rb.jpg +0 -0
- data/pdf/RubyKaigi-2019-Practical-mrubyc-firmware-development-with-CRuby.pdf +0 -0
- data/theme.rb +97 -0
- metadata +107 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 9fb4cf832657583181ab5b1474fc09a2211ad84d0cdffc312e21b67177198b3f
|
4
|
+
data.tar.gz: c8388bd094b023c5887f1b555bc7a1d9c10d14231b55624404a84bda7bc88b76
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 3b10ae64e16fc83dc00c7cf5e3dd040f57a0e597c906468abdac9b83856dfde69c78b2ac70fd6f0159fc570758ae4f1641d95af553c9497f7ef72caef45a69db
|
7
|
+
data.tar.gz: b7a6e6edc848c14ba7fcb47fb6ad16848678b79a0ba1cd0f7868ef1f9fe456e8b0ce9cc6fbcf5edf222d99efef61a70b5f6a1cc92e24628c9a40c20a62af7602
|
data/.rabbit
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
RubyKaigi-2019--Practical-mrubyc-firmware-development-with-CRuby.rab
|
data/README.rd
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
= Practical mruby/c firmware development with CRuby
|
2
|
+
|
3
|
+
A talk of RubyKaigi 2019 in Fukuoka. Writing mruby/c firmware applications is like writing mrbgems. You need to make some C functions and mruby wrapper of them in order to handle peripherals like sensor, flash memory or BLE. Easy to imagine it's hard to develop for a team in a situation of TIGHT COUPLING, right? I will talk about some tools, mrubyc-test and mrubyc-debugger, which I made with CRuby for testing and debugging to keep our team slack coupling.
|
4
|
+
|
5
|
+
== 作者向け
|
6
|
+
|
7
|
+
=== 表示
|
8
|
+
|
9
|
+
rake
|
10
|
+
|
11
|
+
=== 公開
|
12
|
+
|
13
|
+
rake publish
|
14
|
+
|
15
|
+
== 閲覧者向け
|
16
|
+
|
17
|
+
=== インストール
|
18
|
+
|
19
|
+
gem install rabbit-slide-hasumikin-RubyKaigi-2019
|
20
|
+
|
21
|
+
=== 表示
|
22
|
+
|
23
|
+
rabbit rabbit-slide-hasumikin-RubyKaigi-2019.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("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
|
@@ -0,0 +1,624 @@
|
|
1
|
+
= Practical mruby/c firmware development with CRuby
|
2
|
+
|
3
|
+
: author
|
4
|
+
HASUMI Hitoshi @hasumikin
|
5
|
+
: content-source
|
6
|
+
RubyKaigi 2019
|
7
|
+
: date
|
8
|
+
April 19, 2019
|
9
|
+
: allotted-time
|
10
|
+
38m
|
11
|
+
: place
|
12
|
+
Fukuoka International Congress Center
|
13
|
+
: theme
|
14
|
+
theme
|
15
|
+
|
16
|
+
= Sake IoT project
|
17
|
+
# image
|
18
|
+
# src = images/kamos.jpg
|
19
|
+
# relative_height = 100
|
20
|
+
|
21
|
+
= Sake IoT project
|
22
|
+
# image
|
23
|
+
# src = images/collage01.jpg
|
24
|
+
# relative_height = 100
|
25
|
+
|
26
|
+
= what is mruby/c?
|
27
|
+
* github.com/mrubyc/mrubyc
|
28
|
+
* one of the mruby family
|
29
|
+
* `/c` symbolizes compact,\nconcurrent and capability
|
30
|
+
* especially dedicated to\none-chip microcontroller
|
31
|
+
# image
|
32
|
+
# src = images/psoc5lp_chip.jpg
|
33
|
+
# align = right
|
34
|
+
# relative_height = 70
|
35
|
+
|
36
|
+
= mruby and mruby/c
|
37
|
+
# RT
|
38
|
+
|
39
|
+
mruby, mruby/c
|
40
|
+
|
41
|
+
v1.0.0 in Jan 2014, v1.0 in Jan 2017
|
42
|
+
for general embedded software, for one-chip microcontroller
|
43
|
+
RAM < 400KB, RAM < 40KB
|
44
|
+
|
45
|
+
* sometimes mruby is still too big to run on microcontroller
|
46
|
+
|
47
|
+
= ((*both*)) mruby and mruby/c
|
48
|
+
* bytecodes are compiled by `mrbc`\nvirtual machine (VM) executes the bytecode
|
49
|
+
# image
|
50
|
+
# src = images/mruby_and_mrubyc.png
|
51
|
+
# align = center
|
52
|
+
# relative-height = 100
|
53
|
+
|
54
|
+
= bytecode
|
55
|
+
* a kind of intermediate representation
|
56
|
+
* virtual machine dynamically interprets the bytecode and processes the program
|
57
|
+
# image
|
58
|
+
# src = images/bytecode.png
|
59
|
+
# align = center
|
60
|
+
# relative-width = 100
|
61
|
+
|
62
|
+
= mruby on microcontroller
|
63
|
+
* RTOS (Real-Time OS) manages mruby VMs. RTOS has features like multi tasking, etc.
|
64
|
+
# image
|
65
|
+
# src = images/mruby_and_mrubyc-mruby.png
|
66
|
+
# align = center
|
67
|
+
# relative-height = 100
|
68
|
+
|
69
|
+
= mruby/c on microcontroller
|
70
|
+
* mruby/c has its own mechanism to manage the runtime: ((*rrt0*))
|
71
|
+
# image
|
72
|
+
# src = images/mruby_and_mrubyc-mrubyc.png
|
73
|
+
# align = center
|
74
|
+
# relative-height = 100
|
75
|
+
|
76
|
+
= mruby/c - virtual machine (VM)
|
77
|
+
* much smaller than mruby's one
|
78
|
+
* that's why mruby/c runs on smaller RAM
|
79
|
+
* accordingly, mruby/c has ((*less*)) functionality than mruby
|
80
|
+
|
81
|
+
= how ((*less*))?
|
82
|
+
|
83
|
+
= how ((*less*))? - for example
|
84
|
+
* mruby/c doesn't have module, hence there is no Kernel module
|
85
|
+
* then you must wonder how can you `#puts`?
|
86
|
+
* in mruby/c, `#puts` is implemented in Object class
|
87
|
+
|
88
|
+
= how ((*less*))? - for example
|
89
|
+
* mruby/c doesn't have #send, #eval, nor #method_missing
|
90
|
+
* moreover, mruby/c neither have your favorite features like TracePoint nor Refinements 😞
|
91
|
+
|
92
|
+
= how ((*less*))? - actually
|
93
|
+
* the full list of mruby/c's classes
|
94
|
+
* Array, FalseClass, Fixnum, Float, Hash, Math, Mutex, NilClass, Numeric, Object, Proc, Range, String, Symbol, TrueClass, VM
|
95
|
+
|
96
|
+
= despite the fact,
|
97
|
+
* no problem in practical use of microcontroller
|
98
|
+
* as far as IoT go, mruby/c is enough Ruby as I expect
|
99
|
+
* we can fully develop firmwares with features of mruby/c
|
100
|
+
|
101
|
+
= ((* *))
|
102
|
+
(('tag:center'))\n\n\n
|
103
|
+
(('tag:xx-large:So'))\n\n
|
104
|
+
(('tag:xx-large:というわけで'))
|
105
|
+
== プロパティ
|
106
|
+
: hide-title
|
107
|
+
true
|
108
|
+
|
109
|
+
= ((* *))
|
110
|
+
(('tag:center'))\n\n\n
|
111
|
+
(('tag:xx-large:Today's agenda'))\n\n
|
112
|
+
(('tag:x-large:きょうはこんな話をします'))
|
113
|
+
== プロパティ
|
114
|
+
: hide-title
|
115
|
+
true
|
116
|
+
|
117
|
+
= ((* *))
|
118
|
+
(('tag:center'))\n\n\n
|
119
|
+
(('tag:xx-large:Little more Rubyish'))
|
120
|
+
\n\n
|
121
|
+
(('tag:x-large:もうちょいRubyっぽくやろう'))
|
122
|
+
== プロパティ
|
123
|
+
: hide-title
|
124
|
+
true
|
125
|
+
|
126
|
+
= matsue.rb
|
127
|
+
# image
|
128
|
+
# src = images/松江城_Matsue.rb.16x9.jpg
|
129
|
+
# relative_width = 110
|
130
|
+
# relative_margin_top = -3
|
131
|
+
== prop
|
132
|
+
: hide-title
|
133
|
+
true
|
134
|
+
|
135
|
+
= mruby/c firmware is made up of three parts
|
136
|
+
* 1) peripheral API wrapper (C)
|
137
|
+
* 2) business logic (mruby)
|
138
|
+
* 3) infinite loop (mruby)
|
139
|
+
# image
|
140
|
+
# src = images/three_parts.png
|
141
|
+
# relative_width = 100
|
142
|
+
|
143
|
+
= mruby/c firmware is made up of three parts
|
144
|
+
* 1) peripheral API wrapper (C)
|
145
|
+
* 2) business logic (mruby) - ((*model*))
|
146
|
+
* 3) infinite loop (mruby) - ((*controller*))
|
147
|
+
# image
|
148
|
+
# src = images/three_parts.png
|
149
|
+
# relative_width = 100
|
150
|
+
|
151
|
+
= things make situation difficult
|
152
|
+
* peripheral API needs ((*real*)) hardware
|
153
|
+
* business logic needs peripheral APIs ((*really*)) work
|
154
|
+
* infinite loop needs ((*real*)) data from business logic
|
155
|
+
# image
|
156
|
+
# src = images/three_parts.png
|
157
|
+
# relative_width = 100
|
158
|
+
|
159
|
+
= mruby/c firmware is made up of three parts
|
160
|
+
* 1) ((*peripheral API wrapper (C)*))
|
161
|
+
* 2) business logic (mruby)
|
162
|
+
* 3) infinite loop (mruby)
|
163
|
+
# image
|
164
|
+
# src = images/three_parts_peripheral.png
|
165
|
+
# relative_width = 100
|
166
|
+
|
167
|
+
= peripheral API wapper
|
168
|
+
* https://rubykaigi.org/2018
|
169
|
+
# image
|
170
|
+
# src = images/rubykaigi2018.png
|
171
|
+
# relative_width = 100
|
172
|
+
|
173
|
+
= mruby/c firmware is made up of three parts
|
174
|
+
* 1) peripheral API (C)
|
175
|
+
* 2) ((*business logic (mruby)*))
|
176
|
+
* 3) infinite loop (mruby)
|
177
|
+
# image
|
178
|
+
# src = images/three_parts_model.png
|
179
|
+
# relative_width = 100
|
180
|
+
|
181
|
+
= mruby/c firmware is made up of three parts
|
182
|
+
# image
|
183
|
+
# src = images/three_sources_0.png
|
184
|
+
# align = center
|
185
|
+
# relative_height = 100
|
186
|
+
|
187
|
+
= mruby/c firmware is made up of three parts
|
188
|
+
# image
|
189
|
+
# src = images/three_sources_1.png
|
190
|
+
# align = center
|
191
|
+
# relative_height = 100
|
192
|
+
|
193
|
+
= mruby/c firmware is made up of three parts
|
194
|
+
# image
|
195
|
+
# src = images/three_sources_2.png
|
196
|
+
# align = center
|
197
|
+
# relative_height = 100
|
198
|
+
|
199
|
+
= mruby/c firmware is made up of three parts
|
200
|
+
# image
|
201
|
+
# src = images/three_sources_3.png
|
202
|
+
# align = center
|
203
|
+
# relative_height = 100
|
204
|
+
|
205
|
+
= mruby/c firmware is made up of three parts
|
206
|
+
# image
|
207
|
+
# src = images/three_sources_4.png
|
208
|
+
# align = center
|
209
|
+
# relative_height = 100
|
210
|
+
|
211
|
+
= by the way,
|
212
|
+
# image
|
213
|
+
# src = images/three_sources_2.png
|
214
|
+
# align = center
|
215
|
+
# relative_height = 100
|
216
|
+
|
217
|
+
= fuga?
|
218
|
+
# image
|
219
|
+
# src = images/three_sources_2_fuga_1.png
|
220
|
+
# align = center
|
221
|
+
# relative_height = 100
|
222
|
+
|
223
|
+
= what is fuga?
|
224
|
+
# image
|
225
|
+
# src = images/three_sources_2_fuga_4.png
|
226
|
+
# align = center
|
227
|
+
# relative_height = 100
|
228
|
+
|
229
|
+
= will calling fuga raise error?
|
230
|
+
# image
|
231
|
+
# src = images/three_sources_2_fuga_1.png
|
232
|
+
# align = center
|
233
|
+
# relative_height = 100
|
234
|
+
|
235
|
+
= methods still not implemented
|
236
|
+
* we often should write business logic without hitting peripherals
|
237
|
+
* it will cost a lot in some case
|
238
|
+
* it is possible the design of peripheral details might not be finished yet
|
239
|
+
* what you expect in this situation?
|
240
|
+
|
241
|
+
= ((* *))
|
242
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:Stub'))
|
243
|
+
== プロパティ
|
244
|
+
: hide-title
|
245
|
+
true
|
246
|
+
|
247
|
+
= ((* *))
|
248
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:Mock'))
|
249
|
+
== プロパティ
|
250
|
+
: hide-title
|
251
|
+
true
|
252
|
+
|
253
|
+
= ((* *))
|
254
|
+
(('tag:center'))\n\n
|
255
|
+
(('tag:xx-large:Test Driven'))\n
|
256
|
+
(('tag:xx-large:Development for'))\n
|
257
|
+
(('tag:xx-large:Embedded Ruby'))
|
258
|
+
== プロパティ
|
259
|
+
: hide-title
|
260
|
+
true
|
261
|
+
|
262
|
+
= (DEMO)
|
263
|
+
(('tag:center'))\n\n\n\ngithub.com/hasumikin/mrubyc-test
|
264
|
+
|
265
|
+
= when I started to use mruby/c
|
266
|
+
* there is no ((*testing tool*))
|
267
|
+
* even mruby/c itself sometimes regressed 😨
|
268
|
+
* I had difficulties of writing my application
|
269
|
+
|
270
|
+
= so, why did I use mruby/c?
|
271
|
+
(('tag:center'))\n\n\n\n(('tag:x-large:so, why did I use mruby/c?'))
|
272
|
+
== プロパティ
|
273
|
+
: hide-title
|
274
|
+
true
|
275
|
+
|
276
|
+
= so, why did I use mruby/c?
|
277
|
+
(('tag:center'))\n\n\n\n((*(('tag:xx-large:DESTINO - 運命'))*))
|
278
|
+
== プロパティ
|
279
|
+
: hide-title
|
280
|
+
true
|
281
|
+
|
282
|
+
= ((* *))
|
283
|
+
(('tag:center'))\n\n\n(('tag:x-large:Anyway, I started to create'))
|
284
|
+
\n(('tag:x-large:mrubyc-test.gem'))
|
285
|
+
== プロパティ
|
286
|
+
: hide-title
|
287
|
+
true
|
288
|
+
|
289
|
+
= mrubyc-test.gem
|
290
|
+
* it's the first testing tool for mruby/c ever
|
291
|
+
* I wanted to go Rubyish in order to make it
|
292
|
+
* but mruby/c doesn't have enough features to make testing tool as you saw just before
|
293
|
+
|
294
|
+
= mrubyc-test.gem - designed as
|
295
|
+
* a ((*RubyGem*)), implemented in CRuby instead of mruby
|
296
|
+
* Test::Unit-like API
|
297
|
+
* supports stub and mock
|
298
|
+
* now you can test your business logic without implementing peripheral functions like ((*#fuga*))
|
299
|
+
|
300
|
+
= mrubyc-test.gem - stub
|
301
|
+
# enscript ruby
|
302
|
+
# app code
|
303
|
+
class Sample
|
304
|
+
attr_accessor :result
|
305
|
+
def do_something(arg)
|
306
|
+
@result = arg + still_not_defined_method
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
# test code
|
311
|
+
class SampleTest < MrubycTestCase
|
312
|
+
def stub_case
|
313
|
+
sample_obj = Sample.new
|
314
|
+
stub(sample_obj).still_not_defined_method { ", it must be Ruby" }
|
315
|
+
sample_obj.do_something("If it behaves like Ruby")
|
316
|
+
assert_equal "If it behaves like Ruby, it must be Ruby", sample_obj.result
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
= mrubyc-test.gem - mock
|
321
|
+
# enscript ruby
|
322
|
+
# app code
|
323
|
+
class Sample
|
324
|
+
def do_other_thing
|
325
|
+
to_be_hit()
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
# test code
|
330
|
+
class SampleTest < MrubycTestCase
|
331
|
+
def mock_case
|
332
|
+
sample_obj = Sample.new
|
333
|
+
mock(sample_obj).to_be_hit
|
334
|
+
sample_obj.do_other_thing
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
= it was my personal tool
|
339
|
+
(('tag:center'))\n\n\n\ngithub.com/hasumikin/mrubyc-test
|
340
|
+
|
341
|
+
= but already abandoned because
|
342
|
+
(('tag:center'))\n\n\n\n(('del:github.com/hasumikin/mrubyc-test'))
|
343
|
+
|
344
|
+
= now it's official 🎉
|
345
|
+
(('tag:center'))\n\n\n\n(('tag:large:github.com/'))((*(('tag:large:mrubyc'))*))(('tag:large:/mrubyc-test'))
|
346
|
+
|
347
|
+
= mrubyc-test.gem
|
348
|
+
* adopted as the testing tool for mruby/c itself
|
349
|
+
* so now you can safely send pull request to mruby/c
|
350
|
+
* you can write mruby/c application with confidence
|
351
|
+
|
352
|
+
= mrubyc-test.gem - internal
|
353
|
+
* the gist is creating ((*test.rb*)) by `test code generator` implemented in CRuby
|
354
|
+
# image
|
355
|
+
# src = images/how-mrubyc-test-works.png
|
356
|
+
# align = center
|
357
|
+
# relative-width = 100
|
358
|
+
|
359
|
+
= mrubyc-test.gem - how to make the test.rb
|
360
|
+
* gathers information of test cases by #method_added
|
361
|
+
* I learned this technique from Test::Unit
|
362
|
+
* generates stub methods and mock methods
|
363
|
+
* makes all-in-one script: ((*test.rb*))
|
364
|
+
* all the indispensable mechanism of assertion, stub, mock, app code and test code get together
|
365
|
+
|
366
|
+
= mrubyc-test.gem - Module#method_added
|
367
|
+
# enscript ruby
|
368
|
+
class MrubycTestCase
|
369
|
+
def self.method_added(name)
|
370
|
+
return false if %i(method_missing setup teardown).include?(name)
|
371
|
+
location = caller_locations(1, 1)[0]
|
372
|
+
path = location.absolute_path || location.path
|
373
|
+
line = location.lineno
|
374
|
+
@@added_methods << {
|
375
|
+
method_name: name.to_s,
|
376
|
+
path: File.expand_path(path),
|
377
|
+
line: line
|
378
|
+
}
|
379
|
+
|
380
|
+
= mrubyc-test.gem
|
381
|
+
# enscript ruby
|
382
|
+
class SampleTest < MrubycTestCase
|
383
|
+
desc "stub test sample"
|
384
|
+
def stub_case # hooks #method_added
|
385
|
+
sample_obj = Sample.new
|
386
|
+
stub(sample_obj).still_not_defined_method {
|
387
|
+
", it must be Ruby"
|
388
|
+
}
|
389
|
+
|
390
|
+
* test code inherits MrubycTestCase to be analyzed
|
391
|
+
|
392
|
+
= mrubyc-test.gem - BasicObject#method_missing
|
393
|
+
# enscript ruby
|
394
|
+
class MrubycTestCase
|
395
|
+
def method_missing(method_name, *args)
|
396
|
+
case method_name
|
397
|
+
when :stub, :mock
|
398
|
+
location = caller_locations(1, 1)[0]
|
399
|
+
Mrubyc::Test::Generator::Double.new(
|
400
|
+
method_name, args[0], location
|
401
|
+
)
|
402
|
+
|
403
|
+
= mrubyc-test.gem - generated stub method
|
404
|
+
# enscript ruby
|
405
|
+
# part of test.rb
|
406
|
+
class Sample
|
407
|
+
def still_not_defined_method
|
408
|
+
", it must be Ruby"
|
409
|
+
end
|
410
|
+
end
|
411
|
+
|
412
|
+
= mrubyc-test.gem - template of stub
|
413
|
+
# enscript ruby
|
414
|
+
<% test_cases.each do |test_case| -%>
|
415
|
+
<% test_case[:stubs].each do |stub| -%>
|
416
|
+
class <%= stub[:class_name] %>
|
417
|
+
attr_accessor <%= stub[:instance_variables] %>
|
418
|
+
def <%= stub[:method_name] %>
|
419
|
+
<% if stub[:return_value].is_a?(String) -%>
|
420
|
+
"<%= stub[:return_value] %>"
|
421
|
+
<% else -%>
|
422
|
+
<%= stub[:return_value] %>
|
423
|
+
<% end -%>
|
424
|
+
end
|
425
|
+
end
|
426
|
+
<% end -%>
|
427
|
+
|
428
|
+
= 宍道湖
|
429
|
+
# image
|
430
|
+
# src = images/shinjiko.jpg
|
431
|
+
# relative_width = 110
|
432
|
+
# relative_margin_top = -3
|
433
|
+
== prop
|
434
|
+
: hide-title
|
435
|
+
true
|
436
|
+
|
437
|
+
= mruby/c firmware is made up of three parts
|
438
|
+
* 1) peripheral API (C)
|
439
|
+
* 2) business logic (mruby)
|
440
|
+
* 3) ((*infinite loop (mruby)*))
|
441
|
+
# image
|
442
|
+
# src = images/three_parts_loop.png
|
443
|
+
# relative_width = 100
|
444
|
+
|
445
|
+
= mruby/c firmware is made up of three parts
|
446
|
+
# image
|
447
|
+
# src = images/three_sources_4.png
|
448
|
+
# align = center
|
449
|
+
# relative_height = 100
|
450
|
+
|
451
|
+
= we have multiple infinite loops
|
452
|
+
* firmware programming is essentially thread programming which consists of multiple infinite loops
|
453
|
+
* they keep watch on status like user input, changing sensor value and BLE/WiFi message, then display some information to indicate internal status
|
454
|
+
# image
|
455
|
+
# src = images/loops.png
|
456
|
+
# align = center
|
457
|
+
# relative_width = 100
|
458
|
+
|
459
|
+
= the loops of mruby/c are
|
460
|
+
* user space threads managed by mruby/c's runtime
|
461
|
+
# enscript c
|
462
|
+
/* main.c */
|
463
|
+
#define MEMORY_SIZE (1024 * 40) /* 40KB */
|
464
|
+
static uint8_t mrubyc_vm_pool[MEMORY_SIZE];
|
465
|
+
int main(void) {
|
466
|
+
mrbc_init(mrubyc_vm_pool, MEMORY_SIZE);
|
467
|
+
mrbc_create_task(watch_user_interace, 0);
|
468
|
+
mrbc_create_task(change_display, 0);
|
469
|
+
mrbc_create_task(watch_sensor_value, 0);
|
470
|
+
mrbc_run();
|
471
|
+
}
|
472
|
+
|
473
|
+
= threads of CRuby
|
474
|
+
* correspond to native threads (with GVL)
|
475
|
+
# enscript ruby
|
476
|
+
def start_loops
|
477
|
+
threads = []
|
478
|
+
threads << Thread.new { watch_user_interface }
|
479
|
+
threads << Thread.new { change_display }
|
480
|
+
threads << Thread.new { watch_sensor_value }
|
481
|
+
threads.each(&:join)
|
482
|
+
end
|
483
|
+
|
484
|
+
= (DEMO)
|
485
|
+
(('tag:center'))\n\n\n\ngithub.com/hasumikin/mrubyc-debugger
|
486
|
+
|
487
|
+
= mrubyc-debugger.gem
|
488
|
+
* mrubyc-debugger runs mruby/c loop script as a CRuby thread
|
489
|
+
* it simultaneously shows which lines are being executed
|
490
|
+
* besides, it have to take over the debug print of the script
|
491
|
+
* in order to do that, we can use your favorite CRuby features like ...
|
492
|
+
|
493
|
+
= ((* *))
|
494
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:TracePoint'))
|
495
|
+
== プロパティ
|
496
|
+
: hide-title
|
497
|
+
true
|
498
|
+
|
499
|
+
= mrubyc-debugger.gem - TracePoint
|
500
|
+
# enscript ruby
|
501
|
+
|
502
|
+
tasks = Dir.glob(File.join(Dir.pwd, "mrubyc_loops_dir", "*.rb"))
|
503
|
+
TracePoint.new(:c_call, :call, :line) do |tp|
|
504
|
+
number = nil
|
505
|
+
caller_locations(1, 1).each do |caller_location|
|
506
|
+
tasks.each_with_index do |task, i|
|
507
|
+
number = i if caller_location.to_s.include?(File.basename(task))
|
508
|
+
end
|
509
|
+
if number
|
510
|
+
@@mutex.lock
|
511
|
+
event = {
|
512
|
+
method_id: tp.method_id,
|
513
|
+
lineno: tp.lineno,
|
514
|
+
caller_location: caller_location,
|
515
|
+
binding: tp.binding }
|
516
|
+
$event_queues[number].push event
|
517
|
+
@@mutex.unlock
|
518
|
+
|
519
|
+
= ((* *))
|
520
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:Refinements'))
|
521
|
+
== プロパティ
|
522
|
+
: hide-title
|
523
|
+
true
|
524
|
+
|
525
|
+
= mrubyc-debugger.gem - Refinements
|
526
|
+
# enscript ruby
|
527
|
+
module DebugQueue
|
528
|
+
refine Kernel do
|
529
|
+
def puts(text)
|
530
|
+
$debug_queues[Thread.current[:index]] << {
|
531
|
+
level: :debug,
|
532
|
+
body: text }
|
533
|
+
|
534
|
+
* assuming mruby/c loops use `#puts` for print debug on serial console,
|
535
|
+
* mrubyc-debugger takes it over to print on Curses window
|
536
|
+
|
537
|
+
= ((* *))
|
538
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:Curses'))
|
539
|
+
== プロパティ
|
540
|
+
: hide-title
|
541
|
+
true
|
542
|
+
|
543
|
+
= mrubyc-debugger.gem - Curses
|
544
|
+
# enscript ruby
|
545
|
+
|
546
|
+
include Curses
|
547
|
+
debug = $debug_queues[i].pop # took over by Refinements
|
548
|
+
wins[i][:out].addstr " #{debug[:level]} " + debug[:body]
|
549
|
+
event = $event_queues[i].pop # event info by TracePoint
|
550
|
+
(1..(wins[i][:src].maxy - 2)).each do |y|
|
551
|
+
wins[i][:src].setpos(y, 1)
|
552
|
+
if !@srcs[i][y]
|
553
|
+
wins[i][:src].addstr ' ' * wins[i][:src].maxx
|
554
|
+
else
|
555
|
+
# hilighten current line
|
556
|
+
wins[i][:src].attron(A_REVERSE) if y == event[:lineno]
|
557
|
+
end
|
558
|
+
end
|
559
|
+
vars = {}
|
560
|
+
event[:tp_binding].local_variables.each do |var|
|
561
|
+
vars[var] = event[:tp_binding].local_variable_get(var).inspect
|
562
|
+
end
|
563
|
+
|
564
|
+
= ((* *))
|
565
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:Binding'))
|
566
|
+
== プロパティ
|
567
|
+
: hide-title
|
568
|
+
true
|
569
|
+
|
570
|
+
= mrubyc-debugger.gem - Binding
|
571
|
+
# enscript ruby
|
572
|
+
binding.local_variables
|
573
|
+
# => [:var_a, :var_b, ...]
|
574
|
+
|
575
|
+
binding.local_variable_get(:var_a)
|
576
|
+
# => "foo"
|
577
|
+
|
578
|
+
binding.local_variable_set(:var_a, "bar")
|
579
|
+
binding.local_variable_get(:var_a)
|
580
|
+
# => "bar"
|
581
|
+
|
582
|
+
= summary
|
583
|
+
|
584
|
+
= summary
|
585
|
+
* mrubyc-test is the first testing tool for mruby/c. it means mruby/c started to have its ecosystem
|
586
|
+
|
587
|
+
= summary
|
588
|
+
* mrubyc-test is the first testing tool for mruby/c. it means mruby/c started to have its ecosystem\neven if Matz hates test
|
589
|
+
|
590
|
+
= summary
|
591
|
+
* mrubyc-test is the first testing tool for mruby/c. it means mruby/c started to have its ecosystem\neven if Matz hates test
|
592
|
+
* mrubyc-debugger is a visualization tool of concurrent mruby/c loop tasks powered by CRuby's Thread
|
593
|
+
|
594
|
+
= summary
|
595
|
+
* mrubyc-test is the first testing tool for mruby/c. it means mruby/c started to have its ecosystem\neven if Matz hates test
|
596
|
+
* mrubyc-debugger is a visualization tool of concurrent mruby/c loop tasks powered by CRuby's Thread\nno matter what Matz regrets
|
597
|
+
|
598
|
+
= summary
|
599
|
+
* at a glance, developing with mruby/c seems to be very restricted due to lack of dynamic features
|
600
|
+
|
601
|
+
= summary
|
602
|
+
* at a glance, developing with mruby/c seems to be very restricted due to lack of dynamic features
|
603
|
+
* however, it will be more effective by using the power of CRuby and our own tools
|
604
|
+
|
605
|
+
= summary
|
606
|
+
* at a glance, developing with mruby/c seems to be very restricted due to lack of dynamic features
|
607
|
+
* however, it will be more effective by using the power of CRuby and our own tools
|
608
|
+
* above all, Rubyish-terminal-based development is fun!
|
609
|
+
|
610
|
+
= me
|
611
|
+
* HASUMI Hitoshi\n@hasumikin
|
612
|
+
* Monstar Lab, inc.\nShimane office
|
613
|
+
* Sake 🍶\nSoba 🍜\nCoffee ☕
|
614
|
+
# image
|
615
|
+
# src = images/hasumi.jpg
|
616
|
+
# align = right
|
617
|
+
# relative-height = 90
|
618
|
+
|
619
|
+
= thank you!
|
620
|
+
(('tag:center'))\n\n\n\n(('tag:xx-large:Thank you!'))
|
621
|
+
== プロパティ
|
622
|
+
: hide-title
|
623
|
+
true
|
624
|
+
|
data/config.yaml
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
---
|
2
|
+
id: RubyKaigi-2019
|
3
|
+
base_name: Practical-mrubyc-firmware-development-with-CRuby
|
4
|
+
tags:
|
5
|
+
- mruby
|
6
|
+
- mruby/c
|
7
|
+
- IoT
|
8
|
+
- TDD
|
9
|
+
presentation_date: 2019/04/19
|
10
|
+
version: 2019.04.19.2
|
11
|
+
licenses: ["BSD 3-Clause"]
|
12
|
+
slideshare_id:
|
13
|
+
speaker_deck_id:
|
14
|
+
ustream_id:
|
15
|
+
vimeo_id:
|
16
|
+
youtube_id:
|
17
|
+
author:
|
18
|
+
markup_language: :rd
|
19
|
+
name: HASUMI Hitoshi
|
20
|
+
email: hasumikin@gmail.com
|
21
|
+
rubygems_user: hasumikin
|
22
|
+
slideshare_user:
|
23
|
+
speaker_deck_user:
|
Binary file
|
data/images/bytecode.png
ADDED
Binary file
|
Binary file
|
data/images/esp32.jpg
ADDED
Binary file
|
data/images/fuga.jpg
ADDED
Binary file
|
data/images/hasumi.jpg
ADDED
Binary file
|
Binary file
|
data/images/kamos.jpg
ADDED
Binary file
|
Binary file
|
data/images/loops.png
ADDED
Binary file
|
data/images/mark32.png
ADDED
Binary file
|
data/images/mark48.png
ADDED
Binary file
|
data/images/mark64.png
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
data/images/shinjiko.jpg
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
|
Binary file
|
Binary file
|
data/theme.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
# puts font_families.sort
|
2
|
+
@xx_large_font_size = screen_size(9 * Pango::SCALE)
|
3
|
+
@x_large_font_size = screen_size(6.5 * Pango::SCALE)
|
4
|
+
@large_font_size = screen_size(4.5 * Pango::SCALE)
|
5
|
+
@normal_font_size = screen_size(3.5 * Pango::SCALE)
|
6
|
+
@small_font_size = screen_size(3.2 * Pango::SCALE)
|
7
|
+
@x_small_font_size = screen_size(2.8 * Pango::SCALE)
|
8
|
+
@xx_small_font_size = screen_size(2 * Pango::SCALE)
|
9
|
+
|
10
|
+
@default_headline_line_color = '#888888'
|
11
|
+
@font_family = find_font_family('Rockwell')
|
12
|
+
@foreground = "#FCF374"
|
13
|
+
|
14
|
+
@table_frame_color = "#ffffff"
|
15
|
+
@table_fill_color = "#0f0428"
|
16
|
+
@table_body_frame_color = "#ffffff"
|
17
|
+
@table_body_fill_color = "#3f3468"
|
18
|
+
@table_head_frame_color = "#ffffff"
|
19
|
+
@table_head_fill_color = "#rf0428"
|
20
|
+
|
21
|
+
@monospace_font_family = 'Ricty Discord'
|
22
|
+
@preformatted_fill_color = '#000000'
|
23
|
+
# @preformatted_centering = true
|
24
|
+
@space = screen_y(1)
|
25
|
+
|
26
|
+
include_theme('default')
|
27
|
+
|
28
|
+
match(Slide, HeadLine) do |heads|
|
29
|
+
heads.prop_set("size", @large_font_size)
|
30
|
+
heads.prop_set("weight", "normal")
|
31
|
+
set_font_family(heads)
|
32
|
+
end
|
33
|
+
|
34
|
+
#match Slide do |slides|
|
35
|
+
# slides.each do |slide|
|
36
|
+
# if slide.match?(/matsue\.rb/)
|
37
|
+
# slide.prop_set("foreground", "yellow")
|
38
|
+
# slide.prop_set("background_image", 'images/rubykaigi_keynote_bg-239.png')
|
39
|
+
# end
|
40
|
+
# end
|
41
|
+
#end
|
42
|
+
|
43
|
+
@title_slide_background_image = 'images/rubykaigi_bg_title-296.png'
|
44
|
+
include_theme("title-slide-background-image")
|
45
|
+
@slide_logo_image = 'images/NEW_ML_LOGO.png'
|
46
|
+
include_theme('slide-logo')
|
47
|
+
|
48
|
+
@slide_background_image = 'images/rubykaigi_keynote_bg-239.png'
|
49
|
+
include_theme("slide-background-image")
|
50
|
+
|
51
|
+
@item_image = 'images/mark32.png'
|
52
|
+
|
53
|
+
include_theme("default-item-mark")
|
54
|
+
|
55
|
+
add_image_path("rabbit-images")
|
56
|
+
|
57
|
+
slide_body = [Slide, Body]
|
58
|
+
item_list_item = [ItemList, ItemListItem]
|
59
|
+
|
60
|
+
indent = 70
|
61
|
+
|
62
|
+
match(*(slide_body + (item_list_item * 1))) do |items|
|
63
|
+
name = "item1"
|
64
|
+
items.delete_pre_draw_proc_by_name(name)
|
65
|
+
items.delete_post_draw_proc_by_name(name)
|
66
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
67
|
+
end
|
68
|
+
|
69
|
+
match(*(slide_body + (item_list_item * 2))) do |items|
|
70
|
+
name = "item2"
|
71
|
+
items.delete_pre_draw_proc_by_name(name)
|
72
|
+
items.delete_post_draw_proc_by_name(name)
|
73
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
74
|
+
end
|
75
|
+
|
76
|
+
match(*(slide_body + (item_list_item * 3))) do |items|
|
77
|
+
name = "item3"
|
78
|
+
items.delete_pre_draw_proc_by_name(name)
|
79
|
+
items.delete_post_draw_proc_by_name(name)
|
80
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
81
|
+
end
|
82
|
+
|
83
|
+
enum_list_item = [EnumList, EnumListItem]
|
84
|
+
|
85
|
+
match(*(slide_body + enum_list_item + item_list_item)) do |items|
|
86
|
+
name = "enum-item1"
|
87
|
+
items.delete_pre_draw_proc_by_name(name)
|
88
|
+
items.delete_post_draw_proc_by_name(name)
|
89
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
90
|
+
end
|
91
|
+
|
92
|
+
match(*(slide_body + enum_list_item + (item_list_item * 2))) do |items|
|
93
|
+
name = "enum-item2"
|
94
|
+
items.delete_pre_draw_proc_by_name(name)
|
95
|
+
items.delete_post_draw_proc_by_name(name)
|
96
|
+
draw_image_mark(items, @item_image, name, indent: indent)
|
97
|
+
end
|
metadata
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rabbit-slide-hasumikin-RubyKaigi-2019
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2019.04.19.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- HASUMI Hitoshi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-04-19 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 talk of RubyKaigi 2019 in Fukuoka. Writing mruby/c firmware applications
|
28
|
+
is like writing mrbgems. You need to make some C functions and mruby wrapper of
|
29
|
+
them in order to handle peripherals like sensor, flash memory or BLE. Easy to imagine
|
30
|
+
it's hard to develop for a team in a situation of TIGHT COUPLING, right? I will
|
31
|
+
talk about some tools, mrubyc-test and mrubyc-debugger, which I made with CRuby
|
32
|
+
for testing and debugging to keep our team slack coupling."
|
33
|
+
email:
|
34
|
+
- hasumikin@gmail.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- ".rabbit"
|
40
|
+
- README.rd
|
41
|
+
- Rakefile
|
42
|
+
- RubyKaigi-2019--Practical-mrubyc-firmware-development-with-CRuby.rab
|
43
|
+
- RubyKaigi-2019--Practical-mrubyc-firmware-development-with-CRuby.rab.pdf
|
44
|
+
- config.yaml
|
45
|
+
- images/NEW_ML_LOGO.png
|
46
|
+
- images/bytecode.png
|
47
|
+
- images/collage01.jpg
|
48
|
+
- images/esp32.jpg
|
49
|
+
- images/fuga.jpg
|
50
|
+
- images/hasumi.jpg
|
51
|
+
- images/how-mrubyc-test-works.png
|
52
|
+
- images/kamos.jpg
|
53
|
+
- images/kamos_2019.png
|
54
|
+
- images/loops.png
|
55
|
+
- images/mark32.png
|
56
|
+
- images/mark48.png
|
57
|
+
- images/mark64.png
|
58
|
+
- images/mruby_and_mrubyc-mruby.png
|
59
|
+
- images/mruby_and_mrubyc-mrubyc.png
|
60
|
+
- images/mruby_and_mrubyc.png
|
61
|
+
- images/psoc5lp_chip.jpg
|
62
|
+
- images/rubykaigi2018.png
|
63
|
+
- images/rubykaigi2019_keynote_sample-289.png
|
64
|
+
- images/rubykaigi_bg_title-296.png
|
65
|
+
- images/rubykaigi_keynote_bg-239.png
|
66
|
+
- images/shinjiko.jpg
|
67
|
+
- images/three_parts.png
|
68
|
+
- images/three_parts_loop.png
|
69
|
+
- images/three_parts_model.png
|
70
|
+
- images/three_parts_peripheral.png
|
71
|
+
- images/three_sources_0.png
|
72
|
+
- images/three_sources_1.png
|
73
|
+
- images/three_sources_2.png
|
74
|
+
- images/three_sources_2_fuga_1.png
|
75
|
+
- images/three_sources_2_fuga_2.png
|
76
|
+
- images/three_sources_2_fuga_3.png
|
77
|
+
- images/three_sources_2_fuga_4.png
|
78
|
+
- images/three_sources_3.png
|
79
|
+
- images/three_sources_4.png
|
80
|
+
- images/松江城_Matsue.rb.16x9.jpg
|
81
|
+
- images/松江城_Matsue.rb.jpg
|
82
|
+
- pdf/RubyKaigi-2019-Practical-mrubyc-firmware-development-with-CRuby.pdf
|
83
|
+
- theme.rb
|
84
|
+
homepage: http://slide.rabbit-shocker.org/authors/hasumikin/RubyKaigi-2019/
|
85
|
+
licenses:
|
86
|
+
- BSD 3-Clause
|
87
|
+
metadata: {}
|
88
|
+
post_install_message:
|
89
|
+
rdoc_options: []
|
90
|
+
require_paths:
|
91
|
+
- lib
|
92
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
requirements: []
|
103
|
+
rubygems_version: 3.0.1
|
104
|
+
signing_key:
|
105
|
+
specification_version: 4
|
106
|
+
summary: Practical mruby/c firmware development with CRuby
|
107
|
+
test_files: []
|