Skip to content
Snippets Groups Projects
Select Git revision
  • c89cd214b99e7e9f66a6b5d7131027300a83de97
  • stable default protected
  • MA_Pape_2018
  • MA_2018_Lopatin
  • feature/mesh_viewer
  • feature/#468_access_isosurface_scalar
  • feature/#459_default_primitives
  • master protected
  • feature/#470_Create_a_color_lookup_table
  • feature/#473_resize_companion_window
  • feature/#462_do_not_use_arb_extensions
  • feature/#495_Provide_data_for_larger_isosurfaces
  • feature/#323_default_image
  • feature/#480_Create_a_smaller_test_mesh_for_combustion_demo
  • feature/#236_Get_Integration_tests_running_on_CI
  • feature/#447_Copy_standard_assets_to_build_folder
  • 447-copy-standard-assets-to-build-folder-and-remove-resource-path
  • feature/#445_mesh_render_settings_component
  • feature/#251_Make_sure_tests_cpp_is_compiled_once
  • feature/#455_Remove_navigation_and_improve_interaction_for_combustion_demo
  • feature/446_strange_txt_files
  • v18.06.0
  • v18.05.0
  • #251_bad
  • #251_good
  • v18.03.0
  • v18.02.0
  • v18.01.0
  • v17.12.0
  • v17.11.0
  • v17.10.0
  • v17.09.0
  • v17.07.0
33 results

conanfile.py

Blame
  • main.c 12.38 KiB
    /* * Copyright (c) 2023 Carl Klemm <carl@uvos.xyz>
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without modification,
     * are permitted provided that the following conditions are met:
     *
     *  * Redistributions of source code must retain the above copyright notice, this
     * list of conditions and the following disclaimer.
     *  * Redistributions in binary form must reproduce the above copyright notice,
     * this list of conditions and the following disclaimer in the documentation and/or
     * other materials provided with the distribution.
     *  * Neither the name of %ORGANIZATION% nor the names of its contributors may be
     * used to endorse or promote products derived from this software without specific
     * prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
     * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
     * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
     * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
     * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include <stdint.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <signal.h>
    #include <time.h>
    
    #include "coincellhell/coincellhell.h"
    #include "options.h"
    #include "float.h"
    
    static void print_commands(void)
    {
    	puts("Valid commands:");
    	puts("set [HEATER] [TEMP]\t | set the temperature setpoint of the given heater");
    	puts("ramp [HEATER] [TEMP] [SECONDS] | ramp to the given temperature in given seconds");
    	puts("get [HEATER] [LOCATION]\t | get the temperature of the given heater");
    	puts("get_setpoint [HEATER]\t | get the temperature setpoint of the given heater");
    	puts("state\t\t\t | get the state of eatch heater");
    	puts("ready\t\t\t | check the ready state of all heaters");
    	puts("enable\t\t\t | enable the heaters");
    	puts("disable\t\t\t | disable the heaters");
    	puts("read [ADDRESS] [LENGTH]\t | read from the device eeprom at address");
    	puts("write [ADDRESS] [LENGTH] | write to the device eeprom at address");
    	puts("git\t\t\t | get the git revision of the firmware on the device");
    	puts("watchdog\t\t\t | enables the on device command watchdog");
    	puts("recal [BOOLEAN]\t\t | enables or disables periodic recal");
    }
    
    static int convert_string_to_heater_id(const char* str)
    {
    	char* str_end;
    	long id = strtol(str, &str_end, 10);
    	if(str == str_end || id < 0 || id > 3)
    	{
    		puts("HEATER must be a whole nummber between 0 and 3");
    		return -1;
    	}
    	return id;
    }
    
    static long convert_string_to_seconds(const char* str)
    {
    	char* str_end;
    	long seconds = strtol(str, &str_end, 10);
    	if(str == str_end || seconds < 0)
    	{
    		puts("SECONDS must be a whole nummber above 0");
    		return -1;
    	}
    	return seconds;
    }
    
    static float convert_string_to_temperature(const char* str)
    {
    	char* str_end;
    	float temperature = strtof(str, &str_end);
    	if(str == str_end || temperature < 0 || temperature > 100)
    	{
    		puts("TEMPERATURE must be a float between 0 and 100");
    		return FLT_MIN;
    	}
    	return temperature;
    }
    
    static temperature_sensor_location_t convert_string_to_location(const char* str)
    {
    	if(strcmp(str, "both") == 0)
    		return TEMP_LOCATION_BOTH;
    	if(strcmp(str, "front") == 0)
    		return TEMP_LOCATION_FRONT;
    	if(strcmp(str, "side") == 0)
    		return TEMP_LOCATION_SIDE;
    	return TEMP_LOCATION_INVALID;
    }
    
    static int process_commands(char** commands, size_t command_count, struct coincellhell* hell, char* name)
    {
    	int ret = 0;
    
    	if(strcmp(commands[0], "help") == 0)
    	{
    		print_commands();
    	}
    	else if(strcmp(commands[0], "set") == 0)
    	{
    		if(command_count < 3)
    		{
    			printf("Usage %s %s [HEATER] [TEMPERATURE]\n", name, commands[0]);
    			return 1;
    		}
    
    		int id = convert_string_to_heater_id(commands[1]);
    		if(id < 0)
    			return 1;
    
    		float temperature = convert_string_to_temperature(commands[2]);
    		if(temperature == FLT_MIN)
    			return 2;
    
    		ret = coincellhell_set_temperature(hell, id, temperature);
    	}
    	else if(strcmp(commands[0], "ramp") == 0)
    	{
    		if(command_count < 4)
    		{
    			printf("Usage %s %s [HEATER] [TEMPERATURE] [SECONDS]\n", name, commands[0]);
    			return 1;
    		}
    
    		int id = convert_string_to_heater_id(commands[1]);
    		if(id < 0)
    			return 1;
    
    		float temperature = convert_string_to_temperature(commands[2]);
    		if(temperature == FLT_MIN)
    			return 2;
    
    		long seconds = convert_string_to_seconds(commands[3]);
    		if(seconds < 0)
    			return 2;
    
    		time_t endtime = time(NULL) + seconds;
    		ret = coincellhell_set_temperature_ramp(hell, id, endtime, temperature);
    	}
    	else if(strcmp(commands[0], "get") == 0)
    	{
    		if(command_count == 1)
    		{
    			for(uint8_t i = 0; i < 4; ++i)
    			{
    				float front = 0;
    				float side = 0;
    				int err = 0;
    				err |= coincellhell_get_temperature(hell, i, TEMP_LOCATION_FRONT, &front);
    				err |= coincellhell_get_temperature(hell, i, TEMP_LOCATION_SIDE, &side);
    
    				if(!err)
    					printf("Heater %i: front temperature %f, side temperature %f, avg temperature %f\n", i, front, side, (front+side)/2);
    				else
    					printf("Heater %i: UNABLE TO READ\n", i);
    
    			}
    		}
    		else if(command_count < 3)
    		{
    			printf("Usage %s %s [HEATER] [LOCATION]\n", name, commands[0]);
    			ret = 1;
    		}
    		else
    		{
    			int id = convert_string_to_heater_id(commands[1]);
    			if(id < 0)
    				return 1;
    			temperature_sensor_location_t location = convert_string_to_location(commands[2]);
    			if(location == TEMP_LOCATION_INVALID)
    				return 2;
    
    			float temperature;
    			ret = coincellhell_get_temperature(hell, id, location, &temperature);
    			if(ret == 0)
    				printf("%f\n", temperature);
    		}
    	}
    	else if(strcmp(commands[0], "get_setpoint") == 0)
    	{
    		if(command_count == 1)
    		{
    			for(uint8_t i = 0; i < 4; ++i)
    			{
    				float setpoint = 0;
    				int err = coincellhell_get_temperature_setpoint(hell, i, &setpoint);
    				if(!err)
    					printf("Heater %i: setpoint %f\n", i, setpoint);
    				else
    					printf("Heater %i: UNABLE TO READ\n", i);
    			}
    		}
    		else
    		{
    			int id = convert_string_to_heater_id(commands[1]);
    			if(id < 0)
    				return 1;
    
    			float temperature;
    			ret = coincellhell_get_temperature_setpoint(hell, id, &temperature);
    			if(ret == 0)
    				printf("%f\n", temperature);
    		}
    	}
    	else if(strcmp(commands[0], "state") == 0)
    	{
    		for(uint8_t i = 0; i < 4; ++i)
    		{
    			struct heater_state state;
    
    			ret = coincellhell_get_state(hell, i, &state);
    			if(ret < 0)
    			{
    				puts("could not read");
    				break;
    			}
    
    			printf("Heater %d:\n\tEnabled: %s\n\tReady: %s\n\tRamp: %s\n\tFault: %s\n\tSet point: %f\n\tDAC command: %d\n",
    				   i, state.enabled ? "True" : "False", state.ready ? "True" : "False", state.ramp ? "True" : "False", state.fault ? "True" : "False",
    				   state.setpoint, state.dacCommand);
    
    			float temperature;
    			ret = coincellhell_get_temperature(hell, i, TEMP_LOCATION_BOTH, &temperature);
    			printf("\tTemperature: %f\n", temperature);
    
    			if(state.ramp)
    			{
    				printf("\tRamp Target: %f\n\tRamp Start Time: %lld\n\tRamp Stop Time: %lld\n",
    					   state.rampTarget, (long long)state.rampStartTime, (long long)state.rampStopTime);
    			}
    
    			if(state.fault)
    				printf("\tFault: %s\n", coincellhell_string_for_fault(state.faultType));
    		}
    	}
    	else if(strcmp(commands[0], "enable") == 0)
    	{
    		for(uint8_t i = 0; i < 4; ++i)
    		{
    			ret = coincellhell_set_enabled(hell, i, true);
    			if(ret < 0)
    			{
    				puts("could not read");
    				break;
    			}
    		}
    	}
    	else if(strcmp(commands[0], "disable") == 0)
    	{
    		for(uint8_t i = 0; i < 4; ++i)
    		{
    			ret = coincellhell_set_enabled(hell, i, false);
    			if(ret < 0)
    			{
    				puts("could not read");
    				break;
    			}
    		}
    	}
    	else if(strcmp(commands[0], "ready") == 0)
    	{
    		bool ready = false;
    		ret = coincellhell_check_ready(hell, &ready);
    		if(ret == 0)
    				printf("%s\n", ready ? "true" : "false");
    		else
    				puts("could not read");
    
    	}
    	else if(strcmp(commands[0], "write") == 0)
    	{
    		if(command_count < 3)
    		{
    			printf("Usage %s %s [ADDRESS] [VALUE]\n", name, commands[0]);
    			return 2;
    		}
    		long address = strtol(commands[1], NULL, 10);
    		long value = strtol(commands[2], NULL, 10);
    		if(address > UINT16_MAX || address < 0 || value < 0 || value > UINT16_MAX)
    		{
    			puts("Value or address is out of range");
    			return 2;
    		}
    		if(address % 2 == 1)
    		{
    			puts("Address must be a even number, 16 bits are written at a time");
    			return 2;
    		}
    		coincellhell_write_eeprom(hell, address, value);
    	}
    	else if(strcmp(commands[0], "read") == 0)
    	{
    		if(command_count < 2)
    		{
    			printf("Usage %s %s [ADDRESS] [LENGTH]\n", name, commands[0]);
    			return 2;
    		}
    		long address = strtol(commands[1], NULL, 10);
    		long length = 2;
    		if(command_count > 2)
    			length = strtol(commands[2], NULL, 10);
    		if(address > UINT16_MAX || address < 0 || length < 0 || length > UINT16_MAX)
    		{
    			puts("Value or address is out of range");
    			return 2;
    		}
    		if(address % 2 == 1)
    		{
    			puts("Address must be a even number, 16 bits are read at a time");
    			return 2;
    		}
    		if(length % 2 == 1)
    		{
    			puts("Length must be a even number, 16 bits are read at a time");
    			return 2;
    		}
    
    		for(uint16_t i = address; i - address < length; i+=2)
    		{
    			uint16_t value = coincellhell_read_eeprom(hell, i);
    			printf("%u: %u\n", i, value);
    		}
    	}
    	else if(strcmp(commands[0], "oscal") == 0)
    	{
    		printf("OSCAL: %u\n", coincellhell_read_oscal(hell));
    	}
    	else if(strcmp(commands[0], "seconds") == 0)
    	{
    		printf("Seconds: %u\n", coincellhell_get_seconds(hell));
    	}
    	else if(strcmp(commands[0], "git") == 0)
    	{
    		const uint8_t* rev = coincellhell_get_fw_git_revision(hell);
    		printf("Git: %x%x%x%x%x%x%x%x\n", rev[0], rev[1], rev[2], rev[3], rev[4], rev[5], rev[6], rev[7]);
    	}
    	else if(strcmp(commands[0], "watchdog") == 0)
    	{
    		ret = coincellhell_enable_watchdog(hell);
    		if(ret < 0)
    			puts("could not enable watchdog");
    	}
    	else if(strcmp(commands[0], "recal") == 0)
    	{
    		if(command_count < 2)
    		{
    			printf("Usage %s %s [BLOOEAN]\n", name, commands[0]);
    			return 2;
    		}
    
    		bool enable = strtol(commands[1], NULL, 10);
    		printf("Seting recal to %s\n", enable ? "true" : "false");
    		ret = coincellhell_set_periodic_recal(hell, enable);
    		if(ret < 0)
    			puts("could not enable watchdog");
    	}
    	else
    	{
    		printf("%s is not a valid command!", commands[0]);
    		print_commands();
    	}
    	return ret;
    }
    
    enum
    {
    	INPUT_SUCESS = 0,
    	INPUT_NO_INPUT,
    	INPUT_TOO_LONG
    };
    
    static int get_input(char *prompt, char *buffer, size_t length)
    {
    	int ch, extra;
    
    	if(prompt != NULL)
    	{
    		fputs(prompt, stdout);
    		fflush(stdout);
    	}
    	if(fgets (buffer, length, stdin) == NULL)
    		return INPUT_NO_INPUT;
    
    	if(buffer[strlen(buffer)-1] != '\n')
    	{
    		extra = 0;
    		while((ch = getchar()) != '\n' && ch != EOF)
    			extra = 1;
    		return (extra == 1) ? INPUT_TOO_LONG : INPUT_SUCESS;
    	}
    
    	buffer[strlen(buffer)-1] = '\0';
    	return INPUT_SUCESS;
    }
    
    
    int main(int argc, char* argv[])
    {
    	struct config config = {};
    	argp_parse(&argp, argc, argv, 0, 0, &config);
    
    	if(config.list_commands)
    	{
    		print_commands();
    		return 0;
    	}
    
    	if(config.command_count < 1 && !(config.interactive || config.pipe))
    	{
    		printf("A command is required\n");
    		return 2;
    	}
    	
    	struct coincellhell hell;
    	if(coincellhell_connect(&hell, config.serialSet ? config.serial : 0))
    	{
    		char serialStr[5];
    		snprintf(serialStr, sizeof(serialStr), "%04hu", config.serial);
    		printf("Can not connect to EIShell device%s%s\n",
    			   config.serialSet ? " with serial " : "", config.serialSet ? serialStr : "");
    		return 1;
    	}
    
    	int ret = 0;
    
    	if(config.interactive || config.pipe)
    	{
    		char buffer[256];
    		while(true)
    		{
    			int ret = get_input(config.pipe ? NULL : "> ", buffer, sizeof(buffer));
    			if(ret == INPUT_NO_INPUT)
    			{
    				break;
    			}
    			else if(ret != INPUT_SUCESS)
    			{
    				puts("Invalid command");
    				continue;
    			}
    
    			char* commands[MAX_COMMANDS];
    			char* command = strtok(buffer, " \t");
    			size_t i = 0;
    			while(command  && i < MAX_COMMANDS)
    			{
    				commands[i] = command;
    				command = strtok(NULL, " \t");
    				++i;
    			}
    
    			coincellhell_set_led(&hell, true);
    			int cmdRet = process_commands(commands, i, &hell, "");
    			coincellhell_set_led(&hell, false);
    			if(cmdRet == 0)
    				puts("OK");
    			else
    				printf("ERR %i\n", cmdRet);
    		}
    	}
    	else
    	{
    		ret = process_commands(config.commands, config.command_count, &hell, argv[0]);
    	}
    
    	coincellhell_disconnect(&hell);
    	return ret;
    }