#include #include #include #include #include /* Private */ #include "gpio.h" static void mrb_gpio_free(mrb_state *mrb, void *ptr); typedef struct { uint32_t pin; machine_gpio_config_t cfg; } mrb_gpio_t; const struct mrb_data_type mrb_gpio_type = { .struct_name = "GPIO", .dfree = mrb_gpio_free, }; static void mrb_gpio_free(mrb_state *mrb, void *ptr) { mrb_free(mrb, ptr); } static mrb_value mrb_gpio_initialize(mrb_state *mrb, mrb_value self) { mrb_int pin_num; mrb_value init_cfg; mrb_int nargs = mrb_get_args(mrb, "i|H", &pin_num, &init_cfg); machine_gpio_mode_t init_mode = MACHINE_GPIO_MODE_INPUT; machine_gpio_value_t init_value = MACHINE_GPIO_LOW; machine_gpio_pull_t init_pull = MACHINE_GPIO_PULL_NONE; /* Optional parameters, use default if not received from hash */ if (nargs == 2) { mrb_ensure_hash_type(mrb, init_cfg); mrb_value pin_mode = mrb_hash_get(mrb, init_cfg, mrb_symbol_value(mrb_intern_static(mrb, "mode", 4))); if (!mrb_nil_p(pin_mode)) { mrb_ensure_integer_type(mrb, pin_mode); init_mode = mrb_integer(pin_mode); if (init_mode >= MACHINE_GPIO_MODE_END) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Invalid GPIO mode"); } } mrb_value pin_pull = mrb_hash_get(mrb, init_cfg, mrb_symbol_value(mrb_intern_static(mrb, "pull", 4))); if (!mrb_nil_p(pin_pull)) { mrb_ensure_integer_type(mrb, pin_pull); init_pull = mrb_integer(pin_pull); if (init_pull >= MACHINE_GPIO_PULL_END) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Invalid GPIO pull"); } } mrb_value pin_initial_value = mrb_hash_get(mrb, init_cfg, mrb_symbol_value(mrb_intern_static(mrb, "init", 4))); if (!mrb_nil_p(pin_initial_value)) { mrb_ensure_integer_type(mrb, pin_initial_value); init_value = mrb_integer(pin_initial_value); if (init_value >= MACHINE_GPIO_END) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Invalid GPIO initial value"); } } } mrb_gpio_t *pin = mrb_malloc(mrb, sizeof(mrb_gpio_t)); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to allocate GPIO struct"); } pin->pin = pin_num; pin->cfg.initial_value = init_value; pin->cfg.mode = init_mode; pin->cfg.pull = init_pull; /* TODO: Initialize GPIO */ mrb_machine_gpio_impl_config(pin->pin, &pin->cfg); DATA_PTR(self) = pin; DATA_TYPE(self) = &mrb_gpio_type; return self; } static mrb_value mrb_gpio_on(mrb_state *mrb, mrb_value self) { mrb_gpio_t *pin = mrb_data_get_ptr(mrb, self, &mrb_gpio_type); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized GPIO struct"); } mrb_machine_gpio_impl_write(pin->pin, MACHINE_GPIO_HIGH); return mrb_nil_value(); } static mrb_value mrb_gpio_off(mrb_state *mrb, mrb_value self) { mrb_gpio_t *pin = mrb_data_get_ptr(mrb, self, &mrb_gpio_type); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized GPIO struct"); } mrb_machine_gpio_impl_write(pin->pin, MACHINE_GPIO_LOW); return mrb_nil_value(); } static mrb_value mrb_gpio_toggle(mrb_state *mrb, mrb_value self) { mrb_gpio_t *pin = mrb_data_get_ptr(mrb, self, &mrb_gpio_type); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized GPIO struct"); } mrb_machine_gpio_impl_toggle(pin->pin); return mrb_nil_value(); } static mrb_value mrb_gpio_get_value(mrb_state *mrb, mrb_value self) { mrb_gpio_t *pin = mrb_data_get_ptr(mrb, self, &mrb_gpio_type); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized GPIO struct"); } int val = mrb_machine_gpio_impl_read(pin->pin); return mrb_int_value(mrb, val); } static mrb_value mrb_gpio_set_value(mrb_state *mrb, mrb_value self) { mrb_gpio_t *pin = mrb_data_get_ptr(mrb, self, &mrb_gpio_type); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized GPIO struct"); } mrb_value new_value = mrb_get_arg1(mrb); mrb_ensure_integer_type(mrb, new_value); mrb_machine_gpio_impl_write(pin->pin, mrb_integer(new_value)); return mrb_nil_value(); } static mrb_value mrb_gpio_config(mrb_state *mrb, mrb_value self) { mrb_value new_cfg = mrb_get_arg1(mrb); mrb_gpio_t *pin = mrb_data_get_ptr(mrb, self, &mrb_gpio_type); if (pin == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized GPIO struct"); } machine_gpio_mode_t new_mode = pin->cfg.mode; machine_gpio_pull_t new_pull = pin->cfg.pull; /* Optional parameters, do not change if not received from hash */ mrb_value pin_mode = mrb_hash_get(mrb, new_cfg, mrb_symbol_value(mrb_intern_static(mrb, "mode", 4))); if (!mrb_nil_p(pin_mode)) { mrb_ensure_integer_type(mrb, pin_mode); new_mode = mrb_integer(pin_mode); if (new_mode >= MACHINE_GPIO_MODE_END) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Invalid GPIO mode"); } } mrb_value pin_pull = mrb_hash_get(mrb, new_cfg, mrb_symbol_value(mrb_intern_static(mrb, "pull", 4))); if (!mrb_nil_p(pin_pull)) { mrb_ensure_integer_type(mrb, pin_pull); new_pull = mrb_integer(pin_pull); if (new_pull >= MACHINE_GPIO_PULL_END) { mrb_raise(mrb, E_ARGUMENT_ERROR, "Invalid GPIO pull"); } } pin->cfg.mode = new_mode; pin->cfg.pull = new_pull; mrb_machine_gpio_impl_config(pin->pin, &pin->cfg); return mrb_nil_value(); } void mrb_machine_gpio_gem_init(mrb_state *mrb) { /** * Example: * pin_led = led = Machine::GPIO.new(10, { * mode: Machine::GPIO::OUTPUT_OD, * pull: Machine::GPIO::PULL_NONE, * init: Machine::GPIO::ON * }) * pin_btn = Machine::GPIO.new(2) # Default mode is Machine::GPIO::INPUT * pin_led.on # Set to logical high * pin_led.off # Set to logical low * pin_led.toggle # Toggle. */ struct RClass *module_machine = mrb_define_module(mrb, "Machine"); struct RClass *class_gpio = mrb_define_class_under(mrb, module_machine, "GPIO", mrb->object_class); MRB_SET_INSTANCE_TT(class_gpio, MRB_TT_CDATA); /* Machine::GPIO::OFF / Machine::GPIO::ON */ mrb_define_const(mrb, class_gpio, "OFF", mrb_fixnum_value(MACHINE_GPIO_LOW)); mrb_define_const(mrb, class_gpio, "ON", mrb_fixnum_value(MACHINE_GPIO_HIGH)); /* Machine::GPIO::PULL_NONE / Machine::GPIO::PULL_UP / Machine::GPIO::PULL_DOWN */ mrb_define_const(mrb, class_gpio, "PULL_NONE", mrb_fixnum_value(MACHINE_GPIO_PULL_NONE)); mrb_define_const(mrb, class_gpio, "PULL_UP", mrb_fixnum_value(MACHINE_GPIO_PULL_UP)); mrb_define_const(mrb, class_gpio, "PULL_DOWN", mrb_fixnum_value(MACHINE_GPIO_PULL_DOWN)); /* Machine::GPIO::MODE_INPUT / Machine::GPIO::MODE_OUTPUT_PP / Machine::GPIO::MODE_OUTPUT_OD */ mrb_define_const(mrb, class_gpio, "INPUT", mrb_fixnum_value(MACHINE_GPIO_MODE_INPUT)); mrb_define_const(mrb, class_gpio, "OUTPUT_PP", mrb_fixnum_value(MACHINE_GPIO_MODE_OUTPUT_PUSHPULL)); mrb_define_const(mrb, class_gpio, "OUTPUT_OD", mrb_fixnum_value(MACHINE_GPIO_MODE_OUTPUT_OPENDRAIN)); /* Instance methods */ mrb_define_method(mrb, class_gpio, "initialize", mrb_gpio_initialize, MRB_ARGS_ARG(1, 1)); mrb_define_method(mrb, class_gpio, "on", mrb_gpio_on, MRB_ARGS_NONE()); mrb_define_method(mrb, class_gpio, "off", mrb_gpio_off, MRB_ARGS_NONE()); mrb_define_method(mrb, class_gpio, "toggle", mrb_gpio_toggle, MRB_ARGS_NONE()); mrb_define_method(mrb, class_gpio, "value", mrb_gpio_get_value, MRB_ARGS_NONE()); mrb_define_method(mrb, class_gpio, "value=", mrb_gpio_set_value, MRB_ARGS_ARG(1, 0)); mrb_define_method(mrb, class_gpio, "config", mrb_gpio_config, MRB_ARGS_ARG(1, 0)); } void mrb_machine_gpio_gem_final(mrb_state *mrb) { /* Unused */ }