inital source files
This commit is contained in:
		
							
								
								
									
										9
									
								
								software/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								software/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,9 @@ | ||||
|  | ||||
| set(EXTRA_COMPONENT_DIRS $ENV{ESP_IDF_LIB_PATH}/components) | ||||
|  | ||||
| # The following lines of boilerplate have to be in your project's CMakeLists | ||||
| # in this exact order for cmake to work correctly | ||||
| cmake_minimum_required(VERSION 3.16) | ||||
|  | ||||
| include($ENV{IDF_PATH}/tools/cmake/project.cmake) | ||||
| project(smart-oil-heating-control-system) | ||||
							
								
								
									
										7
									
								
								software/main/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								software/main/CMakeLists.txt
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| idf_component_register(SRCS "main.c" | ||||
|                             "http_metrics.c" | ||||
|                             "inputs.c" | ||||
|                             "outputs.c" | ||||
|                             "control.c" | ||||
|                             "safety.c" | ||||
|                     INCLUDE_DIRS ".") | ||||
							
								
								
									
										19
									
								
								software/main/Kconfig.projbuild
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								software/main/Kconfig.projbuild
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,19 @@ | ||||
| menu "Smart Oil Heating Control System" | ||||
|  | ||||
|     config SSID | ||||
|         string "SSID" | ||||
|         default "my WiFi SSID" | ||||
|     config WIFI_PASSWORD | ||||
|         string "WIFI_PASSWORD" | ||||
|         default "my WIFI Password" | ||||
|     config STATIC_IP_ADDR | ||||
|         string "Static IPv4 address" | ||||
|         default "192.168.0.42" | ||||
|     config STATIC_IP_NETMASK | ||||
|         string "Static IPv4 netmask" | ||||
|         default "255.255.0.0" | ||||
|     config STATIC_GATEWAY_IP_ADDR | ||||
|         string "Static IPv4 gateway address" | ||||
|         default "192.168.0.1" | ||||
|  | ||||
| endmenu | ||||
							
								
								
									
										0
									
								
								software/main/control.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/control.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								software/main/control.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/control.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										154
									
								
								software/main/http_metrics.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								software/main/http_metrics.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,154 @@ | ||||
| #include "http_metrics.h" | ||||
|  | ||||
| static EventGroupHandle_t s_wifi_event_group; | ||||
|  | ||||
| static const char *TAG = "esp32-env-exp-http_metrics"; | ||||
|  | ||||
| char caHtmlResponse[HTML_RESPONSE_SIZE]; | ||||
| SemaphoreHandle_t xMutexAccessMetricResponse = NULL; | ||||
|  | ||||
| void vSetMetrics(sMetric* paMetrics, uint16_t u16Size) { | ||||
|  | ||||
|     if( xSemaphoreTake( xMutexAccessMetricResponse, ( TickType_t ) 100 ) == pdTRUE ) | ||||
|     { | ||||
|         memset(caHtmlResponse,0,strlen(caHtmlResponse)); | ||||
|         for(uint16_t u16Index = 0U; u16Index < u16Size; u16Index++) { | ||||
|             char caValueBuffer[64]; | ||||
|             sprintf(caValueBuffer, " %f", paMetrics[u16Index].fMetricValue); | ||||
|             //printf("%s\n", caValueBuffer); | ||||
|             strcat(caHtmlResponse, paMetrics[u16Index].caMetricName); | ||||
|             strcat(caHtmlResponse, caValueBuffer); | ||||
|             strcat(caHtmlResponse, "\n"); | ||||
|         } | ||||
|         xSemaphoreGive( xMutexAccessMetricResponse ); | ||||
|     } else { | ||||
|         ESP_LOGI(TAG, "[SET] Unable to obtain mutex for metric response"); | ||||
|     } | ||||
| } | ||||
|  | ||||
| static void event_handler(void *arg, esp_event_base_t event_base, | ||||
|                           int32_t event_id, void *event_data) | ||||
| { | ||||
|     if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) | ||||
|     { | ||||
|         esp_wifi_connect(); | ||||
|     } | ||||
|     else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) | ||||
|     { | ||||
|         esp_wifi_connect(); | ||||
|         ESP_LOGI(TAG, "Retry to connect to the AP"); | ||||
|     } | ||||
|     else if (event_base == IP_EVENT && event_id == IP_EVENT_STA_GOT_IP) | ||||
|     { | ||||
|         ip_event_got_ip_t *event = (ip_event_got_ip_t *)event_data; | ||||
|         ESP_LOGI(TAG, "Got ip:" IPSTR, IP2STR(&event->ip_info.ip)); | ||||
|         xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void connect_wifi(void) | ||||
| { | ||||
|     s_wifi_event_group = xEventGroupCreate(); | ||||
|     ESP_ERROR_CHECK(esp_netif_init()); | ||||
|     ESP_ERROR_CHECK(esp_event_loop_create_default()); | ||||
|  | ||||
|     esp_netif_t *my_sta = esp_netif_create_default_wifi_sta(); | ||||
|     esp_netif_dhcpc_stop(my_sta); | ||||
|     esp_netif_ip_info_t ip_info; | ||||
|     ip_info.ip.addr = ipaddr_addr(CONFIG_STATIC_IP_ADDR); | ||||
|    	ip_info.gw.addr = ipaddr_addr(CONFIG_STATIC_GATEWAY_IP_ADDR); | ||||
|    	ip_info.netmask.addr = ipaddr_addr(CONFIG_STATIC_IP_NETMASK); | ||||
|     esp_netif_set_ip_info(my_sta, &ip_info); | ||||
|      | ||||
|     wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT(); | ||||
|     ESP_ERROR_CHECK(esp_wifi_init(&cfg)); | ||||
|     esp_event_handler_instance_t instance_any_id; | ||||
|     esp_event_handler_instance_t instance_got_ip; | ||||
|     ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT, | ||||
|                     ESP_EVENT_ANY_ID, | ||||
|                     &event_handler, | ||||
|                     NULL, | ||||
|                     &instance_any_id)); | ||||
|     ESP_ERROR_CHECK(esp_event_handler_instance_register(IP_EVENT, | ||||
|                     IP_EVENT_STA_GOT_IP, | ||||
|                     &event_handler, | ||||
|                     NULL, | ||||
|                     &instance_got_ip)); | ||||
|  | ||||
|     wifi_config_t wifi_config = { | ||||
|         .sta = { | ||||
|             .ssid = CONFIG_SSID, | ||||
|             .password = CONFIG_WIFI_PASSWORD, | ||||
|             .threshold.authmode = WIFI_AUTH_WPA2_PSK, | ||||
|         }, | ||||
|     }; | ||||
|     ESP_ERROR_CHECK(esp_wifi_set_mode(WIFI_MODE_STA)); | ||||
|     ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_STA, &wifi_config)); | ||||
|     ESP_ERROR_CHECK(esp_wifi_start()); | ||||
|  | ||||
|     ESP_LOGI(TAG, "wifi_init_sta finished."); | ||||
|  | ||||
|     EventBits_t bits = xEventGroupWaitBits(s_wifi_event_group, | ||||
|                                            WIFI_CONNECTED_BIT | WIFI_FAIL_BIT, | ||||
|                                            pdFALSE, | ||||
|                                            pdFALSE, | ||||
|                                            portMAX_DELAY); | ||||
|  | ||||
|     if (bits & WIFI_CONNECTED_BIT) | ||||
|     { | ||||
|         ESP_LOGI(TAG, "Connected to ap SSID:%s", CONFIG_SSID); | ||||
|     } | ||||
|     else if (bits & WIFI_FAIL_BIT) | ||||
|     { | ||||
|         ESP_LOGI(TAG, "Failed to connect to SSID:%s", CONFIG_SSID); | ||||
|     } | ||||
|     else | ||||
|     { | ||||
|         ESP_LOGE(TAG, "Unexpected event"); | ||||
|     } | ||||
|     vEventGroupDelete(s_wifi_event_group); | ||||
| } | ||||
|  | ||||
| esp_err_t get_metrics_handler(httpd_req_t *req) | ||||
| { | ||||
|     if( xSemaphoreTake( xMutexAccessMetricResponse, ( TickType_t ) 100 ) == pdTRUE ) | ||||
|     { | ||||
|         esp_err_t err =  httpd_resp_send(req, caHtmlResponse, HTTPD_RESP_USE_STRLEN); | ||||
|         xSemaphoreGive( xMutexAccessMetricResponse ); | ||||
|         return err; | ||||
|     } else | ||||
|     { | ||||
|         ESP_LOGI(TAG, "[GET] Unable to obtain mutex for metric response"); | ||||
|         return httpd_resp_send(req, 0, 0); | ||||
|     } | ||||
| } | ||||
|  | ||||
| httpd_uri_t uri_get = { | ||||
|     .uri = "/metrics", | ||||
|     .method = HTTP_GET, | ||||
|     .handler = get_metrics_handler, | ||||
|     .user_ctx = NULL | ||||
| }; | ||||
|  | ||||
| httpd_handle_t setup_server(void) | ||||
| { | ||||
|     httpd_config_t config = HTTPD_DEFAULT_CONFIG(); | ||||
|     config.server_port = 9100; | ||||
|     httpd_handle_t server = NULL; | ||||
|  | ||||
|  | ||||
|     xMutexAccessMetricResponse = xSemaphoreCreateBinary(); | ||||
|     if(xMutexAccessMetricResponse == NULL) { | ||||
|         ESP_LOGE(TAG, "Unable to create mutex for metric response"); | ||||
|         vTaskDelay(pdMS_TO_TICKS(300*60)); //wait 5min before restart | ||||
|         esp_restart(); | ||||
|     } | ||||
|     xSemaphoreGive( xMutexAccessMetricResponse ); | ||||
|  | ||||
|     if (httpd_start(&server, &config) == ESP_OK) | ||||
|     { | ||||
|         httpd_register_uri_handler(server, &uri_get); | ||||
|     } | ||||
|  | ||||
|     return server; | ||||
| } | ||||
							
								
								
									
										40
									
								
								software/main/http_metrics.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								software/main/http_metrics.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,40 @@ | ||||
| #ifndef H_HTTPS_METRICS | ||||
| #define H_HTTPS_METRICS | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include "freertos/FreeRTOS.h" | ||||
| #include "freertos/task.h" | ||||
| #include "esp_system.h" | ||||
| #include "spi_flash_mmap.h" | ||||
| #include <esp_http_server.h> | ||||
|  | ||||
| #include "esp_wifi.h" | ||||
| #include "esp_event.h" | ||||
| #include "freertos/event_groups.h" | ||||
| #include "esp_log.h" | ||||
| #include "nvs_flash.h" | ||||
| #include "esp_netif.h" | ||||
| #include <lwip/sockets.h> | ||||
| #include <lwip/sys.h> | ||||
| #include <lwip/api.h> | ||||
| #include <lwip/netdb.h> | ||||
|  | ||||
| #define WIFI_CONNECTED_BIT BIT0 | ||||
| #define WIFI_FAIL_BIT BIT1 | ||||
| #define HTML_RESPONSE_SIZE 256U | ||||
| #define METRIC_NAME_MAX_SIZE 64U | ||||
| #define METRIC_MAX_COUNT 32U | ||||
|  | ||||
| typedef struct _metric { | ||||
|     char caMetricName[METRIC_NAME_MAX_SIZE]; | ||||
|     float fMetricValue; | ||||
| } sMetric; | ||||
|  | ||||
|  | ||||
| void connect_wifi(void); | ||||
| httpd_handle_t setup_server(void); | ||||
| void vSetMetrics(sMetric* paMetrics, uint16_t u16Size); | ||||
|  | ||||
| #endif /* H_HTTPS_METRICS */ | ||||
							
								
								
									
										0
									
								
								software/main/inputs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/inputs.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								software/main/inputs.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/inputs.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										181
									
								
								software/main/main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								software/main/main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,181 @@ | ||||
| #include <stdio.h> | ||||
| #include "esp_log.h" | ||||
| #include "driver/i2c.h" | ||||
| #include <esp_system.h> | ||||
| #include <bmp280.h> | ||||
| #include <dht.h> | ||||
| #include <aht.h> | ||||
| #include <veml7700.h> | ||||
| #include <string.h> | ||||
| #include <freertos/FreeRTOS.h> | ||||
| #include <freertos/task.h> | ||||
| #include "freertos/timers.h" | ||||
|  | ||||
| #include "http_metrics.h" | ||||
|  | ||||
| #define I2C_MASTER_SCL 19 | ||||
| #define I2C_MASTER_SDA 18 | ||||
|  | ||||
| #define BMP280 | ||||
| #define DHT11 | ||||
| //#define AHT10 | ||||
| //#define VEML7700 | ||||
|  | ||||
| #ifdef DHT11 | ||||
| #define CONFIG_EXAMPLE_DATA_GPIO 17 | ||||
| #define SENSOR_TYPE DHT_TYPE_DHT11 | ||||
| #endif | ||||
|  | ||||
| #ifdef AHT10 | ||||
| #define AHT_TYPE AHT_TYPE_AHT1x | ||||
| #endif | ||||
|  | ||||
| static const char *TAG = "smart-oil-heater-control-system"; | ||||
|  | ||||
| void app_main(void) | ||||
| { | ||||
|     ESP_LOGI(TAG, "starting ..."); | ||||
|  | ||||
|     //Initialize NVS | ||||
|     esp_err_t ret = nvs_flash_init(); | ||||
|     if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) | ||||
|     { | ||||
|         ESP_ERROR_CHECK(nvs_flash_erase()); | ||||
|         ret = nvs_flash_init(); | ||||
|     } | ||||
|     ESP_ERROR_CHECK(ret); | ||||
|  | ||||
|     connect_wifi(); //will return if successful | ||||
|     setup_server(); | ||||
|  | ||||
|     sMetric aMetrics[METRIC_MAX_COUNT]; | ||||
|  | ||||
|     /*Sensor Init*/ | ||||
|     ESP_ERROR_CHECK(i2cdev_init()); | ||||
|  | ||||
| #ifdef BMP280 | ||||
|     bmp280_params_t params; | ||||
|     bmp280_init_default_params(¶ms); | ||||
|     bmp280_t devBMP280; | ||||
|     memset(&devBMP280, 0, sizeof(bmp280_t)); | ||||
|     ESP_ERROR_CHECK(bmp280_init_desc(&devBMP280, BMP280_I2C_ADDRESS_0, 0, I2C_MASTER_SDA, I2C_MASTER_SCL)); | ||||
|     ESP_ERROR_CHECK(bmp280_init(&devBMP280, ¶ms)); | ||||
|     bool bme280p = devBMP280.id == BME280_CHIP_ID; | ||||
|     ESP_LOGI(TAG, "BMP280: found %s\n", bme280p ? "BME280" : "BMP280"); | ||||
| #endif | ||||
|  | ||||
| #ifdef AHT10 | ||||
|     aht_t devAHT10 = {0}; | ||||
|     devAHT10.mode = AHT_MODE_NORMAL; | ||||
|     devAHT10.type = AHT_TYPE; | ||||
|     ESP_ERROR_CHECK(aht_init_desc(&devAHT10, AHT_I2C_ADDRESS_GND, 0, I2C_MASTER_SDA, I2C_MASTER_SCL)); | ||||
|     ESP_ERROR_CHECK(aht_init(&devAHT10)); | ||||
| #endif | ||||
|  | ||||
| #ifdef VEML7700 | ||||
|     i2c_dev_t veml7700_device; | ||||
|     veml7700_config_t veml7700_configuration; | ||||
|      | ||||
|     memset(&veml7700_device, 0, sizeof(i2c_dev_t)); | ||||
|     memset(&veml7700_configuration, 0, sizeof(veml7700_config_t)); | ||||
|  | ||||
|     // initialize the device struct | ||||
|     ESP_ERROR_CHECK(veml7700_init_desc(&veml7700_device, I2C_NUM_0, I2C_MASTER_SDA, I2C_MASTER_SCL)); | ||||
|  | ||||
|     // check if the device is available | ||||
|     ESP_ERROR_CHECK(veml7700_probe(&veml7700_device)); | ||||
|  | ||||
|     /* set configuration parameters | ||||
|      * select gain 1/8 coastest resolution but the sensor will most likely not | ||||
|      * over-saturated | ||||
|      */ | ||||
|     veml7700_configuration.gain = VEML7700_GAIN_DIV_8; | ||||
|  | ||||
|     /* set the time to integrate the light values. more time will lead to a finer | ||||
|      * resolution but will be over-saturated earlier | ||||
|      */ | ||||
|     veml7700_configuration.integration_time = VEML7700_INTEGRATION_TIME_100MS; | ||||
|  | ||||
|     // interrupt is not used | ||||
|     veml7700_configuration.persistence_protect = VEML7700_PERSISTENCE_PROTECTION_4; | ||||
|     veml7700_configuration.interrupt_enable = 1; | ||||
|     veml7700_configuration.shutdown = 0; | ||||
|  | ||||
|     // write the configuration to the device | ||||
|     ESP_ERROR_CHECK(veml7700_set_config(&veml7700_device, &veml7700_configuration)); | ||||
|  | ||||
| #endif | ||||
|  | ||||
|     ESP_LOGI(TAG, "running"); | ||||
|  | ||||
|     while (1) | ||||
|     { | ||||
|         vTaskDelay(pdMS_TO_TICKS(5000)); | ||||
|         uint16_t u16MetricCounter = 0U; | ||||
|  | ||||
|         /*Wifi RSSI*/ | ||||
|         wifi_ap_record_t ap; | ||||
|         esp_wifi_sta_get_ap_info(&ap); | ||||
|         printf("WiFi RSSI: %d\n", ap.rssi); | ||||
|         strcpy(aMetrics[u16MetricCounter].caMetricName, "wifi_rssi"); | ||||
|         aMetrics[0].fMetricValue = ap.rssi; | ||||
|         u16MetricCounter++; | ||||
|  | ||||
| #ifdef BMP280 | ||||
|         if ((bmp280_read_float(&devBMP280, &aMetrics[u16MetricCounter].fMetricValue, &aMetrics[u16MetricCounter+1].fMetricValue, 0) == ESP_OK)) | ||||
|         { | ||||
|             strcpy(aMetrics[u16MetricCounter].caMetricName, "bmp280_temperature"); | ||||
|             strcpy(aMetrics[u16MetricCounter+1].caMetricName, "bmp280_pressure"); | ||||
|             printf("(BMP280) Temperature: %.2f C, Pressure: %.2f Pa\n", aMetrics[u16MetricCounter].fMetricValue, aMetrics[u16MetricCounter+1].fMetricValue); | ||||
|             u16MetricCounter++; | ||||
|             u16MetricCounter++; | ||||
|         } else { | ||||
|             printf("(BMP280) Temperature/pressure reading failed\n"); | ||||
|         } | ||||
| #endif | ||||
|  | ||||
| #ifdef AHT10 | ||||
|         if ((aht_get_data(&devAHT10, &aMetrics[u16MetricCounter].fMetricValue, &aMetrics[u16MetricCounter+1].fMetricValue) == ESP_OK)) | ||||
|         { | ||||
|             strcpy(aMetrics[u16MetricCounter].caMetricName, "aht10_temperature"); | ||||
|             strcpy(aMetrics[u16MetricCounter+1].caMetricName, "aht10_humidity"); | ||||
|             printf("(AHT10) Temperature: %.2f C, Humidity: %.2f %% \n", aMetrics[u16MetricCounter].fMetricValue, aMetrics[u16MetricCounter+1].fMetricValue); | ||||
|             u16MetricCounter++; | ||||
|             u16MetricCounter++; | ||||
|         } else { | ||||
|             printf("(AHT10) Temperature/Humidity reading failed\n"); | ||||
|         } | ||||
| #endif | ||||
|  | ||||
| #ifdef DHT11 | ||||
|         if ((dht_read_float_data(SENSOR_TYPE, CONFIG_EXAMPLE_DATA_GPIO, &aMetrics[u16MetricCounter].fMetricValue, &aMetrics[u16MetricCounter+1].fMetricValue) == ESP_OK)) | ||||
|         { | ||||
|             strcpy(aMetrics[u16MetricCounter].caMetricName, "dht11_humidity"); | ||||
|             strcpy(aMetrics[u16MetricCounter+1].caMetricName, "dht11_temperature"); | ||||
|             printf("(DHT11) Humidity: %.2f %%, Temperature: %.2f C\n", aMetrics[u16MetricCounter].fMetricValue, aMetrics[u16MetricCounter+1].fMetricValue); | ||||
|             u16MetricCounter++; | ||||
|             u16MetricCounter++; | ||||
|         } else { | ||||
|             printf("(DHT11) Temperature/pressure reading failed\n"); | ||||
|         } | ||||
| #endif | ||||
|  | ||||
| #ifdef VEML7700 | ||||
|     uint32_t u32AmbientLight = 0U; | ||||
|     uint32_t u32WhiteChannel = 0U; | ||||
|     if ((veml7700_get_ambient_light(&veml7700_device, &veml7700_configuration, &u32AmbientLight) == ESP_OK) && (veml7700_get_white_channel(&veml7700_device, &veml7700_configuration, &u32WhiteChannel) == ESP_OK)) | ||||
|         { | ||||
|             aMetrics[u16MetricCounter].fMetricValue = u32AmbientLight; | ||||
|             aMetrics[u16MetricCounter+1].fMetricValue = u32WhiteChannel; | ||||
|             strcpy(aMetrics[u16MetricCounter].caMetricName, "veml7700_ambient_light"); | ||||
|             strcpy(aMetrics[u16MetricCounter+1].caMetricName, "veml7700_white_channel"); | ||||
|             printf("(VEML7700) Ambient light: %.2f lux, White channel: %.2f lux\n", aMetrics[u16MetricCounter].fMetricValue, aMetrics[u16MetricCounter+1].fMetricValue); | ||||
|             u16MetricCounter++; | ||||
|             u16MetricCounter++; | ||||
|         } else { | ||||
|             printf("(VEML7700)  light reading failed\n"); | ||||
|         } | ||||
| #endif | ||||
|         vSetMetrics(aMetrics, u16MetricCounter); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										0
									
								
								software/main/output.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/output.h
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								software/main/outputs.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/outputs.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								software/main/safety.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/safety.c
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										0
									
								
								software/main/safety.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								software/main/safety.h
									
									
									
									
									
										Normal file
									
								
							
		Reference in New Issue
	
	Block a user