#include #include #include #include #include /* Private */ #include "pwm.h" typedef struct { uint32_t channel; } mrb_pwm_t; static void mrb_pwm_free(mrb_state *mrb, void *ptr); const struct mrb_data_type mrb_pwm_type = { .struct_name = "PWM", .dfree = mrb_pwm_free, }; static void mrb_pwm_free(mrb_state *mrb, void *ptr) { mrb_free(mrb, ptr); } static mrb_value mrb_pwm_initialize(mrb_state *mrb, mrb_value self) { mrb_int channel_id; mrb_value init_cfg; uint32_t init_freq = 1000; uint32_t init_duty = 32768; bool init_enabled = false; mrb_int nargs = mrb_get_args(mrb, "i|H", &channel_id, &init_cfg); if (nargs == 2) { mrb_ensure_hash_type(mrb, init_cfg); mrb_value freq_value = mrb_hash_get(mrb, init_cfg, mrb_symbol_value(mrb_intern_static(mrb, "freq", 4))); if (!mrb_nil_p(freq_value)) { mrb_ensure_integer_type(mrb, freq_value); init_freq = mrb_integer(freq_value); } mrb_value duty_value = mrb_hash_get(mrb, init_cfg, mrb_symbol_value(mrb_intern_static(mrb, "duty", 4))); if (!mrb_nil_p(duty_value)) { mrb_ensure_integer_type(mrb, duty_value); init_duty = mrb_integer(duty_value); } mrb_value enabled_value = mrb_hash_get(mrb, init_cfg, mrb_symbol_value(mrb_intern_static(mrb, "enabled", 7))); if (!mrb_nil_p(enabled_value)) { mrb_ensure_integer_type(mrb, enabled_value); init_enabled = mrb_integer(enabled_value) ? true : false; } } mrb_pwm_t *pwm_ch = mrb_malloc(mrb, sizeof(mrb_pwm_t)); if (pwm_ch == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Failed to allocate PWM struct"); } pwm_ch->channel = channel_id; machine_pwm_config_t cfg = { .freq = init_freq, .duty = init_duty, .enabled = init_enabled, }; mrb_machine_pwm_impl_init(pwm_ch->channel, &cfg); DATA_PTR(self) = pwm_ch; DATA_TYPE(self) = &mrb_pwm_type; return self; } static mrb_value mrb_pwm_enable(mrb_state *mrb, mrb_value self) { mrb_pwm_t *pwm_ch = mrb_data_get_ptr(mrb, self, &mrb_pwm_type); if (pwm_ch == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized PWM struct"); } mrb_machine_pwm_impl_output_set(pwm_ch->channel, true); return mrb_nil_value(); } static mrb_value mrb_pwm_disable(mrb_state *mrb, mrb_value self) { mrb_pwm_t *pwm_ch = mrb_data_get_ptr(mrb, self, &mrb_pwm_type); if (pwm_ch == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized PWM struct"); } mrb_machine_pwm_impl_output_set(pwm_ch->channel, false); return mrb_nil_value(); } static mrb_value mrb_pwm_enabled_get(mrb_state *mrb, mrb_value self) { mrb_pwm_t *pwm_ch = mrb_data_get_ptr(mrb, self, &mrb_pwm_type); if (pwm_ch == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized PWM struct"); } bool enabled = mrb_machine_pwm_impl_output_get(pwm_ch->channel); return mrb_bool_value(enabled); } static mrb_value mrb_pwm_enabled_set(mrb_state *mrb, mrb_value self) { mrb_value enabled = mrb_get_arg1(mrb); if (mrb_integer(enabled) != 0) { return mrb_pwm_enable(mrb, self); } else { return mrb_pwm_disable(mrb, self); } } static mrb_value mrb_pwm_duty_get(mrb_state *mrb, mrb_value self) { mrb_pwm_t *pwm_ch = mrb_data_get_ptr(mrb, self, &mrb_pwm_type); if (pwm_ch == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized PWM struct"); } uint16_t duty = mrb_machine_pwm_impl_duty_get(pwm_ch->channel); return mrb_int_value(mrb, duty); } static mrb_value mrb_pwm_duty_set(mrb_state *mrb, mrb_value self) { mrb_value new_duty = mrb_get_arg1(mrb); mrb_ensure_integer_type(mrb, new_duty); mrb_pwm_t *pwm_ch = mrb_data_get_ptr(mrb, self, &mrb_pwm_type); if (pwm_ch == NULL) { mrb_raise(mrb, E_RUNTIME_ERROR, "Uninitialized PWM struct"); } mrb_machine_pwm_impl_duty_set(pwm_ch->channel, mrb_integer(new_duty)); return mrb_nil_value(); } void mrb_machine_pwm_gem_init(mrb_state *mrb) { /** * Example: * pwm_pin led = Machine::PWM.new(0, {frequency: 1000, duty: 32768, enable: false}) * led.enable * led.disable * led.freq(5000) * led.duty(10) * led.freq += 1000 * led.duty = 512 */ struct RClass *module_machine = mrb_define_module(mrb, "Machine"); struct RClass *class_pwm = mrb_define_class_under(mrb, module_machine, "PWM", mrb->object_class); MRB_SET_INSTANCE_TT(class_pwm, MRB_TT_CDATA); mrb_define_method(mrb, class_pwm, "initialize", mrb_pwm_initialize, MRB_ARGS_ARG(1, 1)); mrb_define_method(mrb, class_pwm, "enable", mrb_pwm_enable, MRB_ARGS_NONE()); mrb_define_method(mrb, class_pwm, "disable", mrb_pwm_disable, MRB_ARGS_NONE()); mrb_define_method(mrb, class_pwm, "enabled", mrb_pwm_enabled_get, MRB_ARGS_NONE()); mrb_define_method(mrb, class_pwm, "enabled=", mrb_pwm_enabled_set, MRB_ARGS_ARG(1, 0)); mrb_define_method(mrb, class_pwm, "duty", mrb_pwm_duty_get, MRB_ARGS_NONE()); mrb_define_method(mrb, class_pwm, "duty=", mrb_pwm_duty_set, MRB_ARGS_ARG(1, 0)); /* TODO: Implement methods */ } void mrb_machine_pwm_gem_final(mrb_state *mrb) { /* Unused */ }