start parsing meta information from JSON objects coming through endpoints,

like shutter status and battery status
This commit is contained in:
Nicole Faerber 2021-02-01 01:35:59 +01:00
parent 654ba67237
commit ab5cbe7d6f
7 changed files with 461 additions and 122 deletions

View file

@ -1,6 +1,6 @@
CC=gcc
CFLAGS=-g -O2 -Wall -D_REENTRANT `pkg-config --cflags gtk+-3.0 libusb-1.0 libjpeg`
LIBS=`pkg-config --libs gtk+-3.0 libusb-1.0 libjpeg` -lm
CFLAGS=-g -O2 -Wall -D_REENTRANT `pkg-config --cflags gtk+-3.0 libusb-1.0 libjpeg libcjson`
LIBS=`pkg-config --libs gtk+-3.0 libusb-1.0 libjpeg libcjson` -lm
OBJ=flirgtk.o cam-thread.o cairo_jpg/src/cairo_jpg.o
PRG=flirgtk

128
NOTES.txt
View file

@ -28,3 +28,131 @@ unsigned char * cairo_image_surface_get_data (cairo_surface_t *surfac
get pointer to imag data for inspection _and_ manipulation
All messages are preceded by a header.
All headers are comprised of 32-bit words in little-endian order.
Headers of config endpoints have 4 words, those of file endpoints have 6 words, and those of frame endpoints are 7 words.
The first word is always the magic number (0x1cc for config, 0x5510 for file, 0xbeef for frame).
The second word appears to be always one. I'm still not sure about its meaning.
The third word is always the payload (message) size in bytes.
The last word is always the CRC-32 of all but the last word of header with the following parameters (this is the conventional CRC-32):
Polynomial: 0x04C11DB7, Init: 0xFFFFFFFF, Reflect Input: true, Reflect Output: true, XOR Output: 0xFFFFFFFF
For file headers:
The fourth word is the stream identifier.
The fifth word is the conventional CRC-32 of the file itself.
For frame headers:
The fourth word is the size of thermal image.
The fifth word is the size of visual (jpeg) image.
The sixth word is the size of status string.
After issuing a command to the config endpoint, you can query it for a response.
For commands of type 'setOption', the response is of type 'setOptionStatus' and indicates the new value of the option (-1 if the option does not exist).
For commands of type 'openFile', the response is of type 'openFileStatus' and indicates the stream identifier of the opened file. The stream identifier is essentially the return value of the fopen function. Negative values indicate different error codes. Non-negative values could be used by a readFile command to read the opened file.
Analysis of the sdk binary reveals that there are also 'reboot' and 'upgradeFirmware' commands with corresponding responses 'rebootStatus' and 'upgradeFirmwareStatus'. But I haven't worked out the required arguments for these commands.
Meta data comes as JSON structures:
EP81
----
{
"type":"sledInformation",
"data":
{
"serialNumberBoard":"F07H8J0055D",
"partNumberBoard":"invalid",
"versionBoard":"invalid",
"serialNumberLepton":"2171207",
"versionLepton":"3.3.26",
"leptonQR":"invalid",
"versionRosebudFactoryESW":"1.0.25",
"versionRosebudOperationalESW":"1.0.27",
"versionRosebudUpdaterESW":"1.0.25",
"versionRosebudAPI":"master.bc654fc",
"gitRevision":"master.bc654fc",
"automaticShutter":"Y",
"formFactor":"dongle",
"thermalHeight":"120",
"thermalWidth":"160",
"bigEndianThermal":"0",
"operatingMode":"operational"
}
}
{
"type":"batteryVoltageUpdate",
"data":
{
"voltage":3.90000009536743,
"percentage":77
}
}
{
"type":"batteryChargingCurrentUpdate",
"data":
{
"chargingCurrent":0
}
}
{
"type":"batteryChargingStateUpdate",
"data":
{
"chargingState":"stateNoCharging"
}
}
{
"type":"batteryChargingStateUpdate",
"data":
{
"chargingState":"stateChargingSmartPhone"
}
}
EP81=0 in 101
<cc><01><00><00><01><00><00><00>U<00><00><00>0s<8c><df>{"type":"batteryVoltageUpdate","data":{"voltage":4.11999988555908,"percentage":100}}<00>
EP81=0 in 100
<cc><01><00><00><01><00><00><00>T<00><00><00>U<14>0g{"type":"batteryVoltageUpdate","data":{"voltage":4.1100001335144,"percentage":100}}<00>
EP81=0 in 101
<cc><01><00><00><01><00><00><00>U<00><00><00>0s<8c><df>{"type":"batteryVoltageUpdate","data":{"voltage":4.11999988555908,"percentage":100}}<00>
EP81=0 in 100
<cc><01><00><00><01><00><00><00>T<00><00><00>U<14>0g{"type":"batteryVoltageUpdate","data":{"voltage":4.1100001335144,"percentage":100}}<00>
EP81=0 in 101
<cc><01><00><00><01><00><00><00>U<00><00><00>0s<8c><df>{"type":"batteryVoltageUpdate","data":{"voltage":4.11999988555908,"percentage":100}}<00>
EP81=0 in 100
<cc><01><00><00><01><00><00><00>T<00><00><00>U<14>0g{"type":"batteryVoltageUpdate","data":{"voltage":4.1100001335144,"percentage":100}}<00>
EP81=0 in 101
<cc><01><00><00><01><00><00><00>U<00><00><00>0s<8c><df>{"type":"batteryVoltageUpdate","data":{"voltage":4.11999988555908,"percentage":100}}<00>
There can be more than one message in one EP transfer:
EP81=0 in 294, magic=0x000001cc sec=00000001 len=00000055
<cc><01><00><00><01><00><00><00>U<00><00><00>0s<8c><df>{"type":"batteryVoltageUpdate","data":{"voltage":4.13000011444092,"percentage":100}}<00><cc><01><00><00><01><00><00><00>H<00><00><00>r<fc><ff>}{"type":"batteryChargingCurrentUpdate","data":{"chargingCurrent":1000}}<00><cc><01><00><00><01><00><00><00>Y<00><00><00><88><cc>Z<95>{"type":"batteryChargingStateUpdate","data":{"chargingState":"stateChargingSmartPhone"}}<00>
EP85
----
{
"shutterState":"FFC",
"shutterTemperature":309.239990234375,
"usbNotifiedTimestamp":1184541462.87291,
"usbEnqueuedTimestamp":1184541462.87494,
"ffcState":"FFC_PROGRESS"
}
{
"shutterState":"ON",
"shutterTemperature":310.679992675781,
"usbNotifiedTimestamp":1184542349.84666,
"usbEnqueuedTimestamp":1184542349.85135,
"ffcState":"FFC_VALID_RAD"
}

View file

@ -5,6 +5,21 @@ GTK+ application for FLIR ONE USB thermal camera based on flir-v4l:
https://github.com/fnoop/flirone-v4l2
== depdendencies ==
GTK+-3.0
Cairo
libusb-1.0
libjpeg
libcjson
This should install everything under Debian and derivatives:
apt install libgtk-3-dev libjpeg-dev libusb-1.0-0-dev libcjson-dev
== building ==
Makefile relies on pkg-config, if setup correctly simply running 'make'
should build the application.
== libusb & udev ==
cp 77-flirone-lusb.rules /lib/udev/rules.d/
udevadm control --reload-rules

View file

@ -18,6 +18,7 @@
*/
#include <gtk/gtk.h>
#include <cJSON.h>
// from main thread
void update_fb(void);
@ -28,6 +29,7 @@ extern unsigned char *color_palette;
#include <unistd.h>
#include <ctype.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
@ -41,19 +43,17 @@ extern unsigned char *color_palette;
#include <fcntl.h>
#include <math.h>
#include "cam-thread.h"
#include "plank.h"
// -----------------START-ORG-CODE------------------------------------------
// #include "jpeglib.h"
#define VENDOR_ID 0x09cb
#define PRODUCT_ID 0x1996
static struct libusb_device_handle *devh = NULL;
int filecount=0;
//int filecount=0;
struct timeval t1, t2;
long long fps_t;
@ -73,6 +73,125 @@ extern unsigned char *jpeg_buffer;
extern unsigned int jpeg_size;
extern unsigned char *ir_buffer;
struct shutter_state_t shutter_state;
struct battery_state_t battery_state;
// EP81 device status message (JSON)
// {
// "type":"batteryChargingCurrentUpdate",
// "data":
// {
// "chargingCurrent":0
// }
// }
// {
// "type":"batteryChargingStateUpdate",
// "data":
// {
// "chargingState":"stateNoCharging"
// }
// }
// {
// "type":"batteryVoltageUpdate",
// "data":
// {
// "voltage":3.76999998092651,
// "percentage":77
// }
// }
void
parse_status(unsigned char *buf)
{
cJSON *status_json = cJSON_Parse((char *)buf);
const cJSON *res = NULL;
if (status_json == NULL)
return;
res = cJSON_GetObjectItemCaseSensitive(status_json, "shutterState");
if (cJSON_IsString(res) && (res->valuestring != NULL)) {
if (strncmp(res->valuestring,"FFC",3)==0) {
shutter_state.shutterState=sFFC;
} else if (strncmp(res->valuestring,"ON",2)==0) {
shutter_state.shutterState=sON;
} else {
shutter_state.shutterState=sUNKNOWN;
}
}
res = cJSON_GetObjectItemCaseSensitive(status_json, "shutterTemperature");
if (cJSON_IsNumber(res)) {
shutter_state.shutterTemperature=res->valuedouble;
}
res = cJSON_GetObjectItemCaseSensitive(status_json, "usbNotifiedTimestamp");
if (cJSON_IsNumber(res)) {
shutter_state.usbNotifiedTimestamp=res->valuedouble;
}
res = cJSON_GetObjectItemCaseSensitive(status_json, "usbEnqueuedTimestamp");
if (cJSON_IsNumber(res)) {
shutter_state.usbEnqueuedTimestamp=res->valuedouble;
}
res = cJSON_GetObjectItemCaseSensitive(status_json, "ffcState");
if (cJSON_IsString(res) && (res->valuestring != NULL)) {
if (strncmp(res->valuestring,"FFC_VALID_RAD",13)==0) {
shutter_state.ffcState=FFC_VALID_RAD;
} else if (strncmp(res->valuestring,"FFC_PROGRESS",12)==0) {
shutter_state.ffcState=FFC_PROGRESS;
} else {
shutter_state.ffcState=FFC_UNKNOWN;
}
}
cJSON_Delete(status_json);
}
void
parse_config_in(unsigned char *buf)
{
cJSON *config_json = cJSON_Parse((char *)buf);
const cJSON *res = NULL;
const cJSON *res2 = NULL;
const cJSON *res3 = NULL;
if (config_json == NULL) {
fprintf(stderr, "config msg parse json failed\n");
return;
}// else
// fprintf(stderr, "config msg parse json\n%s\n", buf);
res = cJSON_GetObjectItemCaseSensitive(config_json, "type");
res2 = cJSON_GetObjectItemCaseSensitive(config_json, "data");
if (cJSON_IsString(res) && (res->valuestring != NULL)) {
if (strncmp(res->valuestring,"batteryVoltageUpdate",20)==0) {
res3 = cJSON_GetObjectItemCaseSensitive(res2, "voltage");
if (cJSON_IsNumber(res3)) {
battery_state.voltage = res3->valuedouble;
// printf("bat %.2fV\n", res3->valuedouble);
}
res3 = cJSON_GetObjectItemCaseSensitive(res2, "percentage");
if (cJSON_IsNumber(res3)) {
battery_state.percentage = res3->valueint;
// printf("bat %f%%\n", res3->valuedouble);
}
}
if (strncmp(res->valuestring,"batteryChargingCurrentUpdate",28)==0) {
res3 = cJSON_GetObjectItemCaseSensitive(res2, "chargingCurrent");
if (cJSON_IsNumber(res3)) {
battery_state.chargingCurrent = res3->valuedouble;
// printf("bat %.2fV\n", res3->valuedouble);
}
}
if (strncmp(res->valuestring,"batteryChargingStateUpdate",26)==0) {
res3 = cJSON_GetObjectItemCaseSensitive(res2, "chargingCurrent");
if (cJSON_IsString(res3) && (res3->valuestring != NULL)) {
printf("bat chg state '%s'\n", res3->valuestring);
}
}
}
cJSON_Delete(config_json);
}
double
raw2temperature(unsigned short RAW)
@ -128,7 +247,7 @@ void vframe(char ep[],char EP_error[], int r, int actual_length, unsigned char b
uint32_t FrameSize = buf85[ 8] + (buf85[ 9] << 8) + (buf85[10] << 16) + (buf85[11] << 24);
uint32_t ThermalSize = buf85[12] + (buf85[13] << 8) + (buf85[14] << 16) + (buf85[15] << 24);
uint32_t JpgSize = buf85[16] + (buf85[17] << 8) + (buf85[18] << 16) + (buf85[19] << 24);
// uint32_t StatusSize = buf85[20] + (buf85[21] << 8) + (buf85[22] << 16) + (buf85[23] << 24);
uint32_t StatusSize = buf85[20] + (buf85[21] << 8) + (buf85[22] << 16) + (buf85[23] << 24);
//printf("FrameSize= %d (+28=%d), ThermalSize %d, JPG %d, StatusSize %d, Pointer %d\n",FrameSize,FrameSize+28, ThermalSize, JpgSize,StatusSize,buf85pointer);
@ -136,22 +255,31 @@ void vframe(char ep[],char EP_error[], int r, int actual_length, unsigned char b
// wait for next chunk
return;
}
int v;
if (StatusSize > 10) {
parse_status(&buf85[28+ThermalSize+JpgSize]);
}
int i,v;
// get a full frame, first print the status
t1=t2;
gettimeofday(&t2, NULL);
// fps as moving average over last 20 frames
// fps_t = (19*fps_t+10000000/(((t2.tv_sec * 1000000) + t2.tv_usec) - ((t1.tv_sec * 1000000) + t1.tv_usec)))/20;
filecount++;
//filecount++;
// printf("#%08i %lld/10 fps:",filecount,fps_t);
// for (i = 0; i < StatusSize; i++) {
// v=28+ThermalSize+JpgSize+i;
// if(buf85[v]>31) {printf("%c", buf85[v]);}
// }
// printf("\n");
#if 0
for (i = 0; i < StatusSize; i++) {
v=28+ThermalSize+JpgSize+i;
if (buf85[v]>31) {
printf("%c", buf85[v]);
} else {
printf("<%02x>", buf85[v]);
}
}
printf("\n");
#endif
buf85pointer=0;
unsigned short pix[160*120]; // original Flir 16 Bit RAW
@ -273,8 +401,8 @@ void vframe(char ep[],char EP_error[], int r, int actual_length, unsigned char b
color_palette[3 * v + 1]; // G
ir_buffer[(4*y * 160 + x*4)+2] =
color_palette[3 * v]; // R
ir_buffer[(4*y * 160 + x*4)+3] =
0x00; // A, empty
// ir_buffer[(4*y * 160 + x*4)+3] =
// 0x00; // A, empty
#if 0
// assemble one 32 bit pixel
fbdata[16*y * 640 + x*16] = color_palette[3 * v + 2]; // B
@ -389,22 +517,24 @@ int i;
/*
char filename[100];
sprintf(filename, "EP%s#%05i.bin",ep,filecount);
filecount++;
//filecount++;
FILE *file = fopen(filename, "wb");
fwrite(buf, 1, actual_length, file);
fclose(file);
*/
// hex print of first byte
#if 1
for (i = 0; i < (((200)<(actual_length))?(200):(actual_length)); i++) {
printf(" %02x", buf[i]);
}
#else
printf("\nSTRING:\n");
for (i = 0; i < (((200)<(actual_length))?(200):(actual_length)); i++) {
if (buf[i]>31) {
if (isascii(buf[i])) {
printf("%c", buf[i]);
}
}
#endif
printf("\n");
}
}
@ -506,7 +636,7 @@ int r = 1;
}
now = time(0); // Get the system time
printf("\n:xx %s",ctime(&now));
state = 3; // jump over wait stait 2. Not really using any data from CameraFiles.zip
state = 3; // jump over wait stait 2. Not really using any data from CameraFiles.zip
break;
case 2:
printf("\nask for CameraFiles.zip on EP 0x83:\n");
@ -599,16 +729,42 @@ int r = 1;
// poll Frame Endpoints 0x85
// don't change timeout=100ms !!
r = libusb_bulk_transfer(devh, 0x85, buf, sizeof(buf), &actual_length, 100);
if (actual_length > 0)
if (actual_length > 0) {
// print_bulk_result("0x85", "none", r, actual_length, buf);
vframe("0x85",EP85_error, r, actual_length, buf, colormap);
}
break;
}
// poll Endpoints 0x81, 0x83
r = libusb_bulk_transfer(devh, 0x81, buf, sizeof(buf), &actual_length, 10);
/*
r = libusb_bulk_transfer(devh, 0x81, buf, sizeof(buf), &actual_length, 10);
if (actual_length > 16) {
int i;
unsigned int magic, second, len;
magic=*(unsigned int *)&buf[0];
second=*(unsigned int *)&buf[4];
len=*(unsigned int *)&buf[8];
fprintf(stderr, "EP81=%d in %d, magic=0x%08x sec=%08x len=%08x\n", r, actual_length,magic,second,len);
if (magic == 0x000001cc) {
parse_config_in(&buf[16]);
}
#if 1
for (i=0; i<actual_length; i++) {
if (buf[i] > 31 && buf[i]<128)
fprintf(stderr, "%c", buf[i]);
else
//fprintf(stderr, ".");
fprintf(stderr, "<%02x>", buf[i]);
}
fprintf(stderr, "\n");
#endif
}
/*
if (actual_length > 0 && actual_length <= 101) {
char k[5];
int i;
if (strncmp (&buf[32],"VoltageUpdate",13)==0) {
printf("xx %d\n",actual_length);
char *token, *string, *tofree, *string2;
@ -636,13 +792,17 @@ int r = 1;
// }
}
}
*/
*/
r = libusb_bulk_transfer(devh, 0x83, buf, sizeof(buf), &actual_length, 10);
if (strcmp(libusb_error_name(r), "LIBUSB_ERROR_NO_DEVICE")==0) {
fprintf(stderr, "EP 0x83 LIBUSB_ERROR_NO_DEVICE -> reset USB\n");
goto out;
}
if (actual_length > 0) {
//int i;
fprintf(stderr, "EP83 in %d\n", actual_length);
}
// print_bulk_result("0x83",EP83_error, r, actual_length, buf);
}

31
cam-thread.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef _CAM_THREAD_H
#define _CAM_THREAD_H
enum ffcstate_t {FFC_VALID_RAD, FFC_PROGRESS, FFC_UNKNOWN};
enum shutterstate_t {sON, sFFC, sUNKNOWN};
// {
// "shutterState":"ON",
// "shutterTemperature":310.679992675781,
// "usbNotifiedTimestamp":1184542349.84666,
// "usbEnqueuedTimestamp":1184542349.85135,
// "ffcState":"FFC_VALID_RAD"
// }
struct shutter_state_t {
enum shutterstate_t shutterState; // ON or FFC
double shutterTemperature; // in Kelvin? C = Kelvin - 273.15
double usbNotifiedTimestamp;
double usbEnqueuedTimestamp;
enum ffcstate_t ffcState; // FFC_VALID_RAD or FFC_PROGRESS
};
enum chargingState_t {stateNoCharging, stateCharging, stateUNKNOWN};
struct battery_state_t {
enum chargingState_t chargingState;
double voltage;
int percentage;
double chargingCurrent;
};
#endif

190
flirgtk.c
View file

@ -25,6 +25,8 @@
#include <time.h>
// #include <limits.h>
#include "cam-thread.h"
#include "cairo_jpg/src/cairo_jpg.h"
#include "palettes/15.h"
@ -60,6 +62,9 @@ unsigned char *color_palette;
gpointer cam_thread_main(gpointer user_data);
extern double t_min, t_max, t_center;
extern struct shutter_state_t shutter_state;
extern struct battery_state_t battery_state;
unsigned char *ir_buffer=NULL;
unsigned char *jpeg_buffer=NULL;
unsigned int jpeg_size=0;
@ -97,27 +102,28 @@ cairo_surface_t
unsigned int *p1, *pc;
int x,y;
static cairo_surface_t *ps=NULL;
//static unsigned char *cm=NULL;
cairo_t *cr;
unsigned char *fbdata;
char tdisp[16];
#define P_XPOS 175
#define P_YPOS 2
#define P_HEIGHT 14
if (ps==NULL)
ps=cairo_image_surface_create(CAIRO_FORMAT_RGB24, 640, 20);
cr=cairo_create(ps);
fbdata=cairo_image_surface_get_data(ps);
memset(fbdata,0,(640*20*4));
y=5;
y=P_YPOS;
for (x=0; x<256; x++) {
fbdata[4* y * 640 + ((x+P_XPOS)*4)] = color_palette[3 * x + 2]; // B
fbdata[(4* y * 640 + ((x+P_XPOS)*4))+1] = color_palette[3 * x + 1]; // G
fbdata[(4* y * 640 + ((x+P_XPOS)*4))+2] = color_palette[3 * x]; // R
}
y=5;
y=P_YPOS;
p1 = (unsigned int *)&fbdata[4 * y * 640 + (P_XPOS*4)]; // pointer to start of line
for (y=5; y<15; y++) {
for (y=P_YPOS; y<(P_YPOS+P_HEIGHT); y++) {
pc = (unsigned int *)&fbdata[4 * y * 640 + (P_XPOS*4)]; // pointer to start of copy line
memcpy(pc,p1,256*4);
}
@ -257,6 +263,15 @@ cairo_t *cr;
cairo_move_to (cr, 330, 220);
cairo_show_text (cr, tdisp);
// print battery % top right
snprintf(tdisp, 16, "%d%%", battery_state.percentage);
cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
cairo_select_font_face (cr, "Sans",
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 14);
cairo_move_to (cr, 580, 20);
cairo_show_text (cr, tdisp);
cairo_destroy(cr);
pending = FALSE;
}
@ -292,7 +307,7 @@ char fname[30];
strftime (fname, 30, "ircam-%y%m%d%H%M%S", loctime);
strncpy(pname, "./", PATH_MAX-30-4); // leave room for filename+extension
strncat(pname, fname, PATH_MAX-5); // -5 to leave space for trailing \0 byte + extension
strncat(pname, ".png", PATH_MAX-1); // -5 to leave space for trailing \0 byte + extension
strncat(pname, ".png", PATH_MAX-1); // -1 to leave space for trailing \0 byte
cairo_surface_write_to_png (psurface, pname);
take_vis_shot=TRUE;
@ -303,6 +318,8 @@ start_clicked(GtkWidget *button, gpointer user_data)
{
if (gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(play_button))) {
flir_run = TRUE;
memset(&shutter_state, 0, sizeof(shutter_state));
memset(&battery_state, 0, sizeof(battery_state));
if (ir_buffer == NULL)
g_printerr("ir_buffer\n");
g_thread_new ("CAM thread", cam_thread_main, NULL);
@ -339,14 +356,6 @@ close_window (void)
gtk_main_quit();
}
gboolean
handle_timeout (gpointer user_data)
{
update_fb();
return TRUE;
}
void
palette_changed (GtkComboBox *widget, gpointer user_data)
{
@ -381,108 +390,97 @@ GtkWidget *w, *i;
// GtkWidget *da;
// default color palette
// init default color palette
color_palette = palette_Rainbow;
if (!window) {
// gappw=gtk_application_window_new(gapp);
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "FLIR One");
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
gtk_window_set_title (GTK_WINDOW (window), "FLIR One");
g_signal_connect (window, "destroy",
G_CALLBACK (close_window), NULL);
g_signal_connect (window, "destroy",
G_CALLBACK (close_window), NULL);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
gtk_container_add (GTK_CONTAINER (window), box);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 4);
gtk_container_add (GTK_CONTAINER (window), box);
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
gtk_container_add (GTK_CONTAINER (box), hbox);
hbox = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4);
gtk_container_add (GTK_CONTAINER (box), hbox);
// 48 GTK_ICON_SIZE_DIALOG
// 32 GTK_ICON_SIZE_DND
// media-playback-start
// w = gtk_button_new_with_label("Start");
// w = gtk_button_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_DND);
play_button = gtk_toggle_button_new();
i = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_DND);
gtk_button_set_image(GTK_BUTTON(play_button),i);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(play_button), FALSE);
gtk_container_add (GTK_CONTAINER (hbox), play_button);
// 48 GTK_ICON_SIZE_DIALOG
// 32 GTK_ICON_SIZE_DND
// media-playback-start
// w = gtk_button_new_with_label("Start");
// w = gtk_button_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_DND);
play_button = gtk_toggle_button_new();
i = gtk_image_new_from_icon_name("media-playback-start", GTK_ICON_SIZE_DND);
gtk_button_set_image(GTK_BUTTON(play_button),i);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(play_button), FALSE);
gtk_container_add (GTK_CONTAINER (hbox), play_button);
g_signal_connect (play_button, "clicked",
G_CALLBACK (start_clicked), NULL);
g_signal_connect (play_button, "clicked",
G_CALLBACK (start_clicked), NULL);
// media-playback-stop
// w = gtk_button_new_with_label("Stop");
//w = gtk_button_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_DND);
stop_button = gtk_toggle_button_new();
i = gtk_image_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_DND);
gtk_button_set_image(GTK_BUTTON(stop_button),i);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(stop_button), TRUE);
gtk_container_add (GTK_CONTAINER (hbox), stop_button);
// media-playback-stop
// w = gtk_button_new_with_label("Stop");
//w = gtk_button_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_DND);
stop_button = gtk_toggle_button_new();
i = gtk_image_new_from_icon_name("media-playback-stop", GTK_ICON_SIZE_DND);
gtk_button_set_image(GTK_BUTTON(stop_button),i);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(stop_button), TRUE);
gtk_container_add (GTK_CONTAINER (hbox), stop_button);
g_signal_connect (stop_button, "clicked",
G_CALLBACK (stop_clicked), NULL);
g_signal_connect (stop_button, "clicked",
G_CALLBACK (stop_clicked), NULL);
// drop down for color palettes
w = gtk_combo_box_text_new();
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "7");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "15");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "17");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "85");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "92");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Grayscale");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Grey");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Iron 2");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Iron Black");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Rainbow");
gtk_combo_box_set_active (GTK_COMBO_BOX(w), 9);
gtk_container_add (GTK_CONTAINER (hbox), w);
g_signal_connect (w, "changed",
G_CALLBACK (palette_changed), NULL);
// drop down for color palettes
w = gtk_combo_box_text_new();
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "7");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "15");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "17");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "85");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "92");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Grayscale");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Grey");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Iron 2");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Iron Black");
gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT(w), NULL, "Rainbow");
gtk_combo_box_set_active (GTK_COMBO_BOX(w), 9);
gtk_container_add (GTK_CONTAINER (hbox), w);
g_signal_connect (w, "changed",
G_CALLBACK (palette_changed), NULL);
w = gtk_toggle_button_new_with_label("IR");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), TRUE);
gtk_container_add (GTK_CONTAINER (hbox), w);
g_signal_connect (w, "clicked",
G_CALLBACK (ircam_clicked), NULL);
w = gtk_toggle_button_new_with_label("IR");
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), TRUE);
gtk_container_add (GTK_CONTAINER (hbox), w);
g_signal_connect (w, "clicked",
G_CALLBACK (ircam_clicked), NULL);
w = gtk_toggle_button_new_with_label("Vis");
gtk_container_add (GTK_CONTAINER (hbox), w);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), FALSE);
g_signal_connect (w, "clicked",
G_CALLBACK (viscam_clicked), NULL);
w = gtk_toggle_button_new_with_label("Vis");
gtk_container_add (GTK_CONTAINER (hbox), w);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(w), FALSE);
g_signal_connect (w, "clicked",
G_CALLBACK (viscam_clicked), NULL);
// w = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL, 0.0, 1.0, .01);
w = gtk_scale_new_with_range (GTK_ORIENTATION_VERTICAL,
0.0,
1.0,
.01);
psurface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 640, 500);
//psurface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 640, 500);
psurface = cairo_image_surface_create (CAIRO_FORMAT_RGB24, 640, 500);
image_darea = gtk_drawing_area_new ();
gtk_widget_set_size_request (image_darea, 640, 500);
gtk_container_add (GTK_CONTAINER (box), image_darea);
image_darea = gtk_drawing_area_new ();
/* set a minimum size */
gtk_widget_set_size_request (image_darea, 640, 500);
g_signal_connect (image_darea, "draw",
G_CALLBACK (draw_event), NULL);
// g_signal_connect (image_darea,"configure-event",
// G_CALLBACK (configure_event), NULL);
gtk_container_add (GTK_CONTAINER (box), image_darea);
// camera-photo
w = gtk_button_new_from_icon_name("camera-photo", GTK_ICON_SIZE_DND);
gtk_container_add (GTK_CONTAINER (box), w);
g_signal_connect (image_darea, "draw",
G_CALLBACK (draw_event), NULL);
g_signal_connect (image_darea,"configure-event",
G_CALLBACK (configure_event), NULL);
g_signal_connect (w, "clicked",
G_CALLBACK (store_shot_clicked), NULL);
// camera-photo
w = gtk_button_new_from_icon_name("camera-photo", GTK_ICON_SIZE_DND);
gtk_container_add (GTK_CONTAINER (box), w);
g_signal_connect (w, "clicked",
G_CALLBACK (store_shot_clicked), NULL);
// g_timeout_add_seconds(1, handle_timeout, NULL);
gtk_widget_show_all(window);
}
gtk_widget_show_all(window);
return window;
}

View file

@ -8,4 +8,11 @@
#define PlanckR2 0.012258549
#define TempReflected 20.0 // Reflected Apparent Temperature [°C]
// 0.01 to 0.99 on the emissivity scale.
// Highly polished metallic surfaces such as copper or aluminum usually have an emissivity below 0.10.
// Roughened or oxidized metallic surfaces will have a much higher emissivity
// (0.6 or greater depending on the surface condition and the amount of oxidation).
// Most flat-finish paints are around 0.90, while human skin and water are about 0.98.
#define Emissivity 0.95 // Emissivity of object