175 lines
5.3 KiB
C
175 lines
5.3 KiB
C
#include <mruby.h>
|
|
#include <mruby/class.h>
|
|
#include <mruby/data.h>
|
|
#include <mruby/hash.h>
|
|
#include <stdbool.h>
|
|
|
|
/* 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 */
|
|
} |