#include #include #include #include #include #include #include #include #include #include "config.h" #include "shell.h" #include "kernel.h" #include "guidance_control.h" #include "data_matrix.h" #include "util/ymodem.h" #include "navigation/coordinate.h" #include #include #include #include #include #include #include #include #include class ShellImpl; struct mrb_user_data { ShellImpl *shell; SEM_Handle sem_mrb; mrb_value uplink_notify_lambda; mrb_value guidance_control_lambda; }; //#define NO_MRUBY #if !defined(NO_MRUBY) extern "C"{ extern int yydebug; } /* Old mruby/string.h misses the following macros. */ #ifndef RSTR_SET_LEN # define RSTR_SET_LEN(s, newlen) RSTR_LEN(s) = (newlen) #endif #ifndef RSTR_PTR # define RSTR_PTR(s) (s)->ptr #endif #ifndef RSTR_LEN # define RSTR_LEN(s) (s)->len #endif struct mRubyTinyFeatherInterface { static mrb_value notify_gps_time(mrb_state *mrb, mrb_value self){ // arg1 => wn(Fixnum), arg2 => itow_ms(Fixnum) mrb_int arg1, arg2; mrb_get_args(mrb, "ii", &arg1, &arg2); Kernel::get_instance().notify_gps_time((Uint32)arg1, (Uint32)arg2); return mrb_true_value(); } static mrb_value simulate_1pps(mrb_state *mrb, mrb_value self){ Kernel::get_instance().simulate_1pps(); return mrb_true_value(); } static mrb_value raw(mrb_state *mrb, mrb_value self){ Kernel::special_devices device(Kernel::SYS_MAPPED); unsigned long address(0xC0000000); char buf[64]; int size(sizeof(buf)); bool print(false); // arg1(opt) => Hash mrb_value arg1; if(mrb_get_args(mrb, "|H", &arg1) >= 1){ // if arg_count >= 1 // Checking device, address, size ... mrb_value v; v = mrb_hash_get(mrb, arg1, mrb_symbol_value(mrb_intern_cstr(mrb, "device"))); if(!mrb_nil_p(v)){ device = (Kernel::special_devices)mrb_fixnum(mrb_to_int(mrb, v)); } v = mrb_hash_get(mrb, arg1, mrb_symbol_value(mrb_intern_cstr(mrb, "address"))); if(!mrb_nil_p(v)){ address = mrb_fixnum(mrb_to_int(mrb, v)); if(address < 0){ mrb_raisef(mrb, E_ARGUMENT_ERROR, "address must be 0 <= n: %S", v); } } v = mrb_hash_get(mrb, arg1, mrb_symbol_value(mrb_intern_cstr(mrb, "size"))); if(!mrb_nil_p(v)){ size = mrb_fixnum(mrb_to_int(mrb, v)); if((size < 0) || (size > sizeof(buf))){ mrb_raisef(mrb, E_ARGUMENT_ERROR, "size must be 0 <= n <= %S: %S", mrb_fixnum_value((mrb_int)sizeof(buf)), v); } } v = mrb_hash_get(mrb, arg1, mrb_symbol_value(mrb_intern_cstr(mrb, "print"))); if((mrb_type(v) == MRB_TT_FALSE) || (mrb_type(v) == MRB_TT_TRUE)){ print = mrb_bool(v); } } size = Kernel::get_instance() .open(device, (void *)address) .receive((char *)buf, size); if(print){ char line_buf[128]; int index(0); for(int i(0); i < size; ++i){ if((i & 0x07) == 0){ mrb_funcall(mrb, self, "puts", 1, mrb_str_new(mrb, line_buf, index)); index = std::snprintf(line_buf, sizeof(line_buf), "%08X:", address + i); } index += std::snprintf(&line_buf[index], sizeof(line_buf) - index, " %02X", (unsigned char)buf[i]); } mrb_funcall(mrb, self, "puts", 1, mrb_str_new(mrb, line_buf, index)); } return mrb_str_new(mrb, buf, (size_t)size); } static mrb_value latest_info(mrb_state *mrb, mrb_value self) { mrb_value res(mrb_hash_new(mrb)); { mrb_value gps(mrb_hash_new(mrb)); #define info_cpy(x) \ mrb_hash_set(mrb, gps, mrb_symbol_value(mrb_intern_cstr(mrb, #x)), mrb_float_value(mrb, latest_processed_info.gps.x)) info_cpy(longitude_deg); info_cpy(latitude_deg); info_cpy(height_meter); info_cpy(horizontal_position_accuracy_meter); info_cpy(vertical_position_accuracy_meter); info_cpy(v_north_ms); info_cpy(v_east_ms); info_cpy(v_down_ms); info_cpy(velocity_accuracy_ms); #undef info_cpy #define info_cpy(x) \ mrb_hash_set(mrb, gps, mrb_symbol_value(mrb_intern_cstr(mrb, #x)), mrb_fixnum_value(latest_processed_info.gps.x)) info_cpy(using_satellites); info_cpy(leap_seconds_gps_minus_utc); #undef info_cpy mrb_hash_set(mrb, res, mrb_symbol_value(mrb_intern_cstr(mrb, "gps")), gps); } { mrb_value inertial_sensor(mrb_hash_new(mrb)); { mrb_value accel[3]; mrb_value omega[3]; for(int i(0); i < 3; ++i){ accel[i] = mrb_float_value(mrb, latest_processed_info.inertial_sensor.accel_ms2[i]); omega[i] = mrb_float_value(mrb, latest_processed_info.inertial_sensor.omega_rads[i]); } mrb_hash_set(mrb, inertial_sensor, mrb_symbol_value(mrb_intern_cstr(mrb, "accel_ms2")), mrb_ary_new_from_values(mrb, 3, accel)); mrb_hash_set(mrb, inertial_sensor, mrb_symbol_value(mrb_intern_cstr(mrb, "omega_rads")), mrb_ary_new_from_values(mrb, 3, omega)); } mrb_hash_set(mrb, res, mrb_symbol_value(mrb_intern_cstr(mrb, "inertial_sensor")), inertial_sensor); } { mrb_value ads(mrb_hash_new(mrb)); #define info_cpy(x) \ mrb_hash_set(mrb, ads, mrb_symbol_value(mrb_intern_cstr(mrb, #x)), mrb_float_value(mrb, latest_processed_info.ads.x)) info_cpy(tas_ms); info_cpy(alpha_rad); info_cpy(beta_rad); info_cpy(pressure_alt_meter); #undef info_cpy mrb_hash_set(mrb, res, mrb_symbol_value(mrb_intern_cstr(mrb, "ads")), ads); } { mrb_value magnetic_sensor(mrb_hash_new(mrb)); mrb_value mag[3]; for(int i(0); i < 3; ++i){ mag[i] = mrb_float_value(mrb, latest_processed_info.magnetic_sensor.corrected_mag_tesla[i]); } mrb_hash_set(mrb, magnetic_sensor, mrb_symbol_value(mrb_intern_cstr(mrb, "corrected_mag_tesla")), mrb_ary_new_from_values(mrb, 3, mag)); mrb_hash_set(mrb, res, mrb_symbol_value(mrb_intern_cstr(mrb, "magnetic_sensor")), magnetic_sensor); } { mrb_value navigation(mrb_hash_new(mrb)); #define info_cpy(x) \ mrb_hash_set(mrb, navigation, mrb_symbol_value(mrb_intern_cstr(mrb, #x)), mrb_float_value(mrb, latest_processed_info.navigation.x)) info_cpy(longitude_rad); info_cpy(latitude_rad); info_cpy(height_meter); info_cpy(v_north_ms); info_cpy(v_east_ms); info_cpy(v_down_ms); info_cpy(heading_rad); info_cpy(roll_rad); info_cpy(pitch_rad); #undef info_cpy { mrb_value accel[3]; mrb_value omega[3]; for(int i(0); i < 3; ++i){ accel[i] = mrb_float_value(mrb, latest_processed_info.navigation.corrected_accel_ms2[i]); omega[i] = mrb_float_value(mrb, latest_processed_info.navigation.corrected_omega_rads[i]); } mrb_hash_set(mrb, navigation, mrb_symbol_value(mrb_intern_cstr(mrb, "corrected_accel_ms2")), mrb_ary_new_from_values(mrb, 3, accel)); mrb_hash_set(mrb, navigation, mrb_symbol_value(mrb_intern_cstr(mrb, "corrected_omega_rads")), mrb_ary_new_from_values(mrb, 3, omega)); } mrb_hash_set(mrb, res, mrb_symbol_value(mrb_intern_cstr(mrb, "navigation")), navigation); } return res; } static mrb_value servo_write(mrb_state *mrb, mrb_value self){ Kernel::msg_servo_write_t msg_servo_write; static const int servo_write_ch(sizeof(msg_servo_write.ch) / sizeof(msg_servo_write.ch[0])); int size; mrb_value *argv; mrb_get_args(mrb, "a", &argv, &size); if(size != servo_write_ch){ mrb_raisef(mrb, E_ARGUMENT_ERROR, "Array size must be %S", mrb_fixnum_value(servo_write_ch)); } for(mrb_int i(0); i < servo_write_ch; ++i, ++argv){ if (mrb_type(*argv) != MRB_TT_FIXNUM) { mrb_raise(mrb, E_TYPE_ERROR, "element must be Fixnum"); } msg_servo_write.ch[i] = mrb_fixnum(*argv); } if(!MBX_post(Kernel::get_instance().mbx(Kernel::MBX_SERVO_WRITE), &msg_servo_write, 0)){ return mrb_false_value(); } return mrb_true_value(); } static mrb_value downlink_write(mrb_state *mrb, mrb_value self){ char *c_str; int length; mrb_get_args(mrb, "s", &c_str, &length); ::downlink_write(c_str, length); return self; } // { // ENU static const mrb_data_type enu_type; static mrb_value mrb_enu_value(mrb_state *mrb, const System_ENU<> &enu) { return mrb_obj_value( Data_Wrap_Struct(mrb, mrb_class_get(mrb, enu_type.struct_name), &enu_type, new System_ENU<>(enu))); } static mrb_value enu_initialize(mrb_state *mrb, mrb_value self) { DATA_PTR(self) = new System_ENU<>(); DATA_TYPE(self) = const_cast(&enu_type); return self; } static void enu_free(mrb_state *mrb, void *ptr) { delete static_cast *>(ptr); } #define enu_method_def(x) \ static mrb_value enu_ ## x(mrb_state *mrb, mrb_value self) { \ return mrb_float_value(mrb, static_cast *>(DATA_PTR(self))->x()); \ } enu_method_def(east); enu_method_def(north); enu_method_def(up); enu_method_def(elevation); enu_method_def(azimuth); #undef enu_method_def static mrb_value enu_to_a(mrb_state *mrb, mrb_value self){ System_ENU<> *enu(static_cast *>(DATA_PTR(self))); mrb_value v[] = { mrb_float_value(mrb, enu->east()), mrb_float_value(mrb, enu->north()), mrb_float_value(mrb, enu->up())}; return mrb_ary_new_from_values(mrb, sizeof(v) / sizeof(v[0]), v); } // } // // { // GCInfo static const mrb_data_type gcinfo_type; static mrb_value mrb_gcinfo_value(mrb_state *mrb, const GCInfo &gcinfo) { return mrb_obj_value( Data_Wrap_Struct(mrb, mrb_class_get(mrb, gcinfo_type.struct_name), &gcinfo_type, new GCInfo(gcinfo))); } static mrb_value gcinfo_initialize(mrb_state *mrb, mrb_value self) { DATA_PTR(self) = new GCInfo(); DATA_TYPE(self) = const_cast(&gcinfo_type); return self; } static void gcinfo_free(mrb_state *mrb, void *ptr) { delete static_cast(ptr); } static mrb_value gcinfo_is_valid_raw(mrb_state *mrb, mrb_value self) { return (static_cast(DATA_PTR(self))->health & GCInfo::ACCEL_OMEGA_UPDATED) ? mrb_true_value() : mrb_false_value(); } static mrb_value gcinfo_is_valid_nav(mrb_state *mrb, mrb_value self) { GCInfo *gcinfo(static_cast(DATA_PTR(self))); if((gcinfo->health & (GCInfo::NAV_UPDATED /*| GCInfo::NAV_INITIALIZED*/)) // TODO == (GCInfo::NAV_UPDATED /*| GCInfo::NAV_INITIALIZED*/)){ return mrb_true_value(); } return mrb_false_value(); } static mrb_value gcinfo_is_valid_ads(mrb_state *mrb, mrb_value self) { return (static_cast(DATA_PTR(self))->health & GCInfo::ADS_UPDATED) ? mrb_true_value() : mrb_false_value(); } static mrb_value gcinfo_is_valid_servo_in(mrb_state *mrb, mrb_value self) { return (static_cast(DATA_PTR(self))->health & GCInfo::SERVO_UPDATED) ? mrb_true_value() : mrb_false_value(); } #define gcinfo_method_def(x) \ static mrb_value gcinfo_ ## x(mrb_state *mrb, mrb_value self) { \ return mrb_float_value(mrb, static_cast(DATA_PTR(self))->x); \ } gcinfo_method_def(itow); gcinfo_method_def(longitude_rad); gcinfo_method_def(latitude_rad); gcinfo_method_def(height_meter); gcinfo_method_def(v_north_ms); gcinfo_method_def(v_east_ms); gcinfo_method_def(v_down_ms); gcinfo_method_def(heading_rad); gcinfo_method_def(roll_rad); gcinfo_method_def(pitch_rad); gcinfo_method_def(tas_ms); gcinfo_method_def(alpha_rad); gcinfo_method_def(beta_rad); gcinfo_method_def(pressure_alt_meter); #undef gcinfo_method_def #define gcinfo_method_def(x) \ static mrb_value gcinfo_ ## x(mrb_state *mrb, mrb_value self) { \ GCInfo *gcinfo(static_cast(DATA_PTR(self))); \ mrb_value v[3]; \ for(int i(0); i < 3; ++i){ \ v[i] = mrb_float_value(mrb, gcinfo->x[i]); \ } \ return mrb_ary_new_from_values(mrb, 3, v); \ } gcinfo_method_def(accel_ms2); gcinfo_method_def(omega_rads); gcinfo_method_def(corrected_accel_ms2); gcinfo_method_def(corrected_omega_rads); #undef gcinfo_method_def static mrb_value gcinfo_servo_in(mrb_state *mrb, mrb_value self) { GCInfo *gcinfo(static_cast(DATA_PTR(self))); mrb_value v[8]; for(int i(0); i < sizeof(v) / sizeof(v[0]); ++i){ v[i] = mrb_fixnum_value(gcinfo->servo_in[i]); } return mrb_ary_new_from_values(mrb, sizeof(v) / sizeof(v[0]), v); } static mrb_value gcinfo_enu_from(mrb_state *mrb, mrb_value self) { GCInfo *gcinfo(static_cast(DATA_PTR(self))); System_LLH<> llh_to(gcinfo->latitude_rad, gcinfo->longitude_rad, gcinfo->height_meter), llh_from; mrb_value arg1; mrb_get_args(mrb, "o", &arg1); GCInfo *gcinfo_arg(static_cast(mrb_get_datatype(mrb, arg1, &gcinfo_type))); if(gcinfo_arg){ llh_from.latitude() = gcinfo_arg->latitude_rad; llh_from.longitude() = gcinfo_arg->longitude_rad; llh_from.height() = gcinfo_arg->height_meter; }else{ int size; mrb_value *argv; mrb_get_args(mrb, "a", &argv, &size); if(size != 3){ mrb_raisef(mrb, E_ARGUMENT_ERROR, "Array size must be %S", mrb_fixnum_value(3)); } for(mrb_int i(0); i < 3; ++i, ++argv){ if (mrb_type(*argv) != MRB_TT_FLOAT) { mrb_raise(mrb, E_TYPE_ERROR, "element must be Float"); } llh_from[i] = mrb_float(*argv); } } return mrb_enu_value( mrb, System_ENU<>::relative_rel(llh_to.xyz() - llh_from.xyz(), llh_from)); } // } // { // Kernel::IO static const mrb_data_type io_type; static mrb_value mrb_io_value(mrb_state *mrb, const Kernel::special_devices &id, const void *params) { return mrb_obj_value( Data_Wrap_Struct(mrb, mrb_class_get(mrb, io_type.struct_name), &io_type, new Kernel::IO(Kernel::get_instance().open(id, params)))); } static void io_free(mrb_state *mrb, void *ptr) { delete static_cast(ptr); } static mrb_value io_receive(mrb_state *mrb, mrb_value self) { mrb_int arg1; mrb_get_args(mrb, "i", &arg1); if(arg1 < 0){ mrb_raisef(mrb, E_ARGUMENT_ERROR, "size(n = %S) must be greater than 0", arg1); } mrb_value res(mrb_str_buf_new(mrb, arg1)); struct RString *str(mrb_str_ptr(res)); RSTR_SET_LEN(str, static_cast(DATA_PTR(self))->receive(RSTR_PTR(str), arg1)); return res; } static mrb_value io_transmit(mrb_state *mrb, mrb_value self) { char *c_str; int length; mrb_get_args(mrb, "s", &c_str, &length); static_cast(DATA_PTR(self)) ->transmit(c_str, length); return self; } static mrb_value io_file(mrb_state *mrb, mrb_value self){ char *c_str; mrb_get_args(mrb, "z", &c_str); mrb_value res(mrb_io_value(mrb, Kernel::FAT_FILE, c_str)); static const unsigned int tx_rx_buffers[] = {0x1000, 0x1000}; static_cast(DATA_PTR(res)) ->ioctl(Kernel::IOCTL_BUFFER, tx_rx_buffers); return res; } static mrb_value io_led(mrb_state *mrb, mrb_value self){ mrb_value res(mrb_io_value(mrb, Kernel::OBCLED, NULL)); return res; } // } // { // callback functions static mrb_state *mrb_for_callback; #define make_mrb_func(callbacked, setter, arity) \ static mrb_value get_ ## callbacked(mrb_state *mrb, mrb_value self){ \ return ((mrb_user_data *)mrb->ud)->callbacked ## _lambda; \ } \ static mrb_value set_ ## callbacked(mrb_state *mrb, mrb_value self){ \ mrb_value arg1; \ mrb_get_args(mrb, "o", &arg1); \ if(mrb_nil_p(arg1)){ \ setter(NULL); \ }else if((mrb_type(arg1) != MRB_TT_PROC) \ || (mrb_fixnum(mrb_funcall(mrb, arg1, "arity", 0)) != arity)) { \ mrb_raise(mrb, E_ARGUMENT_ERROR, "Proc(arity=" #arity ") or nil is required!"); \ }else{ \ setter(callbacked); \ } \ mrb_vm_cv_set(mrb, mrb_intern_cstr(mrb, #callbacked), arg1); /* protect from GC */ \ return ((mrb_user_data *)mrb->ud)->callbacked ## _lambda = arg1; \ } static void uplink_notify(char *buf, const unsigned int &buf_size){ SEM_pendBinary(((mrb_user_data *)mrb_for_callback->ud)->sem_mrb, SYS_FOREVER); int mrb_ai(mrb_gc_arena_save(mrb_for_callback)); mrb_funcall(mrb_for_callback, ((mrb_user_data *)mrb_for_callback->ud)->uplink_notify_lambda, "call", 1, mrb_str_new(mrb_for_callback, buf, buf_size)); mrb_gc_arena_restore(mrb_for_callback, mrb_ai); SEM_postBinary(((mrb_user_data *)mrb_for_callback->ud)->sem_mrb); } make_mrb_func(uplink_notify, uplink_read, 1); static void guidance_control(const GCInfo &info){ SEM_pendBinary(((mrb_user_data *)mrb_for_callback->ud)->sem_mrb, SYS_FOREVER); int mrb_ai(mrb_gc_arena_save(mrb_for_callback)); mrb_funcall(mrb_for_callback, ((mrb_user_data *)mrb_for_callback->ud)->guidance_control_lambda, "call", 1, mrb_gcinfo_value(mrb_for_callback, info)); mrb_gc_arena_restore(mrb_for_callback, mrb_ai); SEM_postBinary(((mrb_user_data *)mrb_for_callback->ud)->sem_mrb); } make_mrb_func(guidance_control, switch_guidance_control, 1); #undef make_mrb_func // } // call back functions static void attach(mrb_state *mrb){ int mrb_ai(mrb_gc_arena_save(mrb)); mrb_for_callback = mrb; RClass *tf = mrb_define_module(mrb, "TinyFeather"); mrb_mod_cv_set(mrb, tf, mrb_intern_cstr(mrb, "NAV_UPDATE_RATIO_MS"), mrb_fixnum_value(NAV_UPDATE_RATIO_ms)); mrb_define_class_method(mrb, tf, "notify_gps_time", (mrb_func_t)notify_gps_time, MRB_ARGS_REQ(2)); mrb_define_class_method(mrb, tf, "simulate_1pps", (mrb_func_t)simulate_1pps, MRB_ARGS_NONE()); mrb_define_class_method(mrb, tf, "raw", (mrb_func_t)raw, MRB_ARGS_OPT(1)); mrb_define_class_method(mrb, tf, "latest_info", (mrb_func_t)latest_info, MRB_ARGS_NONE()); mrb_define_class_method(mrb, tf, "servo_write", (mrb_func_t)servo_write, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, tf, "downlink_write", (mrb_func_t)downlink_write, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, tf, "uplink_notify", (mrb_func_t)get_uplink_notify, MRB_ARGS_NONE()); mrb_define_class_method(mrb, tf, "uplink_notify=", (mrb_func_t)set_uplink_notify, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, tf, "guidance_control", (mrb_func_t)get_guidance_control, MRB_ARGS_NONE()); mrb_define_class_method(mrb, tf, "guidance_control=", (mrb_func_t)set_guidance_control, MRB_ARGS_REQ(1)); ((mrb_user_data *)mrb->ud)->uplink_notify_lambda = mrb_nil_value(); ((mrb_user_data *)mrb->ud)->guidance_control_lambda = mrb_nil_value(); RClass *enu = mrb_define_class(mrb, "ENU", mrb->object_class); MRB_SET_INSTANCE_TT(enu, MRB_TT_DATA); mrb_define_method(mrb, enu, "initialize", (mrb_func_t)enu_initialize, MRB_ARGS_NONE()); mrb_define_method(mrb, enu, "east", (mrb_func_t)enu_east, MRB_ARGS_NONE()); mrb_define_method(mrb, enu, "north", (mrb_func_t)enu_north, MRB_ARGS_NONE()); mrb_define_method(mrb, enu, "up", (mrb_func_t)enu_up, MRB_ARGS_NONE()); mrb_define_method(mrb, enu, "elevation", (mrb_func_t)enu_elevation, MRB_ARGS_NONE()); mrb_define_method(mrb, enu, "azimuth", (mrb_func_t)enu_azimuth, MRB_ARGS_NONE()); mrb_define_method(mrb, enu, "to_a", (mrb_func_t)enu_to_a, MRB_ARGS_NONE()); RClass *gcinfo = mrb_define_class(mrb, "GCInfo", mrb->object_class); MRB_SET_INSTANCE_TT(gcinfo, MRB_TT_DATA); mrb_define_method(mrb, gcinfo, "initialize", (mrb_func_t)gcinfo_initialize, MRB_ARGS_NONE()); mrb_define_method(mrb, gcinfo, "itow", (mrb_func_t)gcinfo_itow, MRB_ARGS_NONE()); mrb_define_method(mrb, gcinfo, "valid_raw?", (mrb_func_t)gcinfo_is_valid_raw, MRB_ARGS_NONE()); mrb_define_method(mrb, gcinfo, "valid_nav?", (mrb_func_t)gcinfo_is_valid_nav, MRB_ARGS_NONE()); mrb_define_method(mrb, gcinfo, "valid_ads?", (mrb_func_t)gcinfo_is_valid_ads, MRB_ARGS_NONE()); mrb_define_method(mrb, gcinfo, "valid_servo_in?", (mrb_func_t)gcinfo_is_valid_servo_in, MRB_ARGS_NONE()); mrb_define_method(mrb, gcinfo, "accel_ms2", (mrb_func_t)gcinfo_accel_ms2, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "raw_accel", "accel_ms2"); mrb_define_method(mrb, gcinfo, "omega_ms2", (mrb_func_t)gcinfo_omega_rads, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "raw_omega", "omega_ms2"); mrb_define_method(mrb, gcinfo, "longitude_rad", (mrb_func_t)gcinfo_longitude_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "lng", "longitude_rad"); mrb_define_method(mrb, gcinfo, "latitude_rad", (mrb_func_t)gcinfo_latitude_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "lat", "latitude_rad"); mrb_define_method(mrb, gcinfo, "height_meter", (mrb_func_t)gcinfo_height_meter, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "h", "height_meter"); mrb_define_method(mrb, gcinfo, "v_north_ms", (mrb_func_t)gcinfo_v_north_ms, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "vn", "v_north_ms"); mrb_define_method(mrb, gcinfo, "v_east_ms", (mrb_func_t)gcinfo_v_east_ms, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "ve", "v_east_ms"); mrb_define_method(mrb, gcinfo, "v_down_ms", (mrb_func_t)gcinfo_v_down_ms, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "vd", "v_down_ms"); mrb_define_method(mrb, gcinfo, "heading_rad", (mrb_func_t)gcinfo_heading_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "psi", "heading_rad"); mrb_define_method(mrb, gcinfo, "roll_rad", (mrb_func_t)gcinfo_roll_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "phi", "roll_rad"); mrb_define_method(mrb, gcinfo, "pitch_rad", (mrb_func_t)gcinfo_pitch_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "theta", "pitch_rad"); mrb_define_method(mrb, gcinfo, "corrected_accel_ms2", (mrb_func_t)gcinfo_corrected_accel_ms2, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "accel", "corrected_accel_ms2"); mrb_define_method(mrb, gcinfo, "corrected_omega_ms2", (mrb_func_t)gcinfo_corrected_omega_rads, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "omega", "corrected_omega_ms2"); mrb_define_method(mrb, gcinfo, "tas_ms", (mrb_func_t)gcinfo_tas_ms, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "tas", "tas_ms"); mrb_define_method(mrb, gcinfo, "alpha_rad", (mrb_func_t)gcinfo_alpha_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "aoa", "alpha_rad"); mrb_define_method(mrb, gcinfo, "beta_rad", (mrb_func_t)gcinfo_beta_rad, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "beta", "beta_rad"); mrb_define_method(mrb, gcinfo, "pressure_alt_meter", (mrb_func_t)gcinfo_pressure_alt_meter, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "qne", "pressure_alt_meter"); mrb_define_method(mrb, gcinfo, "servo_in", (mrb_func_t)gcinfo_servo_in, MRB_ARGS_NONE()); mrb_define_alias(mrb, gcinfo, "in", "servo_in"); mrb_define_method(mrb, gcinfo, "enu_from", (mrb_func_t)gcinfo_enu_from, MRB_ARGS_REQ(1)); RClass *io = mrb_define_class(mrb, "IO", mrb->object_class); MRB_SET_INSTANCE_TT(io, MRB_TT_DATA); mrb_define_method(mrb, io, "receive", (mrb_func_t)io_receive, MRB_ARGS_REQ(1)); mrb_define_alias(mrb, io, "read", "receive"); mrb_define_method(mrb, io, "transmit", (mrb_func_t)io_transmit, MRB_ARGS_REQ(1)); mrb_define_alias(mrb, io, "write", "transmit"); mrb_define_class_method(mrb, io, "file", (mrb_func_t)io_file, MRB_ARGS_REQ(1)); mrb_define_class_method(mrb, io, "led", (mrb_func_t)io_led, MRB_ARGS_NONE()); mrb_gc_arena_restore(mrb, mrb_ai); // mrb->arena_idx: 8 => 0, checked with debugger } static void detach(mrb_state *mrb){ } }; extern "C"{ typedef void (*mrb_dfree_func_t)(mrb_state *mrb, void*); } const mrb_data_type mRubyTinyFeatherInterface::gcinfo_type = {"GCInfo", (mrb_dfree_func_t)gcinfo_free}; const mrb_data_type mRubyTinyFeatherInterface::enu_type = {"ENU", (mrb_dfree_func_t)enu_free}; const mrb_data_type mRubyTinyFeatherInterface::io_type = {"IO", (mrb_dfree_func_t)io_free}; mrb_state *mRubyTinyFeatherInterface::mrb_for_callback = NULL; #endif /* #if !defined(NO_MRUBY) */ static class ShellImpl : public Shell { protected: bool system_attached; char in_buf_default[0x400], out_buf[0x400]; char *in_buf, *in_buf_current, *in_buf_end, *out_buf_top, *out_buf_bottom; unsigned int in_buf_size; char in_key_buf[8]; char *in_key_buf_current; SEM_Obj sem_out_buf_available; mrb_state *mrb; mrbc_context *cxt; bool code_block_open; mrb_user_data mrb_ud; SEM_Obj sem_mrb; unsigned int out_buf_write(const void *buf, const int &buf_size){ if(buf_size <= 0){return 0;} int buf_size_remain(buf_size); const char *_buf((const char *)buf); while(true){ int buf_filled(buf_size_remain); int buf_filled_max(out_buf_bottom - out_buf_top); if(buf_filled_max >= 0){ buf_filled_max = (sizeof(out_buf) - 1) - buf_filled_max; }else{ buf_filled_max = -buf_filled_max - 1; } bool overflow(buf_filled > buf_filled_max); if(overflow){ buf_filled = buf_filled_max; } char *out_buf_bottom_next(out_buf_bottom + buf_filled); int buf_filled2(out_buf + sizeof(out_buf) - out_buf_bottom); if(buf_filled > buf_filled2){ std::memcpy(out_buf, _buf + buf_filled2, buf_filled - buf_filled2); out_buf_bottom_next -= sizeof(out_buf); }else{ buf_filled2 = buf_filled; } std::memcpy(out_buf_bottom, _buf, buf_filled2); out_buf_bottom = out_buf_bottom_next; buf_size_remain -= buf_filled; _buf += buf_filled; if(overflow && TSK_isTSK()){ SEM_reset(&sem_out_buf_available, 0); if(SEM_pendBinary(&sem_out_buf_available, 100)){continue;} } break; } return buf_size - buf_size_remain; } unsigned int out_buf_putc(const char &c){ return out_buf_write(&c, sizeof(char)); } #if !defined(NO_MRUBY) void out_buf_p(mrb_state *mrb, mrb_value obj){ obj = mrb_funcall(mrb, obj, "inspect", 0); out_buf_write(RSTRING_PTR(obj), RSTRING_LEN(obj)); out_buf_printf("\r\n"); } #endif /* #if !defined(NO_MRUBY) */ unsigned int out_buf_printf(const char *format, ...){ char buf[sizeof(out_buf)]; va_list args; va_start(args, format); int buf_filled(std::vsnprintf(buf, sizeof(buf), format, args)); va_end(args); return out_buf_write(buf, buf_filled); } void in_buf_reset(){ if(in_buf != in_buf_default){ // is extended buffer? delete [] in_buf; in_buf = in_buf_default; in_buf_size = sizeof(in_buf_default); } in_buf_current = in_buf_end = in_buf; } void in_buf_expand(){ _TRY_BEGIN const unsigned int in_buf_size_new(in_buf_size << 1); char *in_buf_new(new char [in_buf_size_new]); std::memcpy(in_buf_new, in_buf, in_buf_size); if(in_buf != in_buf_default){ // is extended buffer? delete [] in_buf; } in_buf_current = in_buf_new + (in_buf_current - in_buf); in_buf_end = in_buf_new + (in_buf_end - in_buf); in_buf_size = in_buf_size_new; in_buf = in_buf_new; _CATCH(std::bad_alloc &e) // Buffer overflow in_buf_reset(); out_buf_printf("\r\n===BUFFER OVERFLOW===\r\n> "); _CATCH_END } #if !defined(NO_MRUBY) /* Guess if the user might want to enter more * or if he wants an evaluation of his code now */ static bool is_code_block_open(struct mrb_parser_state *parser){ /* check for unterminated string */ if(parser->lex_strterm){return true;} /* check for heredoc */ //if(parser->heredoc_starts_nextline){return true;} if(parser->parsing_heredoc != NULL){return true;} if(parser->heredoc_end_now){ parser->heredoc_end_now = false; return false; } /* check if parser error are available */ if(0 < parser->nerr){ const char *unexpected_end("syntax error, unexpected $end"); const char *message(parser->error_buffer[0].message); /* a parser error occur, we have to check if */ /* we need to read one more line or if there is */ /* a different issue which we have to show to */ /* the user */ if(std::strncmp(message, unexpected_end, std::strlen(unexpected_end)) == 0){ return true; }else if(std::strcmp(message, "syntax error, unexpected keyword_end") == 0){ return false; }else if(std::strcmp(message, "syntax error, unexpected tREGEXP_BEG") == 0){ return false; } } switch(parser->lstate){ /* all states which need more code */ case EXPR_BEG: /* an expression was just started, */ /* we can't end it like this */ return true; case EXPR_DOT: /* a message dot was the last token, */ /* there has to come more */ return true; case EXPR_CLASS: /* a class keyword is not enough! */ /* we need also a name of the class */ return true; case EXPR_FNAME: /* a method name is necessary */ return true; case EXPR_VALUE: /* if, elsif, etc. without condition */ return true; /* now all the states which are closed */ case EXPR_ARG: /* an argument is the last token */ return false; /* all states which are unsure */ case EXPR_CMDARG: break; case EXPR_END: /* an expression was ended */ break; case EXPR_ENDARG: /* closing parenthese */ break; case EXPR_ENDFN: /* definition end */ break; case EXPR_MID: /* jump keyword like break, return, ... */ break; case EXPR_MAX_STATE: /* don't know what to do with this token */ break; default: /* this state is unexpected! */ break; } return false; } bool interpret(){ int mrb_ai(mrb_gc_arena_save(mrb)); /* parse code */ struct mrb_parser_state *parser(mrb_parser_new(mrb)); parser->s = in_buf; parser->send = in_buf_end; parser->lineno = 1; mrb_parser_parse(parser, cxt); code_block_open = is_code_block_open(parser); if(!code_block_open){ out_buf_printf("\r\n"); if(0 < parser->nerr){ /* syntax error */ out_buf_printf("line %d: %s", parser->error_buffer[0].lineno, parser->error_buffer[0].message); }else{ /* generate bytecode */ //int n(mrb_generate_code(mrb, parser)); // old struct RProc *proc(mrb_generate_code(mrb, parser)); //new /* evaluate the bytecode by passing a proc for evaulation */ //mrb_value result(mrb_run(mrb, mrb_proc_new(mrb, mrb->irep[n]), mrb_top_self(mrb))); // old mrb_value result(mrb_context_run(mrb, proc, mrb_top_self(mrb), proc->body.irep->nregs)); // new /* did an exception occur? */ if(mrb->exc){ out_buf_p(mrb, mrb_obj_value(mrb->exc)); mrb->exc = 0; }else{ /* no */ out_buf_printf(" => "); //if(!mrb_respond_to(mrb, result, mrb_intern(mrb, "inspect"))){ // old if(!mrb_respond_to(mrb, result, mrb_intern_lit(mrb, "inspect"))){ // new result = mrb_any_to_s(mrb, result); } out_buf_p(mrb, result); } } } mrb_parser_free(parser); mrb_gc_arena_restore(mrb, mrb_ai); #if 0 if(std::strcmp(argv[0], "erase") == 0){ // Erace Flash ROM } if(std::strcmp(argv[0], "burn") == 0){ // Burn Flash ROM } if(std::strcmp(argv[0], "load.f") == 0){ // Load from file on FAT } if(std::strcmp(argv[0], "load.y") == 0){ // Load via terminal by using ymodel } if(std::strcmp(argv[0], "ls") == 0){ // File list } if(std::strcmp(argv[0], "cd") == 0){ // Change directory or move to root } if(std::strcmp(argv[0], "pwd") == 0){ // Show current directory } if(std::strcmp(argv[0], "cat") == 0){ // Show file } if(std::strcmp(argv[0], "reboot") == 0){ // Reboot } out_buf_printf("Command not found: %s", argv[0]); #endif return false; } #else bool interpret(){ code_block_open = false; return true; // do nothing } #endif /* #if !defined(NO_MRUBY) */ ShellImpl(const ShellImpl &orig){} public: unsigned int receive(char *buf, const unsigned int &buf_size) { int buf_filled(out_buf_bottom - out_buf_top); if(buf_filled >= 0){ // [xxxooooooxxx] (o:valid data) if(buf_filled > buf_size){ buf_filled = buf_size; } std::memcpy(buf, out_buf_top, buf_filled); out_buf_top += buf_filled; }else{ // [oooxxxxxxooo] (o:valid data) int buf_filled2(out_buf + sizeof(out_buf) - out_buf_top); char *out_buf_top_next(out_buf_top); if(buf_filled2 < buf_size){ unsigned int remain(buf_size - buf_filled2); buf_filled = out_buf_bottom - out_buf; if(buf_filled > remain){ buf_filled = remain; } std::memcpy(buf + buf_filled2, out_buf, buf_filled); out_buf_top_next = out_buf + buf_filled; }else{ buf_filled = 0; buf_filled2 = buf_size; out_buf_top_next += buf_size; } std::memcpy(buf, out_buf_top, buf_filled2); buf_filled += buf_filled2; out_buf_top = out_buf_top_next; } if((buf_filled > 0) && TSK_isTSK()){ SEM_postBinary(&sem_out_buf_available); TSK_yield(); } return buf_filled; } // @see http://www14.ocn.ne.jp/~bkclass/doc_vt100.html unsigned int transmit(const char *buf, const unsigned int &buf_size){ for(int index(0); index < buf_size; ++index){ if(buf[index] == '\x03'){ in_key_buf_current = in_key_buf; in_buf_current = in_buf_end = in_buf; out_buf_printf("\r\n> "); continue; } if(in_key_buf_current != in_key_buf){ // handle special key input *(in_key_buf_current++) = buf[index]; if(in_key_buf_current - in_key_buf < 3){ // The special key codes are represented in three chars. continue; } if(in_key_buf[1] == '['){ switch(in_key_buf[2]){ case 'A': // Up break; case 'B': // Down break; case 'C': // Right if(in_buf_current < in_buf_end){ ++in_buf_current; out_buf_printf("\x1b[C"); } break; case 'D': // Left if((in_buf_current > in_buf) && (*(in_buf_current - 1) != '\n')){ --in_buf_current; out_buf_printf("\x1b[D"); } break; case 'H': { // Home char *in_buf_next(in_buf_current); while(in_buf_next > in_buf){ if(*(in_buf_next - 1) == '\n'){break;} --in_buf_next; } out_buf_printf("\x1b[%dD", in_buf_current - in_buf_next); in_buf_current = in_buf_next; break; } case 'K': // End if(in_buf_current < in_buf_end){ out_buf_printf("\x1b[%dC", in_buf_end - in_buf_current); in_buf_current = in_buf_end; } break; } } in_key_buf_current = in_key_buf; continue; } bool do_interpret(false); switch(buf[index]){ case '\x1b': in_key_buf[0] = buf[index]; in_key_buf_current = in_key_buf + 1; break; case '\b': if((in_buf_current > in_buf) && (*(in_buf_current - 1) != '\n')){ std::memmove(in_buf_current - 1, in_buf_current, in_buf_end - in_buf_current); --in_buf_current; *(--in_buf_end) = '\0'; out_buf_printf("\x1b[D\x1b[K"); if(in_buf_current < in_buf_end){ out_buf_printf("%s\x1b[%dD", in_buf_current, in_buf_end - in_buf_current); } } break; case '\n': if(in_key_buf[0] == '\r'){ // treat "\r\n" as 1-line break; } case '\r': if(in_buf_end > in_buf){ do_interpret = true; }else{ out_buf_printf("\r\n> "); } in_key_buf[0] = buf[index]; break; default: // printable characters will be echoed. if((buf[index] >= 0x20) && (buf[index] <= 0x7E)){ if(in_buf_current == in_buf_end){ out_buf_putc(*in_buf_end = buf[index]); in_buf_current = (++in_buf_end); }else{ std::memmove(in_buf_current + 1, in_buf_current, in_buf_end - in_buf_current); *(in_buf_current++) = buf[index]; *(++in_buf_end) = '\0'; out_buf_printf("\x1b[K%s\x1b[%dD", in_buf_current - 1, in_buf_end - in_buf_current); } if(in_buf_end >= &in_buf[in_buf_size - 1]){ // require to expand buffer? in_buf_expand(); } } break; } if(!do_interpret){continue;} *in_buf_end = '\0'; if(TSK_isTSK()){ SEM_pendBinary(&sem_mrb, SYS_FOREVER); interpret(); SEM_postBinary(&sem_mrb); }else{ interpret(); } if(code_block_open){ *(in_buf_end++) = '\n'; in_buf_current = in_buf_end; out_buf_printf("\r\n* "); }else{ in_buf_reset(); out_buf_printf("\r\n> "); } } return buf_size; } #if !defined(NO_MRUBY) /* 15.3.1.2.9 */ /* 15.3.1.3.34 */ static mrb_value mrb_printstr(mrb_state *mrb, mrb_value self){ mrb_value argv; mrb_get_args(mrb, "o", &argv); if(mrb_string_p(argv)){ struct RString *str(mrb_str_ptr(argv)); ((mrb_user_data *)mrb->ud) ->shell->out_buf_write(RSTR_PTR(str), RSTR_LEN(str)); } return argv; } static mrb_value mrb_sleep(mrb_state *mrb, mrb_value self){ mrb_int arg1; mrb_get_args(mrb, "i", &arg1); if(!TSK_isTSK()){ return mrb_fixnum_value(0); } TSK_sleep(arg1); return mrb_fixnum_value(arg1); } #endif public: ShellImpl() : Shell(), system_attached(false), in_buf(in_buf_default), in_buf_current(in_buf), in_buf_end(in_buf), out_buf_top(out_buf), out_buf_bottom(out_buf), in_buf_size(sizeof(in_buf_default)), in_key_buf_current(in_key_buf), mrb(NULL), cxt(NULL), code_block_open(false){ SEM_new(&sem_out_buf_available, 0); SEM_new(&sem_mrb, 0); SEM_postBinary(&sem_mrb); in_key_buf[0] = '\n'; #if !defined(NO_MRUBY) yydebug = 0; if(!(mrb = mrb_open())){return;} int mrb_ai(mrb_gc_arena_save(mrb)); struct RClass *krn(mrb->kernel_module); //mrb_undef_method(mrb, krn, "__printstr__"); // redefine __printstr__ of mruby-print gem. mrb_define_method(mrb, krn, "__printstr__", (mrb_func_t)mrb_printstr, MRB_ARGS_REQ(1)); mrb_define_method(mrb, krn, "sleep", (mrb_func_t)mrb_sleep, MRB_ARGS_REQ(1)); mrb_gc_arena_restore(mrb, mrb_ai); mrb->ud = &mrb_ud; mrb_ud.shell = this; mrb_ud.sem_mrb = &sem_mrb; cxt = mrbc_context_new(mrb); cxt->capture_errors = 1; //cxt->dump_result = 0; // default #endif /* #if !defined(NO_MRUBY) */ } ~ShellImpl(){ #if !defined(NO_MRUBY) if(system_attached){ mRubyTinyFeatherInterface::detach(mrb); } if(cxt){ mrbc_context_free(mrb, cxt); } if(mrb){ mrb_close(mrb); } #endif /* #if !defined(NO_MRUBY) */ } void initialize(){ #if !defined(NO_MRUBY) mRubyTinyFeatherInterface::attach(mrb); system_attached = true; #endif /* #if !defined(NO_MRUBY) */ } } shell_imple; Shell::Shell() : MinimalIO() {} Shell::~Shell() {} Shell &shell(shell_imple);