メソッドの詳細
このセクションでは、独自のメソッドを記述します。
この実装の例は、こちらにあります: 4_external_led_methods.rs。
ここでは、共通アノード RGB LED を使用していると想定します。共通カソード RGB LED を使用する場合、high と low の設定は逆になります。
✅ 外部 RGB LED 用のコードに戻ってください。
各チャンネルの Level を個別に設定する代わりに、3 つのチャンネルすべてを含む型と、RGB LED の振る舞いを定義するメソッドを定義できます。
✅ GPIO とピン設定をスコープに取り込んでください。
#![allow(unused)]
fn main() {
use nrf52840_hal::{
self as hal,
gpio::{
p0::{Parts as P0Parts, P0_03, P0_04, P0_28},
Level, Output, PushPull,
},
Timer,
};
}
✅ fn main() の上に、各チャンネルに 1 つずつ、3 つのフィールドを持つ struct を定義してください。各チャンネルはそれぞれ独自の型を持ちます!
#![allow(unused)]
fn main() {
struct LEDState {
r: P0_03<Output<PushPull>>,
b: P0_04<Output<PushPull>>,
g: P0_28<Output<PushPull>>,
}
}
✅ struct LEDState の下に、その struct 用の impl ブロックを作成してください。
#![allow(unused)]
fn main() {
impl LEDState {
// 空
}
}
メソッドには 2 種類あります: 静的メソッド と インスタンスメソッド です。静的メソッドは一般に、インスタンスのコンストラクターとして使用されます。これらは :: 構文で呼び出されます。インスタンスメソッドはオブジェクトによって呼び出されるため、そのオブジェクトへの参照を引数として持ちます。これらはドット構文で呼び出されます。
✅ impl ブロック内に、struct を構築する静的メソッドを作成してください。メソッドの前半ではピンを設定し、後半では struct を作成して、それを返します。
#![allow(unused)]
fn main() {
fn init(pins: P0Parts) -> LEDState {
let mut led_red = pins.p0_03.into_push_pull_output(Level::High);
let mut led_blue = pins.p0_04.into_push_pull_output(Level::High);
let mut led_green = pins.p0_28.into_push_pull_output(Level::High);
LEDState {
r: led_red,
b: led_blue,
g: led_green,
}
}
}
✅ fn main() 内で、ピンを設定している 3 行を、この静的メソッドの呼び出しに置き換えてください。
- let mut led_red = pins.p0_03.into_push_pull_output(Level::High);
- let mut led_blue = pins.p0_04.into_push_pull_output(Level::High);
- let mut led_green = pins.p0_28.into_push_pull_output(Level::High);
+ let mut light = LEDState::init(pins);
これで、LED の振る舞いを制御するさまざまなインスタンスメソッドを定義できるようになりました。例として、1000ms 間隔で LED を赤色光から青色光へ切り替える、このコード片をリファクタリングします:
#![allow(unused)]
fn main() {
loop {
led_red.set_low().unwrap();
led_blue.set_high().unwrap();
timer.delay_ms(1000_u32);
led_red.set_high().unwrap();
led_blue.set_low().unwrap();
timer.delay_ms(1000_u32);
}
}
✅ impl ブロックに戻ってください。赤チャンネルを low にし、他を high に設定するインスタンスメソッドを定義してください。
#![allow(unused)]
fn main() {
fn red(&mut self) {
self.r.set_low().unwrap();
self.g.set_high().unwrap();
self.b.set_high().unwrap();
}
}
このメソッドは、LEDState のインスタンスの可変参照を引数として受け取ります。&mut self は self: &mut Self の短縮形です。struct のフィールドには . 構文でアクセスできます。
✅ 同じ方法で、青チャンネルを high にし、他を low に設定するメソッドを定義してください。
✅ fn main() に戻り、loop の中の行を対応する関数呼び出しに置き換えてください。
- led_red.set_low().unwrap();
- led_blue.set_high().unwrap();
+ light.red();
timer.delay_ms(1000_u32);
- led_red.set_high().unwrap();
- led_blue.set_low().unwrap();
+ light.blue();
timer.delay_ms(1000_u32);
✅ この点滅 loop を、呼び出し可能なメソッドにしてください。
現在、LED 用のピンはハードコードされています。これにより、2 つ目の LED に対してコードを再利用しにくくなっています。この部分のコードをリファクタリングしましょう。
✅ Pin 型と prelude::* モジュールをスコープに取り込んでください。
#![allow(unused)]
fn main() {
use nrf52840_hal::{
prelude::*,
gpio::{
Level,
Output,
PushPull,
Pin,
},
Timer,
};
}
✅ struct 定義で、特定のピンを Pin 型に置き換えてください。
#![allow(unused)]
fn main() {
struct LEDColor {
r: Pin<Output<PushPull>>,
b: Pin<Output<PushPull>>,
g: Pin<Output<PushPull>>,
}
}
✅ init メソッドを変更し、受け取るピンが任意の番号付きピンであり、さらに任意の設定でもよいようにしてください。このメソッドは、LEDColor struct をインスタンス化するときに、ピンを high レベルのプッシュプル出力に設定します。
ジェネリック型パラメーター <Mode> に注意してください。これは引数の型宣言で使用できるように、関数名の直後で宣言する必要があります。<Mode> は、未知のピン設定のプレースホルダーです。
#![allow(unused)]
fn main() {
pub fn init<Mode>(led_red: Pin<Mode>, led_blue: Pin<Mode>, led_green: Pin<Mode>) -> LEDColor {
LEDColor {
r: led_red.into_push_pull_output(Level::High),
b: led_blue.into_push_pull_output(Level::High),
g: led_green.into_push_pull_output(Level::High),
}
}
}
✅ コードが動作するように、fn main() の行を書き換えてください。
#![allow(unused)]
fn main() {
let led_channel_red = pins.p0_03.degrade();
let led_channel_blue = pins.p0_04.degrade();
let led_channel_green = pins.p0_28.degrade();
let mut light = LEDColor::init(led_channel_red, led_channel_blue, led_channel_green);
}