diff --git a/os/board/rtl8721csm/src/Make.defs b/os/board/rtl8721csm/src/Make.defs index f8328e635d..547878b27c 100644 --- a/os/board/rtl8721csm/src/Make.defs +++ b/os/board/rtl8721csm/src/Make.defs @@ -51,3 +51,6 @@ CSRCS += rtl8721csm_boot.c CSRCS += rtl8721csm_i2schar.c +ifeq ($(CONFIG_MI48),y) +CSRCS += rtl8721csm_mi48.c +endif diff --git a/os/board/rtl8721csm/src/rtl8721csm_boot.c b/os/board/rtl8721csm/src/rtl8721csm_boot.c index 69ca55afef..b06f55023f 100644 --- a/os/board/rtl8721csm/src/rtl8721csm_boot.c +++ b/os/board/rtl8721csm/src/rtl8721csm_boot.c @@ -313,9 +313,10 @@ void board_initialize(void) ipc_table_init(); amebad_mount_partions(); board_gpio_initialize(); - board_i2c_initialize(); - board_spi_initialize(); +// board_i2c_initialize(); +// board_spi_initialize(); board_i2s_initialize(); + rtl8721csm_mi48_initialize(); #ifdef CONFIG_WATCHDOG amebad_wdg_initialize(CONFIG_WATCHDOG_DEVPATH, 5000); #endif diff --git a/os/board/rtl8721csm/src/rtl8721csm_mi48.c b/os/board/rtl8721csm/src/rtl8721csm_mi48.c new file mode 100644 index 0000000000..7f74f3a728 --- /dev/null +++ b/os/board/rtl8721csm/src/rtl8721csm_mi48.c @@ -0,0 +1,189 @@ +/**************************************************************************** + * + * Copyright 2023 Samsung Electronics All Rights Reserved. + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include "gpio_api.h" +#include "gpio_irq_api.h" + +#ifdef CONFIG_MI48 + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ +#define DEVNAME_FORMAT "/dev/img%d" + +#define GPIO_RESET PB_2 // will set it to the right pin after wards +#define GPIO_DATA_READY PA_19 + +#define GPIO_UNSET 0 +#define GPIO_SET 1 + +/* i2c config */ +#define MI48_I2C_PORT 0 +#define MI48_I2C_FREQ 100000 +#define MI48_I2C_ADDRLEN 7 + +#define MI48_I2C_ADDR_H 0x41 /* need to set correct address */ +#define MI48_I2C_ADDR_L 0x40 + +/* spi config */ +#define MI48_SPI_PORT 0 +#define MI48_SPI_FREQ 1000000 +#define MI48_SPI_BPW 16 +#define MI48_SPI_CS 0 +#define MI48_SPI_MODE SPIDEV_MODE1 + +/**************************************************************************** + * Public Data + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct rtl8721csm_gpio_info_s { + gpio_t reset; + gpio_irq_t data_ready; +}; + +struct rtl8721csm_mi48_dev_s { + /* Lower level mi48 dev */ + struct mi48_lower_s lower; + + /* board specific gpio information */ + struct rtl8721csm_gpio_info_s gpio_info; + + /* gpio interrupt handler */ + mi48_handler_t handler; +}; + +static int rtl8721csm_mi48_gpio_reset(struct mi48_lower_s *lower); +static int rtl8721csm_mi48_gpio_irq_attach(struct mi48_lower_s *lower, mi48_handler_t handler, FAR char *arg); +static int rtl8721csm_mi48_gpio_irq_enable(struct mi48_lower_s *lower, int enable); + +static struct rtl8721csm_mi48_dev_s g_rtl8721csm_dev = { + .lower = { + .reset = rtl8721csm_mi48_gpio_reset, + .attach = rtl8721csm_mi48_gpio_irq_attach, + .enable = rtl8721csm_mi48_gpio_irq_enable, + .i2c_config = { + .frequency = MI48_I2C_FREQ, + .address = MI48_I2C_ADDR_L, + .addrlen = MI48_I2C_ADDRLEN, + }, + .spi_config = { + .bpw = MI48_SPI_BPW, + .freq = MI48_SPI_FREQ, + .cs = MI48_SPI_CS, + .mode = MI48_SPI_MODE, + }, + }, + .gpio_info = { + .reset.pin = GPIO_RESET, + }, + .handler = NULL + +}; + +/**************************************************************************** + * Private Functions Prototype + ****************************************************************************/ + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + +static int rtl8721csm_mi48_gpio_reset(struct mi48_lower_s *lower) +{ + gpio_write(&(g_rtl8721csm_dev.gpio_info.reset), GPIO_UNSET); + HAL_Delay(100); + gpio_write(&(g_rtl8721csm_dev.gpio_info.reset), GPIO_SET); + HAL_Delay(1000); + return OK; +} + +static void rtl8721csm_gpio_irq_handler(uint32_t id, gpio_irq_event event) +{ + if (g_rtl8721csm_dev.handler) { + g_rtl8721csm_dev.handler((void *)id); + } +} + +static int rtl8721csm_mi48_gpio_irq_attach(struct mi48_lower_s *lower, mi48_handler_t handler, FAR char *arg) +{ + g_rtl8721csm_dev.handler = handler; + return OK; +} + +static int rtl8721csm_mi48_gpio_irq_enable(struct mi48_lower_s *lower, int enable) +{ + if (enable) { + gpio_irq_enable(&(g_rtl8721csm_dev.gpio_info.data_ready)); + } else { + gpio_irq_disable(&(g_rtl8721csm_dev.gpio_info.data_ready)); + } + return OK; +} + +int rtl8721csm_mi48_initialize(void) +{ + int result = 0; + FAR struct i2c_dev_s *i2c; + FAR struct spi_dev_s *spi; + char devpath[32]; + + gpio_irq_init(&(g_rtl8721csm_dev.gpio_info.data_ready), GPIO_DATA_READY, rtl8721csm_gpio_irq_handler, 1); + gpio_irq_set(&(g_rtl8721csm_dev.gpio_info.data_ready), IRQ_RISE, 1); // Rising edge trigger + + i2c = up_i2cinitialize(MI48_I2C_PORT); + if (!i2c) { + result = -ENODEV; + goto done; + } + + spi = up_spiinitialize(1); + if (!i2c) { + result = -ENODEV; + goto done; + } + + /* register mi48 driver */ + snprintf(devpath, sizeof(devpath), DEVNAME_FORMAT, 0); + if (mi48_register(devpath, &g_rtl8721csm_dev.lower, i2c, spi) != 0) { + goto done; + } + + /* result is success */ + result = 0; + +done: + return result; +} + +#endif /* CONFIG_MI48 */ diff --git a/os/drivers/sensors/Kconfig b/os/drivers/sensors/Kconfig index b100785c93..a790d5c7ae 100644 --- a/os/drivers/sensors/Kconfig +++ b/os/drivers/sensors/Kconfig @@ -24,3 +24,10 @@ config SENSOR_PPD42NS_DEBUG enable PPD42ns dust sensor driver's debug message endif # SENSOR_PPD42NS + +config MI48 + bool "mi48 thermal imaging sensor" + depends on I2C && SPI + default n + ---help--- + enable mi48 thermal imaging sensor diff --git a/os/drivers/sensors/Make.defs b/os/drivers/sensors/Make.defs index 84378da638..4711005967 100644 --- a/os/drivers/sensors/Make.defs +++ b/os/drivers/sensors/Make.defs @@ -23,6 +23,10 @@ ifeq ($(CONFIG_SENSOR_PPD42NS),y) CSRCS += ppd42ns.c endif +ifeq ($(CONFIG_MI48),y) + CSRCS += mi48.c +endif + # Include sensor build support DEPPATH += --dep-path sensors diff --git a/os/drivers/sensors/mi48.c b/os/drivers/sensors/mi48.c new file mode 100644 index 0000000000..1133567c8b --- /dev/null +++ b/os/drivers/sensors/mi48.c @@ -0,0 +1,435 @@ +/**************************************************************************** + * + * Copyright 2023 Samsung Electronics All Rights Reserved. + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ +#include +#include +#include +#include +#include +#include + +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +#define GPIO_SIGNAL_LOW 0 +#define GPIO_SIGNAL_HIGH 1 + +#ifdef CONFIG_MI48_ENABLE_FRAME_HEADER +#define FRAME_HEADER_SIZE 80 /* 80 16bit words */ +#else +#define FRAME_HEADER_SIZE 0 +#endif + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct mi48_dev_s { + FAR struct mi48_lower_s *lower; /* mi48 driver config */ + FAR struct i2c_dev_s *i2c; /* I2C driver to use */ + FAR struct spi_dev_s *spi; /* SPI driver to use */ + int crefs; /* reference count on the driver instance */ + sem_t exclsem; /* exclusive access to the device */ + sem_t datasem; /* exclusive access while reading sensor data */ + uint16_t frame_data[4960 + FRAME_HEADER_SIZE]; /* Latest frame data */ +}; + +/**************************************************************************** + * Private Functions Prototype + ****************************************************************************/ + +void mi48Reset(void); +void mi48EnbleTemporalFilter(void); +void mi48SetFrameRateDivisor(uint8_t framerateDivisor); +void mi48StartContinuousCapture(void); + +static int mi48_open(FAR struct file *filep); +static int mi48_close(FAR struct file *filep); +static ssize_t mi48_read(FAR struct file *filep, FAR char *buffer, size_t len); +static int mi48_ioctl(FAR struct file *filep, int cmd, unsigned long arg); + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +/* mi48 driver instance */ +static FAR struct mi48_dev_s g_mi48_priv; + +/* This the vtable that supports the character driver interface */ +static const struct file_operations g_mi48_fops = { + mi48_open, /* open */ + mi48_close, /* close */ + mi48_read, /* read */ + NULL, /* write ?? probably no direct dependency*/ + NULL, /* seek */ + mi48_ioctl, /* ioctl */ +}; + +/**************************************************************************** + * Private Function + ****************************************************************************/ + +static uint8_t mi48_readreg_1byte(FAR struct mi48_dev_s *priv, uint8_t regaddr) +{ + uint8_t reg[4]; + FAR struct i2c_dev_s *dev = priv->i2c; + FAR struct i2c_config_s *mi48_i2c_config = &(priv->lower->i2c_config); + uint8_t reg_w[4]; + reg_w[0] = regaddr; + int ret = i2c_write(dev, mi48_i2c_config, reg_w, 1); + if (ret != 1) { + lldbg("Error, cannot read reg %x\n", regaddr); + PANIC(); + return ERROR; + } + ret = i2c_read(dev, mi48_i2c_config, reg, 1); + if (ret != 1) { + lldbg("Error, cannot read reg %x\n", regaddr); + PANIC(); + return ERROR; + } + return reg[0]; +} + +static int mi48_writereg_1byte(FAR struct mi48_dev_s *priv, uint8_t regaddr, uint8_t regval) +{ + int ret; + uint8_t reg[2]; + FAR struct i2c_dev_s *dev = priv->i2c; + FAR struct i2c_config_s *mi48_i2c_config = &(priv->lower->i2c_config); + + reg[0] = regaddr; + reg[1] = regval; + + ret = i2c_write(dev, mi48_i2c_config, (uint8_t *)reg, 2); + if (ret != 2) { + lldbg("Error, cannot write reg %x\n", regaddr); + PANIC(); + return ERROR; + } + return ret; +} + +void mi48EnbleTemporalFilter() +{ + mi48_writereg_1byte(&g_mi48_priv, 0xd0, 0x0b); + HAL_Delay(1000); +} + +void mi48SetFrameRateDivisor(uint8_t framerateDivisor) +{ + mi48_writereg_1byte(&g_mi48_priv, 0xb4, framerateDivisor); +} + +void mi48StartContinuousCapture() +{ + mi48_writereg_1byte(&g_mi48_priv, 0xb1, 0x03); +} + +/**************************************************************************** + * Name: mi48_takesem + * + * Description: + * Take the lock, waiting as necessary + * + ****************************************************************************/ +static inline int mi48_takesem(FAR sem_t *sem) +{ + /* Take a count from the semaphore, possibly waiting */ + if (sem_wait(sem) < 0) { + /* EINTR is the only error that we expect */ + int errcode = get_errno(); + DEBUGASSERT(errcode == EINTR); + return errcode; + } + + return 0; +} + +/**************************************************************************** + * Name: mi48_givesem + * + * Description: + * release the lock + * + ****************************************************************************/ +static inline void mi48_givesem(sem_t *sem) +{ + sem_post(sem); +} + +/**************************************************************************** + * Name: mi48_interrupt_handler + * + * Description: + * handle mi48's digital pin interrupt + * + ****************************************************************************/ +static void mi48_interrupt_handler(void *arg) +{ + /* this is rising edge interrupt handler on mi48's data ready pin */ + FAR struct mi48_dev_s *priv = (FAR struct mi48_dev_s *)&g_mi48_priv; + + if (priv == NULL) { + return; + } + + int ret; + + ret = mi48_takesem(&priv->datasem); + if (ret < 0) { + lldbg("Error: mi48_takesem() failed: %d\n", ret); + return; + } + + /* this interrupt indicates that a complete frame is available to read + * So, we need to fetch the frame using SPI */ + + SPI_RECVBLOCK(priv->spi, priv->frame_data, 4960 + FRAME_HEADER_SIZE); + + mi48_givesem(&priv->datasem); + return; +} + +/**************************************************************************** + * Name: mi48_open + * + * Description: + * Standard character driver open method. + * + ****************************************************************************/ +static int mi48_open(FAR struct file *filep) +{ + int ret; + + mi48StartContinuousCapture(); + + FAR struct inode *inode = filep->f_inode; + FAR struct mi48_dev_s *priv = inode->i_private; + + ret = mi48_takesem(&priv->exclsem); + if (ret < 0) { + /* + * A signal received while waiting for the last close + * operation. + */ + lldbg("ERROR: mi48_takesem() failed: %d\n", ret); + return ret; + } + + /* mi48 driver allows only 1 instance */ + if (priv->crefs > 0) { + lldbg("ERROR: mi48 driver is already opened.\n"); + goto errout_with_sem; + } + + /* set reference count */ + priv->crefs = 1; + + /* enable the gpio pin interrupt */ + +errout_with_sem: + mi48_givesem(&priv->exclsem); + return ret; +} + +/**************************************************************************** + * Name: mi48_close + * + * Description: + * Standard character driver close method. + * + ****************************************************************************/ +static int mi48_close(FAR struct file *filep) +{ + int ret; + FAR struct inode *inode = filep->f_inode; + FAR struct mi48_dev_s *priv = inode->i_private; + + /* Get exclusive access to the driver structure */ + ret = mi48_takesem(&priv->exclsem); + if (ret < 0) { + lldbg("ERROR: mi48_takesem() failed: %d\n", ret); + return ret; + } + + if (priv->crefs == 0) { + lldbg("ERROR: mi48 driver is already closed.\n"); + goto errout_with_sem; + } + + priv->crefs = 0; + + /* disable the gpio pin interrupt */ + ret = priv->lower->enable(priv->lower, 0); + if (ret < 0) { + lldbg("ERROR: failed to disable the interrupt handler. (ret=%d)\n", ret); + goto errout_with_sem; + } + + ret = 0; + +errout_with_sem: + mi48_givesem(&priv->exclsem); + return ret; +} + +/**************************************************************************** + * Name: mi48_read + * + * Description: + * Standard character driver read method. + * + ****************************************************************************/ +static ssize_t mi48_read(FAR struct file *filep, FAR char *buffer, size_t len) +{ + int ret; + FAR struct inode *inode = filep->f_inode; + FAR struct mi48_dev_s *priv = inode->i_private; + + ret = mi48_takesem(&priv->datasem); + if (ret < 0) { + lldbg("ERROR: mi48_takesem() failed: %d\n", ret); + return ret; + } + + /* disable gpio pin interrupt */ + priv->lower->enable(priv->lower, 0); + + /* copy the frame contents to the buffer */ + //abhishek .. to do may be print the contents here... + + /* enable gpio pin interrupt */ + priv->lower->enable(priv->lower, 1); + + mi48_givesem(&priv->datasem); + + return sizeof(float); +} + +/**************************************************************************** + * Name: mi48_ioctl + * + * Description: + * Standard character driver ioctl method. + * + ****************************************************************************/ +static int mi48_ioctl(FAR struct file *filep, int cmd, unsigned long arg) +{ + FAR struct inode *inode = filep->f_inode; + FAR struct mi48_dev_s *priv = inode->i_private; + + switch (cmd) { + case MI48IOC_HW_RESET: { + priv->lower->reset(priv->lower); + } + break; + case MI48IOC_ENABLE_TEMPORAL_FILTER: { + mi48EnbleTemporalFilter(); + } + break; + case MI48IOC_SET_FR_DIV: { + mi48SetFrameRateDivisor(2); + } + break; + case MI48IOC_CONT_CAPTURE: { + mi48StartContinuousCapture(); + } + break; + } + return OK; +} + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: mi48_register + * + * Description: + * This function will register mi48 dust sensor driver as /dev/dustN where N + * is the minor device number + * + * Input Parameters: + * devname - The full path to the driver to register. E.g., "/dev/img0" + * config - configuration for the mi48 driver. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ +int mi48_register(FAR const char *devname, FAR struct mi48_lower_s *lower, FAR struct i2c_dev_s *i2c, FAR struct spi_dev_s *spi) +{ + int ret; + + struct mi48_dev_s *priv = &g_mi48_priv; + + /* validate mi48 config */ + if (i2c == NULL || spi == NULL || lower == NULL || lower->reset == NULL || lower->attach == NULL || lower->enable == NULL) { + ret = EINVAL; + lldbg("ERROR: invalid mi48 config\n"); + return ret; + } + + priv->i2c = i2c; + priv->spi = spi; + /* set mi48 config */ + priv->lower = lower; + + /* reference count is set to 0 */ + priv->crefs = 0; + + /* set the SPI config */ + SPI_SETMODE(priv->spi, lower->spi_config.mode); + SPI_SETFREQUENCY(priv->spi, lower->spi_config.freq); + SPI_SETBITS(priv->spi, lower->spi_config.bpw); + + /* init semaphore */ + sem_init(&priv->exclsem, 0, 1); + sem_init(&priv->datasem, 0, 1); + + /* attach the interrupt handler */ + ret = priv->lower->attach(priv->lower, mi48_interrupt_handler, (FAR void *)priv); + if (ret < 0) { + lldbg("ERROR: failed to attach the interrupt handler. (ret=%d)\n", ret); + sem_destroy(&priv->exclsem); + sem_destroy(&priv->datasem); + return ret; + } + + /* register the character device driver */ + ret = register_driver(devname, &g_mi48_fops, 0666, priv); + if (ret < 0) { + lldbg("ERROR: failed to register driver %s. (ret=%d)\n", devname, ret); + sem_destroy(&priv->exclsem); + sem_destroy(&priv->datasem); + return ret; + } + + lldbg("Registered %s\n", devname); + + return 0; +} diff --git a/os/include/tinyara/fs/ioctl.h b/os/include/tinyara/fs/ioctl.h index 15ae18aa91..d293f8cd7f 100644 --- a/os/include/tinyara/fs/ioctl.h +++ b/os/include/tinyara/fs/ioctl.h @@ -101,6 +101,7 @@ #define _IOTBUSBASE (0x2600) /* iotbus ioctl commands */ #define _FBIOCBASE (0x2700) /* Frame buffer character driver ioctl commands */ #define _CPULOADBASE (0x2800) /* cpuload ioctl commands */ +#define _MI48BASE (0x2900) /* mi48 control ioctl commands */ #define _TESTIOCBASE (0xfe00) /* KERNEL TEST DRV module ioctl commands */ @@ -442,6 +443,16 @@ #define CPULOADIOC_STOP _CPULOADIOC(0x0002) #define CPULOADIOC_GETVALUE _CPULOADIOC(0x0003) +/* MI48 driver ioctl definitions ************************/ + +#define _MI48IOCVALID(c) (_IOC_TYPE(c) == _MI48BASE) +#define _MI48IOC(nr) _IOC(_CPULOADBASE, nr) + +#define MI48IOC_ENABLE_TEMPORAL_FILTER _MI48IOC(0x0001) +#define MI48IOC_SET_FR_DIV _MI48IOC(0x0002) +#define MI48IOC_CONT_CAPTURE _MI48IOC(0x0003) +#define MI48IOC_HW_RESET _MI48IOC(0x0004) + /* Audio driver ioctl definitions *************************************/ /* (see tinyara/audio/audio.h) */ diff --git a/os/include/tinyara/sensors/mi48.h b/os/include/tinyara/sensors/mi48.h new file mode 100644 index 0000000000..ff6fb46bed --- /dev/null +++ b/os/include/tinyara/sensors/mi48.h @@ -0,0 +1,74 @@ +/**************************************************************************** + * + * Copyright 2023 Samsung Electronics All Rights Reserved. + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Public Data + ****************************************************************************/ +#define HAL_Delay os_delay + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +typedef void (*mi48_handler_t)(void* arg); + +struct mi48_lower_s { + /* I2C related configs */ + struct i2c_config_s i2c_config; + + /* SPI related configs */ + struct spi_io_config spi_config; + + /* callback function: reset mi48 */ + int (*reset)(struct mi48_lower_s *lower); + + /* callback function: attach the mi48 interrupt handler to the GPIO interrupt */ + int (*attach)(struct mi48_lower_s *lower, mi48_handler_t handler, FAR char *arg); + + /* callback function: enable or disable gpio pin interrupt */ + int (*enable)(struct mi48_lower_s *lower, int enable); +}; + +/**************************************************************************** + * Public Function + ****************************************************************************/ + +/**************************************************************************** + * Name: mi48_register + * + * Description: + * This function will register mi48 thermal imaging sensor driver as /dev/imgN where N + * is the minor device number + * + * Input Parameters: + * devname - The full path to the driver to register. E.g., "/dev/img0" + * config - configuration for the mi48 driver. + * + * Returned Value: + * Zero is returned on success. Otherwise, a negated errno value is + * returned to indicate the nature of the failure. + * + ****************************************************************************/ +int mi48_register(FAR const char *devname, FAR struct mi48_lower_s *lower, FAR struct i2c_dev_s *i2c, FAR struct spi_dev_s *spi); diff --git a/tools/mi48/temp_to_rgb.py b/tools/mi48/temp_to_rgb.py new file mode 100644 index 0000000000..798f487425 --- /dev/null +++ b/tools/mi48/temp_to_rgb.py @@ -0,0 +1,50 @@ +import numpy as np +from PIL import Image + +array = np.zeros([62, 80, 3], dtype=np.uint8) + +print(array.shape) + +thermal_data = [] +polarity = 0 +temp = 350 +flip = 0 +# below code is to generate temprature data randomly +# if we have data we can direclty read it instead +for j in range(4960) : + thermal_data.append(temp) + temp = temp - 1 + flip = flip + 1 + if flip == 80 : + temp = 350 + flip = 0 + +maxTemperature = max(thermal_data) +minTemperature = min(thermal_data) + +r = [255,253,251,249,247,245,243,241,239,237,235,233,231,229,227,225,223,221,219,217,215,213,211,209,207,205,203,201,199,197,195,193,191,189,187,185,183,181,179,177,175,173,171,169,167,165,163,161,159,157,155,153,151,149,147,145,143,141,139,137,135,133,131,129,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,62,60,58,56,54,52,50,48,46,44,42,40,38,36,34,32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0,0,2,4,6,8,10,12,14,17,19,21,23,25,27,29,31,36,41,46,51,56,61,66,71,76,81,86,91,96,101,106,111,116,121,125,130,135,139,144,149,153,158,163,167,172,177,181,186,189,191,194,196,198,200,203,205,207,209,212,214,216,218,221,223,224,225,226,227,228,229,230,231,231,232,233,234,235,236,237,238,239,240,240,241,241,242,242,243,243,244,244,245,245,246,246,247,247,248,248,249,249,250,250,251,251,252,252,253,253,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255] +g = [255,253,251,249,247,245,243,241,239,237,235,233,231,229,227,225,223,221,219,217,215,213,211,209,207,205,203,201,199,197,195,193,191,189,187,185,183,181,179,177,175,173,171,169,167,165,163,161,159,157,155,153,151,149,147,145,143,141,139,137,135,133,131,129,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,62,60,58,56,54,52,50,48,46,44,42,40,38,36,34,32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,3,3,3,4,4,5,5,5,6,6,7,7,10,13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,57,60,64,67,71,74,78,81,85,88,92,95,99,102,106,109,112,116,119,123,127,130,134,138,141,145,149,152,156,160,163,167,171,175,178,182,185,189,192,196,199,203,206,210,213,217,220,224,227,229,231,233,234,236,238,240,242,244,246,248,249,251,253,255] +b = [255,253,251,249,247,245,243,241,239,237,235,233,231,229,227,225,223,221,219,217,215,213,211,209,207,205,203,201,199,197,195,193,191,189,187,185,183,181,179,177,175,173,171,169,167,165,163,161,159,157,155,153,151,149,147,145,143,141,139,137,135,133,131,129,126,124,122,120,118,116,114,112,110,108,106,104,102,100,98,96,94,92,90,88,86,84,82,80,78,76,74,72,70,68,66,64,62,60,58,56,54,52,50,48,46,44,42,40,38,36,34,32,30,28,26,24,22,20,18,16,14,12,10,8,6,4,2,0,9,16,24,31,38,45,53,60,67,74,82,89,96,103,111,118,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,136,137,137,137,138,138,138,139,139,139,140,140,140,141,141,137,132,127,121,116,111,106,101,95,90,85,80,75,69,64,59,49,47,44,42,39,37,34,32,29,27,24,22,19,17,14,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,14,15,16,18,19,20,21,22,23,24,25,27,28,29,30,39,53,67,81,95,109,123,137,151,165,179,193,207,221,235,249] + +row = 0 +col = 0 +thermal = 350 +for j in range(4960) : + v = (float)(thermal_data[j] - minTemperature)/(float)(maxTemperature - minTemperature) + vv = (int) (v*255) + R = r[vv] + G = g[vv] + B = b[vv] + array[col][row][0] = R + array[col][row][1] = G + array[col][row][2] = B + row = row + 1 + print(thermal_data[j], end = ',') + if row == 80 : + print(' ') + row = 0 + col = col + 1 + +img = Image.fromarray(array) +img.show('testrgb.png') +img.save('testrgb.png') diff --git a/tools/mi48/test.csv b/tools/mi48/test.csv new file mode 100644 index 0000000000..e88c7bbb0c --- /dev/null +++ b/tools/mi48/test.csv @@ -0,0 +1,62 @@ +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, +350,349,348,347,346,345,344,343,342,341,340,339,338,337,336,335,334,333,332,331,330,329,328,327,326,325,324,323,322,321,320,319,318,317,316,315,314,313,312,311,310,309,308,307,306,305,304,303,302,301,300,299,298,297,296,295,294,293,292,291,290,289,288,287,286,285,284,283,282,281,280,279,278,277,276,275,274,273,272,271, diff --git a/tools/mi48/testrgb.png b/tools/mi48/testrgb.png new file mode 100644 index 0000000000..ff56505646 Binary files /dev/null and b/tools/mi48/testrgb.png differ