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 @@
-
+
-
-
-
+
+
+
@@ -195,15 +199,15 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
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::