diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eb32977..bedc9a8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Change log +## 0.9.11 on 2022/01/21 +### Duplex matrix 😎 +- Now we encourage you to make a duplex matrix keyboard with Seeed XIAO RP2040 + Check details of the API here: [https://github.com/picoruby/prk_firmware/wiki/Keyscan-matrix#duplex-and-round-robin-matrix](https://github.com/picoruby/prk_firmware/wiki/Keyscan-matrix#duplex-and-round-robin-matrix) + ## 0.9.10 on 2022/01/06 ### Keyboard#define_composite_key diff --git a/CMakeLists.txt b/CMakeLists.txt index e6cabbf6..8d2e2077 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ add_definitions( -DMRBC_USE_HAL_USER_RESERVED -DMRBC_REQUIRE_32BIT_ALIGNMENT -DMAX_REGS_SIZE=256 - -DMAX_SYMBOLS_COUNT=600 + -DMAX_SYMBOLS_COUNT=700 -DMAX_VM_COUNT=10 -DMRBC_CONVERT_CRLF ) @@ -27,7 +27,7 @@ pico_sdk_init() execute_process (COMMAND date +%Y%m%d OUTPUT_VARIABLE CMAKE_BUILDDATE OUTPUT_STRIP_TRAILING_WHITESPACE) execute_process (COMMAND git rev-parse --short HEAD OUTPUT_VARIABLE CMAKE_REVISION OUTPUT_STRIP_TRAILING_WHITESPACE) -set (PRK_VERSION 0.9.10) +set (PRK_VERSION 0.9.11) set (PRK_BUILDDATE ${CMAKE_BUILDDATE}) set (PRK_REVISION ${CMAKE_REVISION}) configure_file ("${CMAKE_CURRENT_SOURCE_DIR}/src/version.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/src/version.h") diff --git a/src/gpio.c b/src/gpio.c index 2be1c0db..189a1f18 100644 --- a/src/gpio.c +++ b/src/gpio.c @@ -2,14 +2,21 @@ #include "hardware/gpio.h" +// GPIO_IN 0b000 (defined in the SDK) +#define GPIO_IN_PULLUP 0b010 +#define GPIO_IN_PULLDOWN 0b110 +// GPIO_OUT 0b001 (defined in the SDK) +#define GPIO_OUT_LO 0b011 +#define GPIO_OUT_HI 0b101 + void c_gpio_get(mrb_vm *vm, mrb_value *v, int argc) { int gpio = GET_INT_ARG(1); if (gpio_get(gpio)) { - SET_INT_RETURN(1); + SET_TRUE_RETURN(); } else { - SET_INT_RETURN(0); + SET_FALSE_RETURN(); } } @@ -22,7 +29,21 @@ c_gpio_init(mrb_vm *vm, mrb_value *v, int argc) void c_gpio_set_dir(mrb_vm *vm, mrb_value *v, int argc) { - gpio_set_dir(GET_INT_ARG(1), GET_INT_ARG(2)); + if (GET_INT_ARG(2)&1 == GPIO_OUT) { + gpio_set_dir(GET_INT_ARG(1), true); + if (GET_INT_ARG(2) == GPIO_OUT_LO) { + gpio_put(GET_INT_ARG(1), 0); + } else if (GET_INT_ARG(2) == GPIO_OUT_HI) { + gpio_put(GET_INT_ARG(1), 1); + } + } else { + gpio_set_dir(GET_INT_ARG(1), false); + if (GET_INT_ARG(2) == GPIO_IN_PULLUP) { + gpio_pull_up(GET_INT_ARG(1)); + } else if (GET_INT_ARG(2) == GPIO_IN_PULLDOWN) { + gpio_pull_down(GET_INT_ARG(1)); + } + } } void diff --git a/src/ruby/Gemfile.lock b/src/ruby/Gemfile.lock index e935f1a1..236b1e73 100644 --- a/src/ruby/Gemfile.lock +++ b/src/ruby/Gemfile.lock @@ -50,6 +50,7 @@ GEM zeitwerk (2.5.3) PLATFORMS + ruby x86_64-linux DEPENDENCIES diff --git a/src/ruby/Rakefile b/src/ruby/Rakefile index c893e6d2..b41e33dd 100644 --- a/src/ruby/Rakefile +++ b/src/ruby/Rakefile @@ -14,5 +14,5 @@ namespace :steep do end task :test do - exec %q(CFLAGS=-DMAX_SYMBOLS_COUNT=600 bundle exec mrubyc-test) + exec %q(CFLAGS=-DMAX_SYMBOLS_COUNT=1000 bundle exec mrubyc-test) end diff --git a/src/ruby/app/models/keyboard.rb b/src/ruby/app/models/keyboard.rb index 8f2c01c2..80917b87 100644 --- a/src/ruby/app/models/keyboard.rb +++ b/src/ruby/app/models/keyboard.rb @@ -1,9 +1,10 @@ class Keyboard - GPIO_OUT = 1 - GPIO_IN = 0 - - HI = 1 - LO = 0 + GPIO_IN = 0b000 + GPIO_IN_PULLUP = 0b010 + GPIO_IN_PULLDOWN = 0b110 + GPIO_OUT = 0b001 + GPIO_OUT_LO = 0b011 + GPIO_OUT_HI = 0b101 MOD_KEYCODE = { KC_LCTL: 0b00000001, @@ -435,7 +436,8 @@ class Keyboard RIGHT_SIDE_FLIPPED_SPLIT = :right_side_flipped_split def initialize - puts "Initializing Keyboard ..." + puts "Initializing Keyboard." + sleep_ms 500 # mruby/c VM doesn't work with a CONSTANT to make another CONSTANT # steep doesn't allow dynamic assignment of CONSTANT @SHIFT_LETTER_THRESHOLD_A = LETTER.index('A').to_i @@ -460,6 +462,7 @@ def initialize @macro_keycodes = Array.new @buffer = Buffer.new("picoirb") @scan_mode = :matrix + @skip_positions = Array.new end attr_accessor :split, :uart_pin @@ -521,40 +524,84 @@ def set_scan_mode(mode) end end - def init_pins(rows, cols) - puts "Initializing GPIO ..." - if @split - print "Configured as a split-type" - @anchor = tud_mounted? - if @anchor - uart_anchor_init(@uart_pin) - puts " Anchor" - else - uart_partner_init(@uart_pin) - puts " Partner" - end + def init_uart + return unless @split + print "Configured as a split-type" + @anchor = tud_mounted? + if @anchor + puts " Anchor" + sleep_ms 500 + uart_anchor_init(@uart_pin) + else + puts " Partner" + uart_partner_init(@uart_pin) end sleep_ms 500 - @rows = rows - @cols = cols - @rows.each do |pin| - gpio_init(pin) - gpio_set_dir(pin, GPIO_OUT); - gpio_put(pin, HI); + end + + def init_matrix_pins(matrix) + puts "Initializing GPIO." + sleep_ms 500 + init_uart + @cols_size = 0 + @matrix = Hash.new + matrix.each do |cols| + @cols_size = [cols.size, @cols_size].max.to_i + cols.each do |cell| + if cell.is_a?(Array) + @matrix[cell[0]] = Hash.new unless @matrix[cell[0]] + end + end end - @cols.each do |pin| - gpio_init(pin) - gpio_set_dir(pin, GPIO_IN); - gpio_pull_up(pin); + matrix.each_with_index do |rows, row_index| + rows.each_with_index do |cell, col_index| + if cell.is_a?(Array) + @matrix[cell[0]][cell[1]] = [row_index, col_index] + gpio_init(cell[0]) + gpio_set_dir(cell[0], GPIO_IN_PULLUP) + gpio_init(cell[1]) + gpio_set_dir(cell[1], GPIO_IN_PULLUP) + else # should be nil + @skip_positions << [row_index, col_index] + end + end + end + @offset_a = (@cols_size / 2.0).ceil_to_i + @offset_b = @cols_size * 2 - @offset_a - 1 + end + + def init_pins(rows, cols) + matrix = Array.new + rows.each do |row| + line = Array.new + cols.each do |col| + line << [row, col] + end + matrix << line end - # for split type - @offset_a = (@cols.size / 2.0).ceil_to_i - @offset_b = @cols.size * 2 - @offset_a - 1 + init_matrix_pins matrix end def init_direct_pins(pins) set_scan_mode :direct - init_pins([], pins) + pins.each do |pin| + gpio_init(pin) + gpio_set_dir(pin, GPIO_IN_PULLUP) + end + @direct_pins = pins + end + + def skip_position?(row, col) + col2 = if col < @cols_size + col + else + if @split_style == RIGHT_SIDE_FLIPPED_SPLIT + col - @cols_size + else # STANDARD_SPLIT + (col - @cols_size + 1) * -1 + @cols_size + end + end + @skip_positions.include?([row, col2]) end # Input @@ -563,12 +610,25 @@ def init_direct_pins(pins) # Result # layer: { default: [ [ -0x04, -0x05, 0b00000001, :MACRO_1 ],... ] } def add_layer(name, map) - new_map = Array.new(@rows.size) + new_map = Array.new + new_map[0] = Array.new row_index = 0 col_index = 0 - @entire_cols_size = @split ? @cols.size * 2 : @cols.size map.each do |key| - new_map[row_index] = Array.new(@cols.size) if col_index == 0 + if entire_cols_size <= col_index + row_index += 1 + col_index = 0 + new_map[row_index] = Array.new + end + while skip_position?(row_index, col_index) + new_map[row_index][calculate_col_position(col_index)] = 0 + col_index += 1 + if entire_cols_size <= col_index + row_index += 1 + col_index = 0 + new_map[row_index] = Array.new + end + end col_position = calculate_col_position(col_index) case key.class when Symbol @@ -586,29 +646,32 @@ def add_layer(name, map) switch: [row_index, col_position] } end - if col_index == @entire_cols_size - 1 - col_index = 0 - row_index += 1 - else - col_index += 1 - end + col_index += 1 end @keymaps[name] = new_map @layer_names << name end + def entire_cols_size + @entire_cols_size ||= @split ? @cols_size * 2 : @cols_size + end + def calculate_col_position(col_index) return col_index unless @split - case @split_style + # `when STANDARD_SPLIT` can be deleted after fixing a picoruby's bug + # https://github.com/picoruby/picoruby/issues/74 when STANDARD_SPLIT col_index when RIGHT_SIDE_FLIPPED_SPLIT - if col_index < @cols.size + if col_index < @cols_size col_index else - @entire_cols_size - (col_index - @cols.size) - 1 + entire_cols_size - (col_index - @cols_size) - 1 end + else + # Should not happen but be guarded to pass steep check. + col_index end end @@ -823,7 +886,7 @@ def start! # To avoid unintentional report on startup # which happens only on Sparkfun Pro Micro RP2040 if @split && @anchor - sleep_ms 100 + sleep_ms 500 while true data = uart_anchor(0) break if data == 0xFFFFFF @@ -839,7 +902,7 @@ def start! @switches.clear @modifier = 0 - @switches = @scan_mode == :matrix ? scan_matrix! : scan_direct! + @scan_mode == :matrix ? scan_matrix! : scan_direct! # TODO: more features $rgb.fifo_push(true) if $rgb && !@switches.empty? @@ -1019,47 +1082,41 @@ def start! end def scan_matrix! - switches = [] # detect physical switches that are pushed - @rows.each_with_index do |row_pin, row| - gpio_put(row_pin, LO) - @cols.each_with_index do |col_pin, col| - if gpio_get(col_pin) == LO - col_data = if @anchor_left - if @anchor - # left - col - else - # right - (col - @offset_a) * -1 + @offset_b - end - else # right side is the anchor - unless @anchor - # left - col - else - # right - (col - @offset_a) * -1 + @offset_b - end - end - switches << [row, col_data] + @matrix.each do |out_pin, in_pins| + gpio_set_dir(out_pin, GPIO_OUT_LO) + in_pins.each do |in_pin, switch| + unless gpio_get(in_pin) + col = if @anchor_left + if @anchor + # left + switch[1] + else + # right + (switch[1] - @offset_a) * -1 + @offset_b + end + else # right side is the anchor + unless @anchor + # left + switch[1] + else + # right + (switch[1] - @offset_a) * -1 + @offset_b + end + end + @switches << [switch[0], col] end - # @type break: nil - break if switches.size >= @cols.size end - gpio_put(row_pin, HI) + gpio_set_dir(out_pin, GPIO_IN_PULLUP) end - return switches end def scan_direct! - switches = [] - @cols.each_with_index do |col_pin, col| - if gpio_get(col_pin) == LO - switches << [0, col] + @direct_pins.each_with_index do |col_pin, col| + if gpio_get(col_pin) + @switches << [0, col] end end - return switches end # diff --git a/src/ruby/app/tasks/usb_task.rb b/src/ruby/app/tasks/usb_task.rb index 77505aae..d8fb227f 100644 --- a/src/ruby/app/tasks/usb_task.rb +++ b/src/ruby/app/tasks/usb_task.rb @@ -1,7 +1,7 @@ -4000.times do +2000.times do tud_task cdc_task - sleep_ms 1 + sleep_ms 2 end print "\e[2J\e[1;1H" # clear all & home puts "Welcome to PRK Firmware!\n\nTUD task started.\n" @@ -18,14 +18,14 @@ puts "Suspending keymap." suspend_keymap $rgb.turn_off if $rgb - autoreload_tick = 1000 + autoreload_tick = 500 elsif autoreload_tick == 1 puts "Trying to reload keymap." reload_keymap - 3000.times do + 500.times do tud_task cdc_task - sleep_ms 1 + sleep_ms 2 end resume_keymap end diff --git a/src/ruby/sig/keyboard.rbs b/src/ruby/sig/keyboard.rbs index a7a5732c..440ecf08 100644 --- a/src/ruby/sig/keyboard.rbs +++ b/src/ruby/sig/keyboard.rbs @@ -8,10 +8,13 @@ class Object end class Keyboard - GPIO_OUT: Integer GPIO_IN: Integer - HI: Integer - LO: Integer + GPIO_IN_PULLUP: Integer + GPIO_IN_PULLDOWN: Integer + GPIO_OUT: Integer + GPIO_OUT_LO: Integer + GPIO_OUT_HI: Integer + MOD_KEYCODE: Hash[Symbol, Integer] KEYCODE: Array[Symbol] KEYCODE_SFT: Hash[Symbol, Integer] @@ -50,10 +53,9 @@ class Keyboard @layer: Symbol @anchor: bool @anchor_left: bool - @rows: Array[Integer] - @cols: Array[Integer] - @offset_a: Integer - @offset_b: Integer + @direct_pins: Array[Integer] + @cols_size: Integer + @matrix: Hash[Integer, Hash[Integer, Array[Integer]]] @locked_layer: Symbol | nil @keycodes: Array[String] @macro_keys: Array[Integer] @@ -63,6 +65,10 @@ class Keyboard @message: Integer @encoders: Array[RotaryEncoder] @scan_mode: Symbol + @offset_a: Integer + @offset_b: Integer + @entire_cols_size: Integer + @skip_positions: Array[Array[Integer]] attr_accessor split: bool attr_accessor uart_pin: Integer @@ -81,11 +87,13 @@ class Keyboard def set_anchor: (Symbol val) -> void def set_scan_mode: (Symbol val) -> void def split_style=: (Symbol style) -> void + def init_matrix_pins: (Array[Array[Array[Integer] | nil]] matrix) -> void + def init_uart: () -> void def init_pins: (Array[Integer] rows, Array[Integer] cols) -> void def init_direct_pins: (Array[Integer] pins) -> void + def calculate_col_position: (Integer col_index) -> Integer def convert_composite_keys: (Array[Symbol]) -> Array[Integer] def add_layer: (Symbol name, Array[ Symbol | Array[Symbol] ] map) -> void - def calculate_col_position: (Integer col_index) -> Integer def find_keycode_index: (Symbol key) -> (Integer | Symbol) def define_composite_key: (Symbol key_name, Array[Symbol] keys) -> void def define_mode_key: (Symbol key_name, [Symbol | Array[Symbol] | Proc | nil, Symbol | Proc, Integer?, Integer?] param) -> void @@ -103,6 +111,9 @@ class Keyboard def macro: (String text, ?::Array[Symbol] opt) -> void def eval: (String) -> void def ruby: () -> void - def scan_matrix!: () -> Array[Array[Integer]] - def scan_direct!: () -> Array[Array[Integer]] + def scan_matrix!: () -> void + def scan_direct!: () -> void + def switch_exists?: (Integer row, Integer col) -> bool + def entire_cols_size: () -> Integer + def skip_position?: (Integer row_index, Integer col_index) -> bool end diff --git a/src/ruby/sig/object.rbs b/src/ruby/sig/object.rbs index d01a0438..2f3bd636 100644 --- a/src/ruby/sig/object.rbs +++ b/src/ruby/sig/object.rbs @@ -21,5 +21,5 @@ class Object def gpio_set_dir : (Integer, Integer) -> void def gpio_pull_up : (Integer) -> void def gpio_put : (Integer, Integer) -> void - def gpio_get : (Integer) -> Integer + def gpio_get : (Integer) -> bool end diff --git a/src/ruby/test/keyboard_test.rb b/src/ruby/test/keyboard_test.rb index 1389af6c..a60be7ae 100644 --- a/src/ruby/test/keyboard_test.rb +++ b/src/ruby/test/keyboard_test.rb @@ -4,8 +4,6 @@ def define_mocks kbd = Keyboard.new mock(kbd).gpio_init(1) mock(kbd).gpio_set_dir(2) - mock(kbd).gpio_put(2) - mock(kbd).gpio_pull_up(1) end def setup @kbd = Keyboard.new @@ -14,6 +12,144 @@ def setup ##### Tests from here + description "init @direct_pins" + def direct_pins_case + @kbd.init_direct_pins([1,2,3,4]) + assert_equal [1,2,3,4], @kbd.instance_variable_get("@direct_pins") + end + + description "normal matrix of anchor" + def init_matrix_case + expectation = { + 1 => { 3 => [0, 0], 4 => [0, 1] }, + 2 => { 3 => [1, 0], 4 => [1, 1] } + } + assert_equal expectation, @kbd.instance_variable_get("@matrix") + assert_equal 2, @kbd.instance_variable_get("@cols_size") + end + + description "normal matrix of partner" + def init_partner_matrix_case + kbd = Keyboard.new + stub(kbd).tud_mounted? { false } + mock(kbd).uart_partner_init(1) + kbd.split = true + kbd.init_pins([1,2], [3,4]) + expectation = { + 1 => { 3 => [0, 0], 4 => [0, 1] }, + 2 => { 3 => [1, 0], 4 => [1, 1] } + } + assert_equal expectation, kbd.instance_variable_get("@matrix") + end + + description "duplex matrix of partner" + def init_duplex_partner_matrix_case + kbd = Keyboard.new + stub(kbd).tud_mounted? { false } + mock(kbd).uart_partner_init(1) + kbd.split = true + kbd.init_matrix_pins( + # col 7 6 5 4 row + [ + [ [1, 3], nil, [2, 3], [3, 2] ], # 0 + [ nil, [4, 1], [2, 4], nil ], # 1 + [ [1, 5], [5, 1], [2, 5], [5, 2] ] # 2 + ] + ) + assert_equal [[0,1],[1,0],[1,3]], kbd.instance_variable_get("@skip_positions") + matrix = { + 1 => { 3 => [0, 0], 5 => [2, 0] }, + 3 => { 2 => [0, 3] }, + 2 => { 3 => [0, 2], 4 => [1, 2], 5 => [2, 2] }, + 4 => { 1 => [1, 1] }, + 5 => { 1 => [2, 1], 2 => [2, 3] } + } + assert_equal matrix, kbd.instance_variable_get("@matrix") + kbd.add_layer :default, %i( + KC_A KC_C KC_D KC_1 KC_2 KC_4 + KC_I KC_J KC_9 KC_0 + KC_E KC_F KC_G KC_H KC_5 KC_6 KC_7 KC_8 + ) + layer = [ + [-4, 0, -6, -7, -30, -31, 0, -33], + [ 0, -12, -13, 0, 0, -38, -39, 0], + [-8, -9, -10, -11, -34, -35, -36, -37] + ] + assert_equal layer, kbd.instance_variable_get("@keymaps")[:default] + end + + description "duplex matrix of anchor" + def init_duplex_matrix_case + @kbd.init_matrix_pins( + # col 0 1 2 3 row + [ + [ [1, 3], [3, 1], [2, 3], nil ], # 0 + [ [1, 4], [4, 1], [2, 4], [4, 2] ], # 1 + [ nil, [5, 1], [2, 5], nil ] # 2 + ] + ) + assert_equal [[0,3],[2,0],[2,3]], @kbd.instance_variable_get("@skip_positions") + matrix = { + 1 => { 3 => [0, 0], 4 => [1, 0] }, + 3 => { 1 => [0, 1] }, + 2 => { 3 => [0, 2], 4 => [1, 2], 5 => [2, 2] }, + 4 => { 1 => [1, 1], 2 => [1, 3] }, + 5 => { 1 => [2, 1] } + } + assert_equal matrix, @kbd.instance_variable_get("@matrix") + assert_equal 4, @kbd.instance_variable_get("@cols_size") + @kbd.add_layer :default, %i( + KC_1 KC_2 KC_3 + KC_5 KC_6 KC_7 KC_8 + KC_9 KC_0 + ) + layer = [ + [-30, -31, -32, 0], + [-34, -35, -36, -37], + [ 0, -38, -39] + ] + assert_equal layer, @kbd.instance_variable_get("@keymaps")[:default] + end + + description "flipped-style duplex matrix" + def init_flipped_stype_duplex_matrix_case + kbd = Keyboard.new + kbd.split = true + kbd.split_style = :right_side_flipped_split + # To test partner side + stub(kbd).tud_mounted? { false } + mock(kbd).uart_partner_init(1) + kbd.init_matrix_pins( + # col 7 6 5 4 row + [ + [ [1, 3], [3, 1], [2, 3], [3, 2] ], # 0 + [ [1, 4], nil, [2, 4], [4, 2] ], # 1 + [ nil, [5, 1], [2, 5], nil ] # 2 + ] + ) + assert_equal [[1,1],[2,0],[2,3]], kbd.instance_variable_get("@skip_positions") + matrix = { + 1 => { 3 => [0, 0], 4 => [1, 0] }, + 3 => { 1 => [0, 1], 2 => [0, 3] }, + 2 => { 3 => [0, 2], 4 => [1, 2], 5 => [2, 2] }, + 4 => { 2 => [1, 3] }, + 5 => { 1 => [2, 1] } + } + assert_equal matrix, kbd.instance_variable_get("@matrix") + kbd.add_layer :default, %i( + KC_A KC_B KC_C KC_D KC_1 KC_2 KC_3 KC_4 + KC_E KC_G KC_H KC_5 KC_7 KC_8 + KC_I KC_J KC_9 KC_0 + ) + layer = [ + [-4, -5, -6, -7, -33, -32, -31, -30], + [-8, 0, -10, -11, -37, -36, 0, -34], + [ 0, -12, -13, 0, nil, -39, -38, 0] + # ^^^ 👀 ^ 👀 + ] + assert_equal layer, kbd.instance_variable_get("@keymaps")[:default] + end + description "default layer" def default_layer assert_equal :default, @kbd.layer @@ -38,7 +174,7 @@ def standard_calculate_col_position_case @kbd.split = true @kbd.split_style = :standard_split @kbd.add_layer :default, %i(KC_A KC_B KC_C KC_D KC_E KC_F KC_G KC_H) - assert_equal 3, @kbd.calculate_col_position(3) + assert_equal 3, @kbd.calculate_col_position(3, 4) end description "should return calculated col_index" @@ -46,7 +182,7 @@ def flipped_calculate_col_position_case @kbd.split = true @kbd.split_style = :right_side_flipped_split @kbd.add_layer :default, %i(KC_A KC_B KC_C KC_D KC_E KC_F KC_G KC_H) - assert_equal 2, @kbd.calculate_col_position(3) + assert_equal 2, @kbd.calculate_col_position(3, 4) end description "raise" diff --git a/src/ruby/test/tmp/main.c b/src/ruby/test/tmp/main.c index 8f81ef49..0cc382be 100644 --- a/src/ruby/test/tmp/main.c +++ b/src/ruby/test/tmp/main.c @@ -24,6 +24,7 @@ static void c_instance_variable_get(struct VM *vm, mrbc_value v[], int argc) for(int i = 0; i < kvh->n_stored; i++) { if (strncmp(&name[1], symid_to_str(kvh->data[i].sym_id), strlen(name) - 1) == 0) { SET_RETURN(kvh->data[i].value); + mrbc_incref(&kvh->data[i].value); return; } } diff --git a/src/uart.c b/src/uart.c index f0da831a..aa9dad53 100644 --- a/src/uart.c +++ b/src/uart.c @@ -32,7 +32,6 @@ c_mutual_uart_at_my_own_risk_eq(mrb_vm *vm, mrb_value *v, int argc) { if (GET_ARG(1).tt == MRBC_TT_TRUE) { mutual = true; - console_printf("Caution: Using mutual UART is at your own risk.\n"); } else { mutual = false; } @@ -42,6 +41,7 @@ void c_uart_anchor_init(mrb_vm *vm, mrb_value *v, int argc) { if (mutual) { + console_printf("\n[WARNING] Using mutual UART is at your own risk.\n\n"); uart_pin = GET_INT_ARG(1); gpio_init(uart_pin); gpio_set_dir(uart_pin, GPIO_OUT);