diff --git a/i2c-stick-arduino/app.cpp.jinja2 b/i2c-stick-arduino/app.cpp.jinja2 new file mode 100644 index 0000000..6ccd94d --- /dev/null +++ b/i2c-stick-arduino/app.cpp.jinja2 @@ -0,0 +1,115 @@ +#include "{{app.src_name}}_app.h" +#include "i2c_stick.h" +#include "i2c_stick_dispatcher.h" +#include "i2c_stick_cmd.h" +#include "i2c_stick_hal.h" +#include +#include +#include + + +// Set here the slave address(SA) which the application should use by default +// in the Configure Application command (ca), you can change the SA to be used by this app. +static uint8_t g_sa = 0x05; + + +uint8_t +cmd_{{app.function_id}}_app_begin(uint8_t channel_mask) +{ + uint8_t ok = 1; + char buf[32]; + +// configure the slave for the {{app.name}} app (and set ok=0 in case it fails). + + if (ok) + { + send_answer_chunk(channel_mask, ":", 0); + itoa(APP_{{app.name}}_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":OK", 1); + } + else // when failed.. + { + send_answer_chunk(channel_mask, ":", 0); + itoa(APP_{{app.name}}_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAILED (app not started)", 1); + return APP_NONE; + } + + +// potentially disable the mlx90394 for emitting results in the continuous mode. + + return APP_{{app.name}}_ID; +} + + +void +handle_{{app.function_id}}_app(uint8_t channel_mask) +{ + static uint32_t prev_time = hal_get_millis(); + char buf[32]; memset(buf, 0, sizeof(buf)); + if (hal_get_millis() - prev_time > 100) /* this is an example code to check-in every 100ms with the sensor. */ + { + // reset the timer + prev_time = hal_get_millis(); + + // all apps responds back to the communication channel on its own, therefore we start it ALWAYS with a hastag '#' + // the format is: + // #:,,..., + // value can be integer format or floating point format. + send_answer_chunk(channel_mask, "#", 0); + itoa(APP_{{app.name}}_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + // read sensor values + int raw_value = 1234; + + // process sensor values as one would do in the application. + float processed_value = raw_value; + processed_value /= 100; + + + // report the results + send_answer_chunk(channel_mask, ":", 0); // remember the first separator is ':', after it is only ','! + itoa(raw_value, buf, 10); // note: replace + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ",", 0); + sprintf(buf, "%5.3f", processed_value); + send_answer_chunk(channel_mask, buf, 1); // only the last line will terminate the communication line. + + } + +} + + +uint8_t +cmd_{{app.function_id}}_app_end(uint8_t channel_mask) +{ + char buf[32]; + send_answer_chunk(channel_mask, ":ENDING:", 0); + itoa(APP_{{app.name}}_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + return APP_NONE; +} + + +void +cmd_{{app.function_id}}_ca(uint8_t channel_mask, const char *input) +{ + char buf[16]; memset(buf, 0, sizeof(buf)); + send_answer_chunk(channel_mask, "ca:", 0); + itoa(APP_{{app.name}}_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":SA=", 0); + uint8_to_hex(buf, g_sa); + send_answer_chunk(channel_mask, buf, 1); +} + + +void +cmd_{{app.function_id}}_ca_write(uint8_t channel_mask, const char *input) +{ +} diff --git a/i2c-stick-arduino/app.h.jinja2 b/i2c-stick-arduino/app.h.jinja2 new file mode 100644 index 0000000..158d015 --- /dev/null +++ b/i2c-stick-arduino/app.h.jinja2 @@ -0,0 +1,20 @@ +#ifndef _{{app.name}}_CMD_ +#define _{{app.name}}_CMD_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t cmd_{{app.function_id}}_app_begin(uint8_t channel_mask); +void handle_{{app.function_id}}_app(uint8_t channel_mask); +uint8_t cmd_{{app.function_id}}_app_end(uint8_t channel_mask); +void cmd_{{app.function_id}}_ca(uint8_t channel_mask, const char *input); +void cmd_{{app.function_id}}_ca_write(uint8_t channel_mask, const char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/i2c-stick-arduino/dodo.py b/i2c-stick-arduino/dodo.py index 0c24ac2..7fe8c89 100644 --- a/i2c-stick-arduino/dodo.py +++ b/i2c-stick-arduino/dodo.py @@ -70,16 +70,43 @@ # remove the disabled drivers context['drivers'] = [driver for driver in context['drivers'] if driver['disable'] == 0] +for index, driver in enumerate(context['drivers']): + driver['id'] = index + 1 + + +# APPLICATIONS +for app in context['applications']: + if 'disable' not in app: + app['disable'] = 0 + +# Arduino compiles all cpp files in the directory; rename to .disable +for app in context['applications']: + if app['disable']: + files = list(Path(".").glob(app['src_name'] + "_*.cpp")) + list(Path(".").glob(app['src_name'] + "_*.h")) + for file in files: + shutil.move(file, str(file) + ".disable") + +# undo: Arduino compiles all cpp files in the directory; rename to .disable +for app in context['applications']: + if app['disable'] == 0: + files = list(Path(".").glob(app['src_name'] + "_*.disable")) + for file in files: + shutil.move(file, str(file).replace(".disable", "")) + +# remove the disabled applications +context['applications'] = [app for app in context['applications'] if app['disable'] == 0] + +for index, app in enumerate(context['applications']): + app['id'] = index + 1 + + # remove the disabled boards for board in context['boards']: if 'disable' not in board: board['disable'] = 0 context['boards'] = [board for board in context['boards'] if board['disable'] == 0] - -for index, driver in enumerate(context['drivers']): - driver['id'] = index + 1 - + arduino_add_url = " ".join(["--additional-urls {}".format(x) for x in context['board_manager']['additional-urls']]) ARDUINO_CLI = os.path.join('tools', 'arduino-cli' + Path(sys.executable).suffix) @@ -474,6 +501,8 @@ def do_upload(board_cfg, port): if p.vid == vid: if p.pid == pid: filtered_ports.append(p) + if len(filtered_ports) <= 0: + return "echo no compatible comport found" port = filtered_ports[0].name if method == 'arduino-cli': @@ -684,6 +713,98 @@ def do_add_driver(driver, src_name, function_id, sa_list): } +def task_add_app(): + """Add a templated entry for a new driver for a sensor to the framework""" + + def do_generate(template, output, data): + yamlinclude.YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir=this_dir) + loader = jinja2.FileSystemLoader(this_dir) + + env = jinja2.Environment( + loader=loader, + autoescape=jinja2.select_autoescape() + ) + + tpl = env.get_template(template) + print("output:", output) + with open(output, 'w') as output_f: + output_f.write(tpl.render(data)) + output_f.write("\n") + + def do_add_app(app, src_name, function_id): + if app is None: + print("Please provide parameters about the application") + print("Run 'doit info add-app' for more information") + return + if src_name is None: + src_name = app.lower() + if function_id is None: + if src_name.startswith('mlx'): + function_id = src_name[3:] + if function_id is None: + print("Please provide parameters about the application") + print("Run 'doit info add-app' for more information") + return + + app_data = {'app': { + 'name': app, + 'src_name': src_name, + 'function_id': function_id + }, + } + + for appli in context['applications']: + if appli['name'] == app: + print("ERROR: App '{}' already exists;".format(appli)) + return + + do_generate("app.h.jinja2", "{}_app.h".format(src_name), app_data) + do_generate("app.cpp.jinja2", "{}_app.cpp".format(src_name), app_data) + # now update the context.yaml file! + + yaml_file = src_name+"_application.yaml" + print("output:", yaml_file) + with open(yaml_file, 'w') as output_f: + output_f.write(yaml.dump({ + 'name': app, + 'src_name': src_name, + 'function_id': function_id, + })) + output_f.write("\n") + + # and finally re-generate the dispatcher for the newly added driver. + # from doit.doit_cmd import DoitMain + # DoitMain().run(["--always", "generate:i2c_stick_dispatcher.h"]) + # DoitMain().run(["--always", "generate:i2c_stick_dispatcher.cpp"]) + + return { + 'basename': 'add-app', + 'actions': [(do_add_app,)], + 'file_dep': ['app.h.jinja2', 'app.cpp.jinja2'], + 'params': [ + {'name': 'app', + 'short': 'd', + 'long': 'app', + 'type': str, + 'default': None, + }, + {'name': 'src_name', + 'short': 's', + 'long': 'src_name', + 'type': str, + 'default': None, + }, + {'name': 'function_id', + 'short': 'f', + 'long': 'function_id', + 'type': str, + 'default': None, + }, + ], + 'uptodate': [False], # make to run the task always + 'verbosity': 2, + } + def task_dist(): def make_dist_dir(): if not Path("../dist").is_dir(): diff --git a/i2c-stick-arduino/driver_cmd.cpp.jinja2 b/i2c-stick-arduino/driver_cmd.cpp.jinja2 index a24ab39..450db22 100644 --- a/i2c-stick-arduino/driver_cmd.cpp.jinja2 +++ b/i2c-stick-arduino/driver_cmd.cpp.jinja2 @@ -423,7 +423,7 @@ cmd_{{driver.function_id}}_mw(uint8_t sa, uint16_t *mem_data, uint16_t mem_start void cmd_{{driver.function_id}}_is(uint8_t sa, uint8_t *is_ok, char const **error_message) -{ // function to call prior any init, only to check is the connected slave IS a MLX90614. +{ // function to call prior any init, only to check is the connected slave IS a {{driver.name}}. uint16_t value; *is_ok = 1; // be optimistic! @@ -436,10 +436,11 @@ cmd_{{driver.function_id}}_is(uint8_t sa, uint8_t *is_ok, char const **error_mes // remember there is no communication initiated yet... - // in this ecample below for MLX90614 we check if the EEPROM reads the slave address at address 0x2E... + // in this example below we check if the EEPROM reads the slave address at address 0x2E, + // and check if that fits with the currently SA in use! -// MLX90614_SMBusInit(); -// if (MLX90614_SMBusRead(sa, 0x2E, &value) < 0) +// {{driver.name}}_I2CInit(); +// if ({{driver.name}}_I2cRead(sa, 0x2E, &value) < 0) { *error_message = {{driver.name}}_ERROR_COMMUNICATION; *is_ok = 0; diff --git a/i2c-stick-arduino/i2c-stick-arduino.ino b/i2c-stick-arduino/i2c-stick-arduino.ino index 5d7b5bc..9be1dcf 100644 --- a/i2c-stick-arduino/i2c-stick-arduino.ino +++ b/i2c-stick-arduino/i2c-stick-arduino.ino @@ -139,9 +139,9 @@ hal_write_pin(uint8_t pin, uint8_t state) uint8_t -hal_read_pin(uint8_t pin, uint8_t pullup) +hal_read_pin(uint8_t pin) { - pinMode(pin, pullup ? INPUT_PULLUP : INPUT); + pinMode(pin, INPUT); return digitalRead(pin); } @@ -354,7 +354,7 @@ loop() { handle_continuous_mode(); } - handle_applications(); + handle_applications(g_channel_mask); } @@ -399,14 +399,6 @@ void msc_flush_cb (void) #endif // ENABLE_USB_MSC - - -void -handle_applications() -{ - //uint8_t channel_mask = 0xFF; -} - uint16_t int_uart() { diff --git a/i2c-stick-arduino/i2c_stick_cmd.cpp b/i2c-stick-arduino/i2c_stick_cmd.cpp index 792ec2e..c7a8f9a 100644 --- a/i2c-stick-arduino/i2c_stick_cmd.cpp +++ b/i2c-stick-arduino/i2c_stick_cmd.cpp @@ -704,37 +704,29 @@ handle_cmd(uint8_t channel_mask, const char *cmd) return NULL; } - this_cmd = "pin"; // Pin command + this_cmd = "pinval"; // Pin value command if (!strncmp(this_cmd, cmd, strlen(this_cmd))) { - int16_t pin_no = -1; + int16_t pin_num = -1; if (cmd[strlen(this_cmd)] == ':') { const char *p = cmd+strlen(this_cmd)+1; if (('0' <= *p) && (*p <= '9')) { - pin_no = atoi(p); + pin_num = atoi(p); } } - if (pin_no >= 0) + if (pin_num >= 0) { const char *p = strchr(cmd+strlen(this_cmd)+1, ':'); - int16_t value = -1; + int16_t pval = -1; if (p) { - value = atoi(p+1); - } else - { - value = hal_read_pin(pin_no, strchr(cmd+strlen(this_cmd)+1, '+') ? 1 : 0); - char buf[32]; - sprintf(buf, ":%d:read:%d", pin_no, value); - send_answer_chunk(channel_mask, this_cmd, 0); - send_answer_chunk(channel_mask, buf, 1); - return NULL; + pval = atoi(p+1); } - if ((value == 0) || (value == 1)) + if ((pval == 0) || (pval == 1)) { - hal_write_pin(pin_no, value); + hal_write_pin(pin_num, pval); send_answer_chunk(channel_mask, this_cmd, 0); send_answer_chunk(channel_mask, ":OK", 1); } else @@ -745,7 +737,7 @@ handle_cmd(uint8_t channel_mask, const char *cmd) } else { send_answer_chunk(channel_mask, this_cmd, 0); - send_answer_chunk(channel_mask, ":FAIL:invalid pin_no", 1); + send_answer_chunk(channel_mask, ":FAIL:pwm invalid pin_num", 1); } return NULL; } @@ -945,16 +937,32 @@ handle_cmd(uint8_t channel_mask, const char *cmd) return NULL; } + this_cmd = "la"; // List Applications command + if (!strncmp(this_cmd, cmd, strlen(this_cmd))) + { + cmd_la(channel_mask); + return NULL; + } this_cmd = "ca"; // Config Application command if (!strncmp(this_cmd, cmd, strlen(this_cmd))) { - int16_t app_id = atohex8(cmd+strlen(this_cmd)); - if (app_id < 0) + int16_t app_id = g_app_id; + uint8_t i = strlen(this_cmd); + if (cmd[i] == ':') { - app_id = g_app_id; + i++; + app_id = atoi(cmd+i); } - uint8_t i = 0; + + if ((app_id < 0) || (app_id >= 256)) + { + send_answer_chunk(channel_mask, cmd, 0); + send_answer_chunk(channel_mask, ":FAILED (invalid APP id)", 1); + return NULL; + } + + for (; i= 256)) { - send_answer_chunk(channel_mask, "FAILED", 1); + send_answer_chunk(channel_mask, ":FAILED (invalid APP id)", 1); } else { - g_app_id = app_id; - char buf[8]; memset(buf, 0, sizeof(buf)); - uint8_to_hex(buf, app_id); - send_answer_chunk(channel_mask, buf, 0); - send_answer_chunk(channel_mask, ":STARTED", 1); + if (g_app_id != app_id) + { + if (g_app_id != APP_NONE) + { // end the previous app + cmd_app_end(channel_mask); + } + } + // begin the new app + g_app_id = cmd_app_begin(app_id, channel_mask); } return NULL; } @@ -1030,7 +1056,7 @@ handle_cmd_mv(uint8_t sa, uint8_t channel_mask) { float mv_list[768+1]; uint16_t mv_count = sizeof(mv_list)/sizeof(mv_list[0]); - char buf[16]; + char buf[20]; const char *error_message = NULL; uint32_t time_stamp = hal_get_millis(); @@ -1077,7 +1103,7 @@ handle_cmd_mv(uint8_t sa, uint8_t channel_mask) for (int16_t i=0; i 10) p = "NaN"; // should never ever happen! @@ -1861,36 +1887,6 @@ cmd_ch_write(uint8_t channel_mask, const char *input) // end of host only commands -uint8_t -cmd_ca(uint8_t app_id, uint8_t channel_mask, const char *input) -{ - switch(app_id) - { - case APP_NONE: - break; - default: - return 0; - } - return app_id; -} - - -uint8_t -cmd_ca_write(uint8_t app_id, uint8_t channel_mask, const char *input) -{ - // 1. all is specific for each application - switch(app_id) - { - case APP_NONE: - break; - default: - return 0; - } - return app_id; -} - - - void handle_cmd_sos(uint8_t channel_mask, const char *input) { diff --git a/i2c-stick-arduino/i2c_stick_dispatcher.cpp b/i2c-stick-arduino/i2c_stick_dispatcher.cpp index e848b54..890313b 100644 --- a/i2c-stick-arduino/i2c_stick_dispatcher.cpp +++ b/i2c-stick-arduino/i2c_stick_dispatcher.cpp @@ -7,11 +7,15 @@ #include "i2c_stick_cmd.h" // Include all the drivers cmd header files: +#include "mlx90394_cmd.h" #include "mlx90614_cmd.h" #include "mlx90632_cmd.h" #include "mlx90640_cmd.h" #include "mlx90641_cmd.h" +// Include all the applications header files: +#include "mlx90394_thumbstick_app.h" + #include #include @@ -19,6 +23,7 @@ int16_t i2c_stick_register_all_drivers() { int16_t result = 1; + if (cmd_90394_register_driver() < 0) result = -1; if (cmd_90614_register_driver() < 0) result = -1; if (cmd_90632_register_driver() < 0) result = -1; if (cmd_90640_register_driver() < 0) result = -1; @@ -32,6 +37,8 @@ i2c_stick_get_drv_name_by_drv(uint8_t drv) { switch(drv) { + case DRV_MLX90394_ID: + return DRV_MLX90394_NAME; case DRV_MLX90614_ID: return DRV_MLX90614_NAME; case DRV_MLX90632_ID: @@ -50,6 +57,7 @@ i2c_stick_get_drv_name_by_drv(uint8_t drv) uint8_t i2c_stick_get_drv_by_drv_name(const char *drv_name) { + if (!strcasecmp(drv_name, DRV_MLX90394_NAME)) return DRV_MLX90394_ID; if (!strcasecmp(drv_name, DRV_MLX90614_NAME)) return DRV_MLX90614_ID; if (!strcasecmp(drv_name, DRV_MLX90632_NAME)) return DRV_MLX90632_ID; if (!strcasecmp(drv_name, DRV_MLX90640_NAME)) return DRV_MLX90640_ID; @@ -58,6 +66,27 @@ i2c_stick_get_drv_by_drv_name(const char *drv_name) } +const char* +i2c_stick_get_app_name(uint8_t app_id) +{ + switch(app_id) + { + case APP_MLX90394_THUMBSTICK_ID: + return APP_MLX90394_THUMBSTICK_NAME; + default: + if (app_id) {} + } + return "Unassigned"; +} + + +uint8_t +i2c_stick_get_app_id(const char *app_name) +{ + if (!strcasecmp(app_name, APP_MLX90394_THUMBSTICK_NAME)) return APP_MLX90394_THUMBSTICK_ID; + return APP_NONE; +} + // command functions. @@ -72,6 +101,9 @@ cmd_mv(uint8_t sa, float *mv_list, uint16_t *mv_count, char const **error_messag switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_mv(sa, mv_list, mv_count, error_message); + break; case DRV_MLX90614_ID: cmd_90614_mv(sa, mv_list, mv_count, error_message); break; @@ -102,6 +134,9 @@ cmd_raw(uint8_t sa, uint16_t *raw_list, uint16_t *raw_count, char const **error_ switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_raw(sa, raw_list, raw_count, error_message); + break; case DRV_MLX90614_ID: cmd_90614_raw(sa, raw_list, raw_count, error_message); break; @@ -132,6 +167,9 @@ cmd_nd(uint8_t sa, uint8_t *nd, char const **error_message) switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_nd(sa, nd, error_message); + break; case DRV_MLX90614_ID: cmd_90614_nd(sa, nd, error_message); break; @@ -162,6 +200,9 @@ cmd_sn(uint8_t sa, uint16_t *sn_list, uint16_t *sn_count, char const **error_mes switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_sn(sa, sn_list, sn_count, error_message); + break; case DRV_MLX90614_ID: cmd_90614_sn(sa, sn_list, sn_count, error_message); break; @@ -203,6 +244,9 @@ cmd_cs(uint8_t sa, uint8_t channel_mask, const char *input) switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_cs(sa, channel_mask, input); + break; case DRV_MLX90614_ID: cmd_90614_cs(sa, channel_mask, input); break; @@ -266,6 +310,9 @@ cmd_cs_write(uint8_t sa, uint8_t channel_mask, const char *input) switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_cs_write(sa, channel_mask, input); + break; case DRV_MLX90614_ID: cmd_90614_cs_write(sa, channel_mask, input); break; @@ -296,6 +343,9 @@ cmd_mr(uint8_t sa, uint16_t *mem_list, uint16_t mem_start_address, uint16_t mem_ switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_mr(sa, mem_list, mem_start_address, mem_count, bit_per_address, address_increments, error_message); + break; case DRV_MLX90614_ID: cmd_90614_mr(sa, mem_list, mem_start_address, mem_count, bit_per_address, address_increments, error_message); break; @@ -327,6 +377,9 @@ cmd_mw(uint8_t sa, uint16_t *mem_list, uint16_t mem_start_address, uint16_t mem_ switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_mw(sa, mem_list, mem_start_address, mem_count, bit_per_address, address_increments, error_message); + break; case DRV_MLX90614_ID: cmd_90614_mw(sa, mem_list, mem_start_address, mem_count, bit_per_address, address_increments, error_message); break; @@ -358,6 +411,9 @@ cmd_is(uint8_t sa, uint8_t drv, uint8_t *is_ok, char const **error_message) switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_is(sa, is_ok, error_message); + break; case DRV_MLX90614_ID: cmd_90614_is(sa, is_ok, error_message); break; @@ -398,6 +454,9 @@ cmd_tear_down(uint8_t sa) switch(drv) { + case DRV_MLX90394_ID: + cmd_90394_tear_down(sa); + break; case DRV_MLX90614_ID: cmd_90614_tear_down(sa); break; @@ -414,4 +473,127 @@ cmd_tear_down(uint8_t sa) return 0; } return drv; -} \ No newline at end of file +} + + +uint8_t +cmd_la(uint8_t channel_mask) +{ + uint8_t count = 0; + char buf[16]; memset(buf, 0, sizeof(buf)); + send_answer_chunk(channel_mask, "la:", 0); + itoa(APP_MLX90394_THUMBSTICK_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":" APP_MLX90394_THUMBSTICK_NAME, 1); + count++; + + if (count == 0) + { + send_answer_chunk(channel_mask, "la:FAILED (no applications registered)", 1); + } + + return count; +} + + +uint8_t +cmd_app_begin(uint8_t app_id, uint8_t channel_mask) +{ + char buf[32]; + switch(app_id) + { + case APP_NONE: + send_answer_chunk(channel_mask, ":", 0); + itoa(APP_NONE, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":OK", 1); + break; + case APP_MLX90394_THUMBSTICK_ID: + return cmd_90394_thumbstick_app_begin(channel_mask); + default: + send_answer_chunk(channel_mask, ":", 0); + itoa(app_id, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAILED (no registered app id)", 1); + break; + } + return APP_NONE; +} + + +uint8_t +cmd_app_end(uint8_t channel_mask) +{ + switch(g_app_id) + { + case APP_NONE: + break; + case APP_MLX90394_THUMBSTICK_ID: + cmd_90394_thumbstick_app_end(channel_mask); + g_app_id = APP_NONE; + break; + default: + break; + } + return APP_NONE; +} + + +void +handle_applications(uint8_t channel_mask) +{ + switch(g_app_id) + { + case APP_NONE: + break; + case APP_MLX90394_THUMBSTICK_ID: + handle_90394_thumbstick_app(channel_mask); + break; + default: + break; + } +} + + +uint8_t +cmd_ca(uint8_t app_id, uint8_t channel_mask, const char *input) +{ + char buf[16]; memset(buf, 0, sizeof(buf)); + switch(app_id) + { + case APP_NONE: + send_answer_chunk(channel_mask, "ca:", 0); + itoa(APP_NONE, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":none", 1); + break; + case APP_MLX90394_THUMBSTICK_ID: + cmd_90394_thumbstick_ca(channel_mask, input); + break; + default: + send_answer_chunk(channel_mask, "ca:", 0); + itoa(app_id, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAILED (unregistered app id)", 1); + return APP_NONE; + } + return app_id; +} + + +uint8_t +cmd_ca_write(uint8_t app_id, uint8_t channel_mask, const char *input) +{ + // 1. all is specific for each application + switch(app_id) + { + case APP_NONE: + break; + case APP_MLX90394_THUMBSTICK_ID: + cmd_90394_thumbstick_ca_write(channel_mask, input); + break; + default: + return 0; + } + return app_id; +} diff --git a/i2c-stick-arduino/i2c_stick_dispatcher.cpp.jinja2 b/i2c-stick-arduino/i2c_stick_dispatcher.cpp.jinja2 index fd54505..76f46cb 100644 --- a/i2c-stick-arduino/i2c_stick_dispatcher.cpp.jinja2 +++ b/i2c-stick-arduino/i2c_stick_dispatcher.cpp.jinja2 @@ -11,6 +11,11 @@ #include "{{driver.src_name}}_cmd.h" {%- endfor %} +// Include all the applications header files: +{%- for app in applications %} +#include "{{app.src_name}}_app.h" +{%- endfor %} + #include #include @@ -51,6 +56,31 @@ i2c_stick_get_drv_by_drv_name(const char *drv_name) } +const char* +i2c_stick_get_app_name(uint8_t app_id) +{ + switch(app_id) + { +{%- for app in applications %} + case APP_{{app.name}}_ID: + return APP_{{app.name}}_NAME; +{%- endfor %} + default: + if (app_id) {} + } + return "Unassigned"; +} + + +uint8_t +i2c_stick_get_app_id(const char *app_name) +{ +{%- for app in applications %} + if (!strcasecmp(app_name, APP_{{app.name}}_NAME)) return APP_{{app.name}}_ID; +{%- endfor %} + return APP_NONE; +} + // command functions. @@ -338,3 +368,140 @@ cmd_tear_down(uint8_t sa) } return drv; } + + +uint8_t +cmd_la(uint8_t channel_mask) +{ + uint8_t count = 0; + char buf[16]; memset(buf, 0, sizeof(buf)); + +{%- for app in applications %} + send_answer_chunk(channel_mask, "la:", 0); + itoa(APP_{{app.name}}_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":" APP_{{app.name}}_NAME, 1); + count++; +{%- endfor %} + + if (count == 0) + { + send_answer_chunk(channel_mask, "la:FAILED (no applications registered)", 1); + } + + return count; +} + + +uint8_t +cmd_app_begin(uint8_t app_id, uint8_t channel_mask) +{ + char buf[32]; + switch(app_id) + { + case APP_NONE: + send_answer_chunk(channel_mask, ":", 0); + itoa(APP_NONE, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":OK", 1); + break; +{%- for app in applications %} + case APP_{{app.name}}_ID: + return cmd_{{app.function_id}}_app_begin(channel_mask); +{%- endfor %} + default: + send_answer_chunk(channel_mask, ":", 0); + itoa(app_id, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAILED (no registered app id)", 1); + break; + } + return APP_NONE; +} + + +uint8_t +cmd_app_end(uint8_t channel_mask) +{ + switch(g_app_id) + { + case APP_NONE: + break; +{%- for app in applications %} + case APP_{{app.name}}_ID: + cmd_{{app.function_id}}_app_end(channel_mask); + g_app_id = APP_NONE; + break; +{%- endfor %} + default: + break; + } + return APP_NONE; +} + + +void +handle_applications(uint8_t channel_mask) +{ + switch(g_app_id) + { + case APP_NONE: + break; +{%- for app in applications %} + case APP_{{app.name}}_ID: + handle_{{app.function_id}}_app(channel_mask); + break; +{%- endfor %} + default: + break; + } +} + + +uint8_t +cmd_ca(uint8_t app_id, uint8_t channel_mask, const char *input) +{ + char buf[16]; memset(buf, 0, sizeof(buf)); + switch(app_id) + { + case APP_NONE: + send_answer_chunk(channel_mask, "ca:", 0); + itoa(APP_NONE, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":none", 1); + break; +{%- for app in applications %} + case APP_{{app.name}}_ID: + cmd_{{app.function_id}}_ca(channel_mask, input); + break; +{%- endfor %} + default: + send_answer_chunk(channel_mask, "ca:", 0); + itoa(app_id, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAILED (unregistered app id)", 1); + return APP_NONE; + } + return app_id; +} + + +uint8_t +cmd_ca_write(uint8_t app_id, uint8_t channel_mask, const char *input) +{ + // 1. all is specific for each application + switch(app_id) + { + case APP_NONE: + break; +{%- for app in applications %} + case APP_{{app.name}}_ID: + cmd_{{app.function_id}}_ca_write(channel_mask, input); + break; +{%- endfor %} + default: + return 0; + } + return app_id; +} + diff --git a/i2c-stick-arduino/i2c_stick_dispatcher.h b/i2c-stick-arduino/i2c_stick_dispatcher.h index 18f8dfb..a4880c3 100644 --- a/i2c-stick-arduino/i2c_stick_dispatcher.h +++ b/i2c-stick-arduino/i2c_stick_dispatcher.h @@ -12,18 +12,28 @@ extern "C" { #endif // driver declarations: -#define DRV_MLX90614_ID 1 +#define DRV_MLX90394_ID 1 +#define DRV_MLX90394_NAME "MLX90394" +#define DRV_MLX90614_ID 2 #define DRV_MLX90614_NAME "MLX90614" -#define DRV_MLX90632_ID 2 +#define DRV_MLX90632_ID 3 #define DRV_MLX90632_NAME "MLX90632" -#define DRV_MLX90640_ID 3 +#define DRV_MLX90640_ID 4 #define DRV_MLX90640_NAME "MLX90640" -#define DRV_MLX90641_ID 4 +#define DRV_MLX90641_ID 5 #define DRV_MLX90641_NAME "MLX90641" +// applications declarations: +#define APP_MLX90394_THUMBSTICK_ID 1 +#define APP_MLX90394_THUMBSTICK_NAME "MLX90394_THUMBSTICK" + int16_t i2c_stick_register_all_drivers(); const char* i2c_stick_get_drv_name_by_drv(uint8_t drv); uint8_t i2c_stick_get_drv_by_drv_name(const char *drv_name); +const char* i2c_stick_get_app_name(uint8_t drv); +uint8_t i2c_stick_get_app_id(const char *drv_name); + +void handle_applications(uint8_t channel_mask); uint8_t cmd_mv(uint8_t sa, float *mv_list, uint16_t *mv_count, char const **error_message); uint8_t cmd_raw(uint8_t sa, uint16_t *raw_list, uint16_t *raw_count, char const **error_message); @@ -33,6 +43,11 @@ uint8_t cmd_cs(uint8_t sa, uint8_t channel_mask, const char *input); uint8_t cmd_cs_write(uint8_t sa, uint8_t channel_mask, const char *input); uint8_t cmd_mr(uint8_t sa, uint16_t *mem_list, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message); uint8_t cmd_mw(uint8_t sa, uint16_t *mem_list, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message); +uint8_t cmd_la(uint8_t channel_mask); +uint8_t cmd_app_begin(uint8_t app_id, uint8_t channel_mask); +uint8_t cmd_app_end(uint8_t channel_mask); +uint8_t cmd_ca(uint8_t app_id, uint8_t channel_mask, const char *input); +uint8_t cmd_ca_write(uint8_t app_id, uint8_t channel_mask, const char *input); uint8_t cmd_is(uint8_t sa, uint8_t drv, uint8_t *is_ok, char const **error_message); uint8_t cmd_tear_down(uint8_t sa); diff --git a/i2c-stick-arduino/i2c_stick_dispatcher.h.jinja2 b/i2c-stick-arduino/i2c_stick_dispatcher.h.jinja2 index eb17967..ac89beb 100644 --- a/i2c-stick-arduino/i2c_stick_dispatcher.h.jinja2 +++ b/i2c-stick-arduino/i2c_stick_dispatcher.h.jinja2 @@ -17,9 +17,19 @@ extern "C" { #define DRV_{{driver.name}}_NAME "{{driver.name}}" {%- endfor %} +// applications declarations: +{%- for app in applications %} +#define APP_{{app.name}}_ID {{app.id}} +#define APP_{{app.name}}_NAME "{{app.name}}" +{%- endfor %} + int16_t i2c_stick_register_all_drivers(); const char* i2c_stick_get_drv_name_by_drv(uint8_t drv); uint8_t i2c_stick_get_drv_by_drv_name(const char *drv_name); +const char* i2c_stick_get_app_name(uint8_t drv); +uint8_t i2c_stick_get_app_id(const char *drv_name); + +void handle_applications(uint8_t channel_mask); uint8_t cmd_mv(uint8_t sa, float *mv_list, uint16_t *mv_count, char const **error_message); uint8_t cmd_raw(uint8_t sa, uint16_t *raw_list, uint16_t *raw_count, char const **error_message); @@ -29,6 +39,11 @@ uint8_t cmd_cs(uint8_t sa, uint8_t channel_mask, const char *input); uint8_t cmd_cs_write(uint8_t sa, uint8_t channel_mask, const char *input); uint8_t cmd_mr(uint8_t sa, uint16_t *mem_list, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message); uint8_t cmd_mw(uint8_t sa, uint16_t *mem_list, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message); +uint8_t cmd_la(uint8_t channel_mask); +uint8_t cmd_app_begin(uint8_t app_id, uint8_t channel_mask); +uint8_t cmd_app_end(uint8_t channel_mask); +uint8_t cmd_ca(uint8_t app_id, uint8_t channel_mask, const char *input); +uint8_t cmd_ca_write(uint8_t app_id, uint8_t channel_mask, const char *input); uint8_t cmd_is(uint8_t sa, uint8_t drv, uint8_t *is_ok, char const **error_message); uint8_t cmd_tear_down(uint8_t sa); diff --git a/i2c-stick-arduino/i2c_stick_fw_config.h b/i2c-stick-arduino/i2c_stick_fw_config.h index 28fa8f5..134ba6b 100644 --- a/i2c-stick-arduino/i2c_stick_fw_config.h +++ b/i2c-stick-arduino/i2c_stick_fw_config.h @@ -4,7 +4,7 @@ // FW Configuration // **************** -#define FW_VERSION "V1.4.0" +#define FW_VERSION "V1.3.15" // enable/disable modules diff --git a/i2c-stick-arduino/i2c_stick_hal.h b/i2c-stick-arduino/i2c_stick_hal.h index aa774df..8e3d7fb 100644 --- a/i2c-stick-arduino/i2c_stick_hal.h +++ b/i2c-stick-arduino/i2c_stick_hal.h @@ -20,7 +20,7 @@ int16_t hal_i2c_direct_write(uint8_t sa, uint8_t *write_buffer, uint16_t write_n int16_t hal_i2c_indirect_read(uint8_t sa, uint8_t *write_buffer, uint16_t write_n_bytes, uint8_t *read_buffer, uint16_t read_n_bytes); void hal_write_pin(uint8_t pin, uint8_t state); -uint8_t hal_read_pin(uint8_t pin, uint8_t pullup = false); +uint8_t hal_read_pin(uint8_t pin); void hal_i2c_set_pwm(uint8_t pin_no, uint8_t pwm); diff --git a/i2c-stick-arduino/i2c_stick_task.cpp b/i2c-stick-arduino/i2c_stick_task.cpp index 30d93ee..e729d05 100644 --- a/i2c-stick-arduino/i2c_stick_task.cpp +++ b/i2c-stick-arduino/i2c_stick_task.cpp @@ -160,6 +160,7 @@ handle_task_help(uint8_t channel_mask) send_answer_chunk(channel_mask, "- mw ==> Memory Write", 1); send_answer_chunk(channel_mask, "- raw ==> RAW sensor data dump", 1); send_answer_chunk(channel_mask, "", 1); + send_answer_chunk(channel_mask, "- la ==> List Applications", 1); send_answer_chunk(channel_mask, "- app ==> APPlication id", 1); send_answer_chunk(channel_mask, "- ca ==> Configuration of Application", 1); send_answer_chunk(channel_mask, "", 1); diff --git a/i2c-stick-arduino/mlx90394_api.cpp b/i2c-stick-arduino/mlx90394_api.cpp new file mode 100644 index 0000000..9d58d46 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_api.cpp @@ -0,0 +1,154 @@ +#include "mlx90394_api.h" +#include "mlx90394_hal.h" +#include // this is here only to debug for "Serial" object... please remove this include! + + +int +mlx90394_init(uint8_t sa) +{ + return 0; +} + + +int +mlx90394_write_measurement_mode(uint8_t sa, uint8_t mode) +{ + uint16_t data = 0; + int result = mlx90394_i2c_addressed_read(sa, MLX90394_CTRL1, &data, 1); + if (result != 0) + { + return -1; + } + + data &= 0x00F0; + data |= (mode & 0x000F); + return mlx90394_i2c_addressed_write(sa, MLX90394_CTRL1, data); +} + + +int +mlx90394_trigger_measurement(uint8_t sa) +{ + return mlx90394_write_measurement_mode(sa, MLX90394_MODE_SINGLE); +} + + +int +mlx90394_read_data_ready_bit(uint8_t sa) +{ + uint16_t data = 0; + int result = mlx90394_i2c_addressed_read(sa, MLX90394_STAT1, &data, 1); + if (result != 0) + { + return -1; + } + if (data & MLX90394_STAT1_MASK_DRDY) + { + return 1; + } + return 0; +} + + +int +mlx90394_read_xyzt(uint8_t sa, int16_t *x, int16_t *y, int16_t *z, int16_t *t) +{ + uint16_t data[10]; + int result = mlx90394_i2c_addressed_read(sa, 0x00, data, 10); + + if (result != 0) + { + return -1; + } + *x = data[0x01] | (data[0x02] << 8); + *y = data[0x03] | (data[0x04] << 8); + *z = data[0x05] | (data[0x06] << 8); + *t = data[0x08] | (data[0x09] << 8); + return 0; +} + + +int +mlx90394_measure_xyzt(uint8_t sa, int16_t *x, int16_t *y, int16_t *z, int16_t *t, int16_t timeout_us) +{ + return -1; +} + +int +mlx90394_write_EN_X(uint8_t sa, uint8_t enable) +{ + uint16_t data = 0; + int result = mlx90394_i2c_addressed_read(sa, MLX90394_CTRL1, &data, 1); + if (result != 0) + { + return -1; + } + + data &= ~MLX90394_CTRL1_MASK_EN_X; + if (enable) + { + data |= MLX90394_CTRL1_MASK_EN_X; + } + result = mlx90394_i2c_addressed_write(sa, MLX90394_CTRL1, data); + return result; +} + + +int +mlx90394_write_EN_Y(uint8_t sa, uint8_t enable) +{ + uint16_t data = 0; + int result = mlx90394_i2c_addressed_read(sa, MLX90394_CTRL1, &data, 1); + if (result != 0) + { + return -1; + } + + data &= ~MLX90394_CTRL1_MASK_EN_Y; + if (enable) + { + data |= MLX90394_CTRL1_MASK_EN_Y; + } + result = mlx90394_i2c_addressed_write(sa, MLX90394_CTRL1, data); + return result; +} + + +int +mlx90394_write_EN_Z(uint8_t sa, uint8_t enable) +{ + uint16_t data = 0; + int result = mlx90394_i2c_addressed_read(sa, MLX90394_CTRL1, &data, 1); + if (result != 0) + { + return -1; + } + + data &= ~MLX90394_CTRL1_MASK_EN_Z; + if (enable) + { + data |= MLX90394_CTRL1_MASK_EN_Z; + } + result = mlx90394_i2c_addressed_write(sa, MLX90394_CTRL1, data); + return result; +} + + +int +mlx90394_write_EN_T(uint8_t sa, uint8_t enable) +{ + uint16_t data = 0; + int result = mlx90394_i2c_addressed_read(sa, MLX90394_CTRL4, &data, 1); + if (result != 0) + { + return -1; + } + + data &= ~MLX90394_CTRL4_MASK_EN_T; + if (enable) + { + data |= MLX90394_CTRL4_MASK_EN_T; + } + result = mlx90394_i2c_addressed_write(sa, MLX90394_CTRL4, data); + return result; +} diff --git a/i2c-stick-arduino/mlx90394_api.h b/i2c-stick-arduino/mlx90394_api.h new file mode 100644 index 0000000..402aa06 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_api.h @@ -0,0 +1,66 @@ +#ifndef __MLX90394_API__ +#define __MLX90394_API__ + +//#ifdef __cplusplus +//extern "C" { +//#endif + +#include + +#define MLX90394_STAT1 0x00 +#define MLX90394_STAT2 0x07 +#define MLX90394_COMPANY_ID 0x0A +#define MLX90394_DEVICE_ID 0x0B +#define MLX90394_CTRL1 0x0E +#define MLX90394_CTRL2 0x0F +#define MLX90394_RESET 0x11 +#define MLX90394_CTRL3 0x14 +#define MLX90394_CTRL4 0x15 + +#define MLX90394_WOC_X 0x58 +#define MLX90394_WOC_Y 0x5A +#define MLX90394_WOC_Z 0x5C + +#define MLX90394_CTRL4_MASK_EN_T (1U<<5) +#define MLX90394_CTRL1_MASK_EN_X (1U<<4) +#define MLX90394_CTRL1_MASK_EN_Y (1U<<5) +#define MLX90394_CTRL1_MASK_EN_Z (1U<<6) + +#define MLX90394_STAT1_MASK_DRDY (1U<<0) + + +#define MLX90394_MODE_POWER_DOWN 0 +#define MLX90394_MODE_SINGLE 1 +#define MLX90394_MODE_5Hz 2 +#define MLX90394_MODE_10Hz 3 +#define MLX90394_MODE_15Hz 4 +#define MLX90394_MODE_50Hz 5 +#define MLX90394_MODE_100Hz 6 +#define MLX90394_MODE_SELF_TEST 7 +#define MLX90394_MODE_POWER_DOWN2 8 +#define MLX90394_MODE_SINGLE2 9 +#define MLX90394_MODE_200Hz 10 +#define MLX90394_MODE_500Hz 11 +#define MLX90394_MODE_700Hz 12 +#define MLX90394_MODE_1000Hz 13 +#define MLX90394_MODE_1400Hz 14 +#define MLX90394_MODE_POWER_DOWN3 15 + + +int mlx90394_init(uint8_t sa); +int mlx90394_write_measurement_mode(uint8_t sa, uint8_t mode); +int mlx90394_trigger_measurement(uint8_t sa); +int mlx90394_read_data_ready_bit(uint8_t sa); +int mlx90394_read_xyzt(uint8_t sa, int16_t *x, int16_t *y, int16_t *z, int16_t *t); +int mlx90394_measure_xyzt(uint8_t sa, int16_t *x, int16_t *y, int16_t *z, int16_t *t, int16_t timeout_us = -1); +int mlx90394_write_EN_X(uint8_t sa, uint8_t enable = 1); +int mlx90394_write_EN_Y(uint8_t sa, uint8_t enable = 1); +int mlx90394_write_EN_Z(uint8_t sa, uint8_t enable = 1); +int mlx90394_write_EN_T(uint8_t sa, uint8_t enable = 1); + +//#ifdef __cplusplus +//} +//#endif + + +#endif // __MLX90394_API__ diff --git a/i2c-stick-arduino/mlx90394_cmd.cpp b/i2c-stick-arduino/mlx90394_cmd.cpp new file mode 100644 index 0000000..203f1c7 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_cmd.cpp @@ -0,0 +1,771 @@ +#include "mlx90394_cmd.h" +#include "i2c_stick.h" +#include "i2c_stick_cmd.h" +#include "i2c_stick_dispatcher.h" +#include "i2c_stick_hal.h" +#include "mlx90394_hal.h" +#include "mlx90394_api.h" + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef MAX_MLX90394_SLAVES +#define MAX_MLX90394_SLAVES 8 +#endif // MAX_MLX90394_SLAVES + +#define MLX90394_ERROR_BUFFER_TOO_SMALL "Buffer too small" +#define MLX90394_ERROR_COMMUNICATION "Communication error" +#define MLX90394_ERROR_NO_FREE_HANDLE "No free handle; pls recompile firmware with higher 'MAX_MLX90394_SLAVES'" +#define MLX90394_ERROR_OUT_OF_RANGE "Out of range" + + +static MLX90394_t *g_mlx90394_list[MAX_MLX90394_SLAVES]; + + +MLX90394_t * +cmd_90394_get_handle(uint8_t sa) +{ + if (sa >= 128) + { + return NULL; + } + + for (uint8_t i=0; islave_address_ & 0x7F) == sa) + { // found! + return g_mlx90394_list[i]; + } + } + + // not found => try to find a handle with slave address zero (not yet initialized)! + for (uint8_t i=0; islave_address_ == 0) + { // found! + return g_mlx90394_list[i]; + } + } + + // not found => use first free spot! + uint8_t i=0; + for (; islave_address_ = 0x80 | sa; + return g_mlx90394_list[i]; + } + } + + return NULL; // no free spot available +} + + +static void +delete_handle(uint8_t sa) +{ + for (uint8_t i=0; islave_address_ & 0x7F) == sa) + { // found! + memset(g_mlx90394_list[i], 0, sizeof(MLX90394_t)); + free(g_mlx90394_list[i]); + g_mlx90394_list[i] = NULL; + } + } +} + + +int16_t +cmd_90394_register_driver() +{ + int16_t r = 0; + + r = i2c_stick_register_driver(0x60, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x61, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x10, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x11, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x68, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x69, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x6a, DRV_MLX90394_ID); + if (r < 0) return r; + + r = i2c_stick_register_driver(0x6b, DRV_MLX90394_ID); + if (r < 0) return r; + + return 1; +} + + +void +cmd_90394_init(uint8_t sa) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + return; + } + // init functions goes here + mlx90394_init(sa); + + mlx90394_write_measurement_mode(sa, MLX90394_MODE_100Hz); + mlx->mode_ = MLX90394_MODE_100Hz; + mlx90394_write_EN_X(sa); + mlx->enable_values_ |= 0x01; + mlx90394_write_EN_Y(sa); + mlx->enable_values_ |= 0x02; + mlx90394_write_EN_Z(sa); + mlx->enable_values_ |= 0x04; + mlx90394_write_EN_T(sa); + mlx->enable_values_ |= 0x08; + + // turn off bit7, to indicate other routines this slave has been init + mlx->slave_address_ &= 0x7F; +} + + +void +cmd_90394_tear_down(uint8_t sa) +{ // nothing special to do, just release all associated memory + delete_handle(sa); +} + + +void +cmd_90394_mv(uint8_t sa, float *mv_list, uint16_t *mv_count, char const **error_message) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + *mv_count = 0; + *error_message = MLX90394_ERROR_NO_FREE_HANDLE; + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + if (*mv_count < 4) // check Measurement Value buffer length + { + *mv_count = 0; + *error_message = MLX90394_ERROR_BUFFER_TOO_SMALL; + return; + } + *mv_count = 0; + + while (mlx90394_read_data_ready_bit(sa) == 0) + { + mlx90394_delay_us(100); + } + + int16_t x = 0; + int16_t y = 0; + int16_t z = 0; + int16_t t = 0; + int result = mlx90394_read_xyzt(sa, &x, &y, &z, &t); + if (result != 0) + { + *mv_count = 0; + *error_message = MLX90394_ERROR_COMMUNICATION; + return; + } + + uint8_t i = 0; + if (mlx->enable_values_ & 0x01) + { + mv_list[i] = x; + i++; + } + if (mlx->enable_values_ & 0x02) + { + mv_list[i] = y; + i++; + } + if (mlx->enable_values_ & 0x04) + { + mv_list[i] = z; + i++; + } + if (mlx->enable_values_ & 0x08) + { + mv_list[i] = t; + i++; + } + *mv_count = i; +} + + +void +cmd_90394_raw(uint8_t sa, uint16_t *raw_list, uint16_t *raw_count, char const **error_message) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + *raw_count = 0; + *error_message = MLX90394_ERROR_NO_FREE_HANDLE; + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + if (*raw_count < 4) // check Raw Value buffer length + { + *raw_count = 0; // input buffer not long enough, report nothing. + *error_message = MLX90394_ERROR_BUFFER_TOO_SMALL; + return; + } + *raw_count = 4; + + while (mlx90394_read_data_ready_bit(sa) == 0) + { + mlx90394_delay_us(100); + } + + int16_t x = 0; + int16_t y = 0; + int16_t z = 0; + int16_t t = 0; + int result = mlx90394_read_xyzt(sa, &x, &y, &z, &t); + if (result != 0) + { + *raw_count = 0; + *error_message = MLX90394_ERROR_COMMUNICATION; + return; + } + raw_list[0] = x; + raw_list[1] = y; + raw_list[2] = z; + raw_list[3] = t; +} + + +void +cmd_90394_nd(uint8_t sa, uint8_t *nd, char const **error_message) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + *nd = 0; + *error_message = MLX90394_ERROR_NO_FREE_HANDLE; + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + int result = mlx90394_read_data_ready_bit(sa); + if (result < 0) + { + *nd = 0; + *error_message = MLX90394_ERROR_COMMUNICATION; + return; + } + + *nd = 0; + if (result > 0) + { + *nd = 1; + return; + } +} + + +void +cmd_90394_sn(uint8_t sa, uint16_t *sn_list, uint16_t *sn_count, char const **error_message) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + *sn_count = 0; + *error_message = MLX90394_ERROR_NO_FREE_HANDLE; + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + if (*sn_count < 4) // check the Serial Number buffer length + { + *sn_count = 0; // input buffer not long enough, report nothing. + *error_message = MLX90394_ERROR_BUFFER_TOO_SMALL; + return; + } + *sn_count = 4; + + // todo: + // + // read the serial number from the sensor. + // +} + + +void +cmd_90394_cs(uint8_t sa, uint8_t channel_mask, const char *input) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + // todo: + // + // read the CS(Configuration of the Slave) from the sensor. + // + + char buf[16]; memset(buf, 0, sizeof(buf)); + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":MODE=", 0); + itoa(mlx->mode_, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + const char *p = "(Unknown)"; + if (mlx->mode_ == MLX90394_MODE_POWER_DOWN ) p = "(POWER_DOWN)"; + if (mlx->mode_ == MLX90394_MODE_SINGLE ) p = "(SINGLE)"; + if (mlx->mode_ == MLX90394_MODE_5Hz ) p = "(5Hz)"; + if (mlx->mode_ == MLX90394_MODE_10Hz ) p = "(10Hz)"; + if (mlx->mode_ == MLX90394_MODE_15Hz ) p = "(15Hz)"; + if (mlx->mode_ == MLX90394_MODE_50Hz ) p = "(50Hz)"; + if (mlx->mode_ == MLX90394_MODE_100Hz ) p = "(100Hz)"; + if (mlx->mode_ == MLX90394_MODE_SELF_TEST ) p = "(SELF_TEST)"; + if (mlx->mode_ == MLX90394_MODE_POWER_DOWN2) p = "(POWER_DOWN)"; + if (mlx->mode_ == MLX90394_MODE_SINGLE2 ) p = "(SINGLE)"; + if (mlx->mode_ == MLX90394_MODE_200Hz ) p = "(200Hz)"; + if (mlx->mode_ == MLX90394_MODE_500Hz ) p = "(500Hz)"; + if (mlx->mode_ == MLX90394_MODE_700Hz ) p = "(700Hz)"; + if (mlx->mode_ == MLX90394_MODE_1000Hz ) p = "(1000Hz)"; + if (mlx->mode_ == MLX90394_MODE_1400Hz ) p = "(1400Hz)"; + if (mlx->mode_ == MLX90394_MODE_POWER_DOWN3) p = "(POWER_DOWN)"; + send_answer_chunk(channel_mask, p, 1); + + + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":EN_X=", 0); + itoa((mlx->enable_values_ & 0x01) ? 1 : 0, buf, 10); + send_answer_chunk(channel_mask, buf, 1); + + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":EN_Y=", 0); + itoa((mlx->enable_values_ & 0x02) ? 1 : 0, buf, 10); + send_answer_chunk(channel_mask, buf, 1); + + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":EN_Z=", 0); + itoa((mlx->enable_values_ & 0x04) ? 1 : 0, buf, 10); + send_answer_chunk(channel_mask, buf, 1); + + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":EN_T=", 0); + itoa((mlx->enable_values_ & 0x08) ? 1 : 0, buf, 10); + send_answer_chunk(channel_mask, buf, 1); + + // todo: + // + // Send the configuration of the MV header, unit and resolution back to the terminal(not to sensor!) + // + + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":RO:MV_HEADER=", 0); + uint8_t value_count = 0; + if (mlx->enable_values_ & 0x01) + { + send_answer_chunk(channel_mask, "X", 0); + value_count++; + } + if (mlx->enable_values_ & 0x02) + { + if (value_count > 0) + { + send_answer_chunk(channel_mask, ",", 0); + } + send_answer_chunk(channel_mask, "Y", 0); + value_count++; + } + if (mlx->enable_values_ & 0x04) + { + if (value_count > 0) + { + send_answer_chunk(channel_mask, ",", 0); + } + send_answer_chunk(channel_mask, "Z", 0); + value_count++; + } + if (mlx->enable_values_ & 0x08) + { + if (value_count > 0) + { + send_answer_chunk(channel_mask, ",", 0); + } + send_answer_chunk(channel_mask, "T", 0); + value_count++; + } + send_answer_chunk(channel_mask, "", 1); + + send_answer_chunk(channel_mask, "cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":RO:MV_UNIT=", 0); + for (uint8_t i=0; islave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + + // + // todo: + // + // write the configuration of the slave to the sensor and report to the channel the status. + // + // Please get inspired from other drivers like MLX90614. + // + // Also if SA can be re-programmed, please add the correct sequence here, see also MLX90614 or MLX90632 for an extensive example. + // + + const char *var_name = "MODE="; + if (!strncmp(var_name, input, strlen(var_name))) + { + const char *v = input+strlen(var_name); + int16_t mode = -1; + if (!strcmp(v, "POWER_DOWN")) mode = MLX90394_MODE_POWER_DOWN; + if (!strcmp(v, "SINGLE")) mode = MLX90394_MODE_SINGLE; + if (!strcmp(v, "5Hz")) mode = MLX90394_MODE_5Hz; + if (!strcmp(v, "10Hz")) mode = MLX90394_MODE_10Hz; + if (!strcmp(v, "15Hz")) mode = MLX90394_MODE_15Hz; + if (!strcmp(v, "50Hz")) mode = MLX90394_MODE_50Hz; + if (!strcmp(v, "100Hz")) mode = MLX90394_MODE_100Hz; + if (!strcmp(v, "SELF_TEST")) mode = MLX90394_MODE_SELF_TEST; + if (!strcmp(v, "200Hz")) mode = MLX90394_MODE_200Hz; + if (!strcmp(v, "500Hz")) mode = MLX90394_MODE_500Hz; + if (!strcmp(v, "700Hz")) mode = MLX90394_MODE_700Hz; + if (!strcmp(v, "1000Hz")) mode = MLX90394_MODE_1000Hz; + if (!strcmp(v, "1400Hz")) mode = MLX90394_MODE_1400Hz; + if (mode < 0) + { + mode = atoi(v); + } + send_answer_chunk(channel_mask, "+cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + if ((mode >= 0) && (mode <= 15)) + { + mlx->mode_ = mode; + mlx90394_write_measurement_mode(sa, mode); + send_answer_chunk(channel_mask, ":MODE=OK [mlx-IO]", 1); + } else + { + send_answer_chunk(channel_mask, ":MODE=FAIL; outbound", 1); + } + return; + } + + var_name = "EN_X="; + if (!strncmp(var_name, input, strlen(var_name))) + { + const char *v = input+strlen(var_name); + int16_t en = atoi(v); + send_answer_chunk(channel_mask, "+cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + if ((en >= 0) && (en <= 1)) + { + mlx->enable_values_ &= ~0x01; + if (en) + { + mlx->enable_values_ |= 0x01; + } + mlx90394_write_EN_X(sa); + send_answer_chunk(channel_mask, ":EN_X=OK [mlx-IO]", 1); + } else + { + send_answer_chunk(channel_mask, ":EN_X=FAIL; outbound", 1); + } + return; + } + + var_name = "EN_Y="; + if (!strncmp(var_name, input, strlen(var_name))) + { + const char *v = input+strlen(var_name); + int16_t en = atoi(v); + send_answer_chunk(channel_mask, "+cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + if ((en >= 0) && (en <= 1)) + { + mlx->enable_values_ &= ~0x02; + if (en) + { + mlx->enable_values_ |= 0x02; + } + mlx90394_write_EN_Y(sa); + send_answer_chunk(channel_mask, ":EN_Y=OK [mlx-IO]", 1); + } else + { + send_answer_chunk(channel_mask, ":EN_Y=FAIL; outbound", 1); + } + return; + } + + var_name = "EN_Z="; + if (!strncmp(var_name, input, strlen(var_name))) + { + const char *v = input+strlen(var_name); + int16_t en = atoi(v); + send_answer_chunk(channel_mask, "+cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + if ((en >= 0) && (en <= 1)) + { + mlx->enable_values_ &= ~0x04; + if (en) + { + mlx->enable_values_ |= 0x04; + } + mlx90394_write_EN_Z(sa); + send_answer_chunk(channel_mask, ":EN_Z=OK [mlx-IO]", 1); + } else + { + send_answer_chunk(channel_mask, ":EN_Z=FAIL; outbound", 1); + } + return; + } + + var_name = "EN_T="; + if (!strncmp(var_name, input, strlen(var_name))) + { + const char *v = input+strlen(var_name); + int16_t en = atoi(v); + send_answer_chunk(channel_mask, "+cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + if ((en >= 0) && (en <= 1)) + { + mlx->enable_values_ &= ~0x08; + if (en) + { + mlx->enable_values_ |= 0x08; + } + mlx90394_write_EN_T(sa); + send_answer_chunk(channel_mask, ":EN_T=OK [mlx-IO]", 1); + } else + { + send_answer_chunk(channel_mask, ":EN_T=FAIL; outbound", 1); + } + return; + } + + // finally we have a catch all to inform the user that they asked something unknown. + send_answer_chunk(channel_mask, "+cs:", 0); + uint8_to_hex(buf, sa); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAIL; unknown variable", 1); +} + + +void +cmd_90394_mr(uint8_t sa, uint16_t *mem_data, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + *bit_per_address = 0; + *address_increments = 0; + *error_message = MLX90394_ERROR_NO_FREE_HANDLE; + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + // indicate 8 bit at each single address: + *bit_per_address = 8; + *address_increments = 1; + + if ((mem_start_address + mem_count) > 0x00FF) + { + *bit_per_address = 0; + *address_increments = 0; + *error_message = MLX90394_ERROR_OUT_OF_RANGE; + return; + } + + int result = mlx90394_i2c_addressed_read(sa, mem_start_address, mem_data, mem_count); + if (result != 0) + { + *bit_per_address = 0; + *address_increments = 0; + *error_message = MLX90394_ERROR_COMMUNICATION; + return; + } +} + + +void +cmd_90394_mw(uint8_t sa, uint16_t *mem_data, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message) +{ + MLX90394_t *mlx = cmd_90394_get_handle(sa); + if (mlx == NULL) + { + *bit_per_address = 0; + *address_increments = 0; + *error_message = MLX90394_ERROR_NO_FREE_HANDLE; + return; + } + if (mlx->slave_address_ & 0x80) + { + cmd_90394_init(sa); + } + + *bit_per_address = 8; + *address_increments = 1; + + if ((mem_start_address + mem_count) > 0x00FF) + { + *bit_per_address = 0; + *address_increments = 0; + *error_message = MLX90394_ERROR_OUT_OF_RANGE; + return; + } + + for (uint16_t i=0; i slave address is actually a MLX90394! + // often times this can be done by reading some specific values from the ROM or EEPROM, + // and verify the values are as expected. + // + + // remember there is no communication initiated yet... + + mlx90394_i2c_init(); + + uint8_t device_id = 0x00; + uint8_t company_id = 0x00; + + mlx90394_i2c_addressed_read(sa, MLX90394_COMPANY_ID, &value, 1); + company_id = value; + mlx90394_i2c_addressed_read(sa, MLX90394_DEVICE_ID, &value, 1); + device_id = value; + + if (company_id != 0x94) + { + *error_message = MLX90394_ERROR_COMMUNICATION; + *is_ok = 0; + return; + } + if (device_id != 0xAA) + { + *error_message = MLX90394_ERROR_COMMUNICATION; + *is_ok = 0; + return; + } +} + + +#ifdef __cplusplus +} +#endif diff --git a/i2c-stick-arduino/mlx90394_cmd.h b/i2c-stick-arduino/mlx90394_cmd.h new file mode 100644 index 0000000..5fbff26 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_cmd.h @@ -0,0 +1,38 @@ +#ifndef _MLX90394_CMD_ +#define _MLX90394_CMD_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +struct MLX90394_t +{ + uint8_t slave_address_; + // local caching of sensor values whenever needed; + // stored along with , such that multiple sensors can be supported. + uint8_t enable_values_; + uint8_t mode_; +}; + + +int16_t cmd_90394_register_driver(); + +void cmd_90394_mv(uint8_t sa, float *mv_list, uint16_t *mv_count, char const **error_message); +void cmd_90394_raw(uint8_t sa, uint16_t *raw_list, uint16_t *raw_count, char const **error_message); +void cmd_90394_nd(uint8_t sa, uint8_t *nd, char const **error_message); +void cmd_90394_sn(uint8_t sa, uint16_t *sn_list, uint16_t *sn_count, char const **error_message); +void cmd_90394_cs(uint8_t sa, uint8_t channel_mask, const char *input); +void cmd_90394_cs_write(uint8_t sa, uint8_t channel_mask, const char *input); +void cmd_90394_mr(uint8_t sa, uint16_t *mem_data, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message); +void cmd_90394_mw(uint8_t sa, uint16_t *mem_data, uint16_t mem_start_address, uint16_t mem_count, uint8_t *bit_per_address, uint8_t *address_increments, char const **error_message); +void cmd_90394_is(uint8_t sa, uint8_t *is_ok, char const **error_message); + +void cmd_90394_tear_down(uint8_t sa); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/i2c-stick-arduino/mlx90394_driver.yaml b/i2c-stick-arduino/mlx90394_driver.yaml new file mode 100644 index 0000000..00e3596 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_driver.yaml @@ -0,0 +1,4 @@ +function_id: '90394' +name: MLX90394 +src_name: mlx90394 + diff --git a/i2c-stick-arduino/mlx90394_hal.h b/i2c-stick-arduino/mlx90394_hal.h new file mode 100644 index 0000000..7276348 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_hal.h @@ -0,0 +1,22 @@ +#ifndef __MLX90394_I2C_HAL__ +#define __MLX90394_I2C_HAL__ + +#include + +//#ifdef __cplusplus +//extern "C" { +//#endif + +void mlx90394_i2c_init(); +int mlx90394_i2c_direct_read(uint8_t sa, uint16_t *data, uint8_t count); +int mlx90394_i2c_addressed_read(uint8_t sa, uint8_t read_address, uint16_t *data, uint8_t count); +int mlx90394_i2c_addressed_write(uint8_t sa, uint8_t write_address, uint8_t data); +void mlx90394_i2c_set_clock_frequency(int freq); + +void mlx90394_delay_us(int32_t delay_us); + +//#ifdef __cplusplus +//} +//#endif + +#endif // __MLX90394_I2C_HAL__ diff --git a/i2c-stick-arduino/mlx90394_hal_arduino.cpp b/i2c-stick-arduino/mlx90394_hal_arduino.cpp new file mode 100644 index 0000000..d502fc6 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_hal_arduino.cpp @@ -0,0 +1,121 @@ +/** + * @copyright (C) 2024 Melexis N.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +#include + +#include "i2c_stick_arduino.h" +#include "mlx90394_hal.h" + + +void +mlx90394_i2c_init() +{ + WIRE.endTransmission(); +} + + +int +mlx90394_i2c_direct_read(uint8_t sa, uint16_t *data, uint8_t count) +{ + int ack = 0; + + WIRE.endTransmission(); + mlx90394_delay_us(5); + + WIRE.beginTransmission(sa); + ack = WIRE.requestFrom(sa, count, (uint8_t)(true)); + Serial.printf("request from ret: %d\n", ack); + for (uint8_t i=0; i +#include +#include +#include + + +static uint8_t g_sa = 0x00; +static uint8_t g_we_disabled_sa = 0; + + +uint8_t +cmd_90394_thumbstick_app_begin(uint8_t channel_mask) +{ +// configure the mlx09394 for the thumbstick app. + uint8_t ok = 1; + char buf[32]; + + // find out which SA is a MLX90394 + if (g_sa == 0x00) + { + for (uint8_t sa = 1; sa<128; sa++) + { + if (g_sa_list[sa].found_) + { + char buf[16]; memset(buf, 0, sizeof(buf)); + int16_t spot = g_sa_list[sa].spot_; + if (g_sa_drv_register[spot].drv_ == DRV_MLX90394_ID) + { + g_sa = sa; + break; + } + } + } + } + + if (g_sa == 0x00) ok = 0; + if (mlx90394_write_EN_X(g_sa) != 0) ok = 0; + if (mlx90394_write_EN_Y(g_sa) != 0) ok = 0; + if (mlx90394_write_EN_Z(g_sa) != 0) ok = 0; + if (mlx90394_write_EN_T(g_sa) != 0) ok = 0; + if (mlx90394_write_measurement_mode(g_sa, MLX90394_MODE_10Hz) != 0) ok = 0; + + if (ok) + { + send_answer_chunk(channel_mask, ":", 0); + itoa(APP_MLX90394_THUMBSTICK_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":OK", 1); + } + else // when failed.. + { + send_answer_chunk(channel_mask, ":", 0); + itoa(APP_MLX90394_THUMBSTICK_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":FAILED (app not started)", 1); + return APP_NONE; + } + + +// potentially disable the mlx90394 for emitting results in the continuous mode. + g_we_disabled_sa = g_sa; + + + return APP_MLX90394_THUMBSTICK_ID; +} + + +void +handle_90394_thumbstick_app(uint8_t channel_mask) +{ + static uint32_t prev_time = hal_get_millis(); + char buf[32]; memset(buf, 0, sizeof(buf)); + if (hal_get_millis() - prev_time > 100) + { + send_answer_chunk(channel_mask, "#", 0); + itoa(APP_MLX90394_THUMBSTICK_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + uint8_t ok = 1; + int16_t x = 0x7FFF; + int16_t y = 0x7FFF; + int16_t z = 0x7FFF; + int16_t t = 0x7FFF; + float heading = 0; + float deflect = 0; + if (mlx90394_read_xyzt(g_sa, &x, &y, &z, &t) != 0) ok = 0; + + // here is the app calculation magic! + if (z < 0) + { + x = -x; + y = -y; + z = -z; + } + heading = fmodf(atan2(x, y) + 2*M_PI, 2*M_PI)*180/M_PI; + deflect = atan2(sqrt(x*x + y*y), z)*180/M_PI; + + // report the result + send_answer_chunk(channel_mask, ":", 0); + uint8_to_hex(buf, g_sa); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ":", 0); + uint32_t time_stamp = hal_get_millis(); + uint32_to_dec(buf, time_stamp, 8); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ":", 0); + itoa(x, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ",", 0); + itoa(y, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ",", 0); + itoa(z, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ",", 0); + itoa(t, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ",", 0); + sprintf(buf, "%5.3f", heading); + send_answer_chunk(channel_mask, buf, 0); + + send_answer_chunk(channel_mask, ",", 0); + sprintf(buf, "%5.3f", deflect); + send_answer_chunk(channel_mask, buf, 1); + + prev_time = hal_get_millis(); + } + +} + + +uint8_t +cmd_90394_thumbstick_app_end(uint8_t channel_mask) +{ + char buf[32]; + send_answer_chunk(channel_mask, ":ENDING:", 0); + itoa(APP_MLX90394_THUMBSTICK_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + + // re-enable when we did the disable at begin + if (g_we_disabled_sa) + { + g_we_disabled_sa = 0; + } + return APP_NONE; +} + + +void +cmd_90394_thumbstick_ca(uint8_t channel_mask, const char *input) +{ + char buf[16]; memset(buf, 0, sizeof(buf)); + send_answer_chunk(channel_mask, "ca:", 0); + itoa(APP_MLX90394_THUMBSTICK_ID, buf, 10); + send_answer_chunk(channel_mask, buf, 0); + send_answer_chunk(channel_mask, ":SA=", 0); + uint8_to_hex(buf, g_sa); + send_answer_chunk(channel_mask, buf, 1); +} + + +void +cmd_90394_thumbstick_ca_write(uint8_t channel_mask, const char *input) +{ +} diff --git a/i2c-stick-arduino/mlx90394_thumbstick_app.h b/i2c-stick-arduino/mlx90394_thumbstick_app.h new file mode 100644 index 0000000..e811902 --- /dev/null +++ b/i2c-stick-arduino/mlx90394_thumbstick_app.h @@ -0,0 +1,20 @@ +#ifndef _MLX90394_THUMBSTICK_APP_ +#define _MLX90394_THUMBSTICK_APP_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +uint8_t cmd_90394_thumbstick_app_begin(uint8_t channel_mask); +void handle_90394_thumbstick_app(uint8_t channel_mask); +uint8_t cmd_90394_thumbstick_app_end(uint8_t channel_mask); +void cmd_90394_thumbstick_ca(uint8_t channel_mask, const char *input); +void cmd_90394_thumbstick_ca_write(uint8_t channel_mask, const char *input); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/i2c-stick-arduino/mlx90394_thumbstick_application.yaml b/i2c-stick-arduino/mlx90394_thumbstick_application.yaml new file mode 100644 index 0000000..9b48f9f --- /dev/null +++ b/i2c-stick-arduino/mlx90394_thumbstick_application.yaml @@ -0,0 +1,4 @@ +function_id: '90394_thumbstick' +name: MLX90394_THUMBSTICK +src_name: mlx90394_thumbstick +disable: 0 \ No newline at end of file diff --git a/i2c-stick-arduino/mlx90632_api.h b/i2c-stick-arduino/mlx90632_api.h index 148756c..4ce44ce 100644 --- a/i2c-stick-arduino/mlx90632_api.h +++ b/i2c-stick-arduino/mlx90632_api.h @@ -90,7 +90,7 @@ enum MLX90632_Reg_Mode MLX90632_REG_MODE_HALT, MLX90632_REG_MODE_SLEEPING_STEP, MLX90632_REG_MODE_STEP, - MLX90632_REG_MODE_CONTINIOUS, + MLX90632_REG_MODE_CONTINUOUS, }; diff --git a/i2c-stick-arduino/mlx90632_cmd.cpp b/i2c-stick-arduino/mlx90632_cmd.cpp index 3eeacc3..f00d578 100644 --- a/i2c-stick-arduino/mlx90632_cmd.cpp +++ b/i2c-stick-arduino/mlx90632_cmd.cpp @@ -266,7 +266,7 @@ cmd_90632_cs(uint8_t sa, uint8_t channel_mask, const char *input) if (mode == MLX90632_REG_MODE_HALT) p = "(HALT)"; if (mode == MLX90632_REG_MODE_SLEEPING_STEP) p = "(SLEEPING_STEP)"; if (mode == MLX90632_REG_MODE_STEP) p = "(STEP)"; - if (mode == MLX90632_REG_MODE_CONTINIOUS) p = "(CONTINIOUS)"; + if (mode == MLX90632_REG_MODE_CONTINUOUS) p = "(CONTINUOUS)"; send_answer_chunk(channel_mask, "cs:", 0); uint8_to_hex(buf, sa); diff --git a/i2c-stick-arduino/mlx90640_api.cpp b/i2c-stick-arduino/mlx90640_api.cpp index 210bab4..43ad560 100644 --- a/i2c-stick-arduino/mlx90640_api.cpp +++ b/i2c-stick-arduino/mlx90640_api.cpp @@ -18,6 +18,7 @@ #include "mlx90640_api.h" #include + static void ExtractVDDParameters(uint16_t *eeData, paramsMLX90640 *mlx90640); static void ExtractPTATParameters(uint16_t *eeData, paramsMLX90640 *mlx90640); static void ExtractGainParameters(uint16_t *eeData, paramsMLX90640 *mlx90640); diff --git a/i2c-stick-arduino/mlx90640_cmd.cpp b/i2c-stick-arduino/mlx90640_cmd.cpp index 712e0f0..4f23950 100644 --- a/i2c-stick-arduino/mlx90640_cmd.cpp +++ b/i2c-stick-arduino/mlx90640_cmd.cpp @@ -11,7 +11,6 @@ #include - #ifdef __cplusplus extern "C" { #endif @@ -274,6 +273,7 @@ cmd_90640_mv(uint8_t sa, float *mv_list, uint16_t *mv_count, char const **error_ { mv_list[pix+1] = mlx->to_list_[pix]; } + mlx->flags_ |= (1U<=1.3.1 +pyyaml-include>=1.3.1,<2.0 Jinja2>=3.1.2 PyYAML>=6.0.1 pyserial>=3.5 diff --git a/web-interface/index.jinja2.html b/web-interface/index.jinja2.html index f70f70d..0c538aa 100644 --- a/web-interface/index.jinja2.html +++ b/web-interface/index.jinja2.html @@ -113,6 +113,7 @@ @@ -132,6 +133,9 @@ Sent

+ Clear console +
console:
+
@@ -172,12 +176,12 @@
-
+
-
- Your browser does not support the HTML5 canvas tag. -
+
+ Your browser does not support the HTML5 canvas tag. +
@@ -195,15 +199,15 @@
@@ -273,6 +277,46 @@
+ +
+
+
+
+ Your browser does not support the HTML5 canvas tag. +
+
+ +
+
+ +
+ + + + +
+
+
+ diff --git a/web-interface/interface.js.jinja2 b/web-interface/interface.js.jinja2 index ead6786..c62a27a 100644 --- a/web-interface/interface.js.jinja2 +++ b/web-interface/interface.js.jinja2 @@ -39,6 +39,8 @@ var spatial_previous_orientation = 0; var connected_slaves = {}; var heat_map_gradient_colors = null; +var thumbstick_max_deflection = 2; + function set_terminal_height() { @@ -96,6 +98,10 @@ $(window).resize(function() { }); $(document).ready(function () { + $(".btn_console_clear").click(function () { + $("#console").html(""); + }); + // navigation bar $(".navbar-burger").click(function () { $(".navbar-burger").toggleClass('is-active'); @@ -381,7 +387,7 @@ $(document).ready(function () { let term = $("#serial_terminal"); let term_html = term.html(); - if (term_html.length > 50000) + if (term_html.length > 10000) { term.empty(); term.append("
"); @@ -579,6 +585,91 @@ $(document).ready(function () { }, false); + // thumbstick updater + div.addEventListener('receive_line', (e) => { + if ($("#tab_int_thumbstick").hasClass("is-active")) + { + let line = e.detail; + + if (line.startsWith ("#")) + { // update chart + //#1::