cariboulabs-cariboulite/software/libcariboulite/src/production_utils/production_testing.c

410 wiersze
12 KiB
C

#ifndef ZF_LOG_LEVEL
#define ZF_LOG_LEVEL ZF_LOG_VERBOSE
#endif
#define ZF_LOG_DEF_SRCLOC ZF_LOG_SRCLOC_LONG
#define ZF_LOG_TAG "PRODUCTION_TESTING"
#include "zf_log/zf_log.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "io_utils/io_utils_fs.h"
#include "io_utils/io_utils.h"
#include "production_testing.h"
//===================================================================
/*void production_testing_lcd_key_callback(void* context, int key1, int key2)
{
//printf("%d, %d\n", key1, key2);
}*/
//===================================================================
/*void production_testing_powermon_callback(void* context, hat_powermon_state_st* state)
{
}*/
//===================================================================
int production_init(production_sequence_st* prod, production_test_st* tests, int num_tests, void* context)
{
memset(prod, 0, sizeof(production_sequence_st));
// init the power-monitor
if (hat_powermon_init(&prod->powermon, PROD_TESTING_PWR_MON_ADDR, /*production_testing_powermon_callback*/NULL, prod) != 0)
{
ZF_LOGE("Failed to init power monitor");
return -1;
}
hat_powermon_set_power_state(&prod->powermon, false);
if (lcd_init(&prod->lcd, /*production_testing_lcd_key_callback*/NULL, prod) != 0)
{
ZF_LOGE("LCD init failed");
return -1;
}
//lcd_set_params(&prod->lcd, 255, 190)
io_utils_get_rpi_info(&prod->tester.rpi_info);
prod->context = context;
prod->tests = tests;
prod->number_of_tests = num_tests;
prod->current_test_number = 0;
return 0;
}
//===================================================================
int production_set_git_repo(production_sequence_st* prod, char* pat, char* repo, char* dir)
{
strcpy(prod->git_pat_path, pat);
strcpy(prod->git_repo, repo);
strcpy(prod->git_res_directory, dir);
lcd_writeln(&prod->lcd, "CaribouLite Tst", "Git repo setup", true);
// read the PAT file
FILE* fid = NULL;
fid = fopen(prod->git_pat_path, "r");
if (fid == NULL)
{
ZF_LOGE("opening file '%s' for reading failed", prod->git_pat_path);
return -1;
}
char* st = fgets(prod->git_pat_user, 255, fid);
if (st == NULL)
{
ZF_LOGE("PAT file doesn't contain username");
return -1;
}
int len = strlen(prod->git_pat_user);
if (prod->git_pat_user[len-1] == '\n' || prod->git_pat_user[len-1] == '\r')
{
prod->git_pat_user[len-1] = 0;
}
st = fgets(prod->git_pat_pass, 255, fid);
if (st == NULL)
{
ZF_LOGE("PAT file doesn't contain pass");
return -1;
}
len = strlen(prod->git_pat_pass);
if (prod->git_pat_pass[len-1] == '\n' || prod->git_pat_pass[len-1] == '\r')
{
prod->git_pat_pass[len-1] = 0;
}
fclose(fid);
// create commands
sprintf(prod->git_base_command, "git --git-dir=%s/.git/ --work-tree=%s",
prod->git_res_directory,
prod->git_res_directory);
sprintf(prod->git_add_command, "%s add --all", prod->git_base_command);
sprintf(prod->git_commit_command, "%s commit -m", prod->git_base_command);
// git push https://user:pass@yourrepo.com/path HEAD
sprintf(prod->git_push_command, "%s push https://%s:%s@%s", prod->git_base_command,
prod->git_pat_user,
prod->git_pat_pass,
prod->git_repo);
sprintf(prod->git_pull_command, "%s pull https://%s:%s@%s", prod->git_base_command,
prod->git_pat_user,
prod->git_pat_pass,
prod->git_repo);
ZF_LOGI("GIT REPO PARAMETERS");
ZF_LOGI("BASE COMMAND: %s", prod->git_base_command);
ZF_LOGI("ADD COMMAND: %s", prod->git_add_command);
ZF_LOGI("COMMIT COMMAND: %s", prod->git_commit_command);
//ZF_LOGI("PUSH COMMAND: %s", prod->git_push_command);
//ZF_LOGI("PULL COMMAND: %s", prod->git_pull_command);
return 0;
}
//===================================================================
void production_git_sync_sequence(production_sequence_st* prod, char* commit_string)
{
char pull_command[1500] = {0};
char add_command[1500] = {0};
char commit_command[1700] = {0};
char push_command[1500] = {0};
char *argv_pull[64] = {0};
char *argv_add[64] = {0};
char *argv_commit[64] = {0};
char *argv_push[64] = {0};
char commit_str[256] = {0};
lcd_writeln(&prod->lcd, "CaribouLite Tst", "Git repo sync", true);
for (unsigned int i = 0; i<strlen(commit_string); i++)
{
if (commit_string[i] == ' ') commit_str[i] = '_';
else commit_str[i] = commit_string[i];
}
sprintf(pull_command, "%s", prod->git_pull_command);
sprintf(add_command, "%s", prod->git_add_command);
sprintf(commit_command, "%s '%s'", prod->git_commit_command, commit_str);
sprintf(push_command, "%s", prod->git_push_command);
lcd_writeln(&prod->lcd, "CaribouLite Tst", "Git repo pull", true);
ZF_LOGI("GIT PULL");
io_utils_parse_command(pull_command, argv_pull);
io_utils_execute_command(argv_pull);
ZF_LOGI("GIT ADD");
io_utils_parse_command(add_command, argv_add);
io_utils_execute_command(argv_add);
lcd_writeln(&prod->lcd, "CaribouLite Tst", "Git repo commit", true);
ZF_LOGI("GIT COMMIT");
io_utils_parse_command(commit_command, argv_commit);
io_utils_execute_command(argv_commit);
lcd_writeln(&prod->lcd, "CaribouLite Tst", "Git repo push", true);
ZF_LOGI("GIT PUSH");
io_utils_parse_command(push_command, argv_push);
io_utils_execute_command(argv_push);
}
//===================================================================
int production_close(production_sequence_st* prod)
{
ZF_LOGI("CLOSING LCD");
lcd_writeln(&prod->lcd, "CL TESTER", "GOODBYE!", true);
lcd_close(&prod->lcd);
ZF_LOGI("CLOSING HAT MON");
hat_powermon_set_power_state(&prod->powermon, false);
hat_powermon_release(&prod->powermon);
return 0;
}
//===================================================================
int production_rewind(production_sequence_st* prod)
{
prod->current_test_number = 0;
prod->current_tests_pass = true;
prod->operator_set_version = production_sys_version_ism;
prod->serial_number_written_and_valid = false;
prod->serial_number = 0;
prod->system_type_valid = false;
memset(prod->product_name, 0, sizeof(prod->product_name));
hat_powermon_set_power_state(&prod->powermon, false);
lcd_writeln(&prod->lcd, "TESTER", "RESTARTS...", true);
for ( prod->current_test_number = 0;
prod->current_test_number < prod->number_of_tests;
prod->current_test_number ++ )
{
production_test_st* current_test = &prod->tests[prod->current_test_number];
current_test->started = false;
current_test->finished = false;
memset (&current_test->start_time_of_test, 0, sizeof(struct tm));
memset (&current_test->end_time_of_test, 0, sizeof(struct tm));
current_test->test_result_float = 0.0;
memset(current_test->test_result_textual, 0, sizeof(current_test->test_result_textual));
current_test->test_pass = false;
}
return 0;
}
#define PROD_GET_TIME(T) {time_t time_now; time(&time_now); memcpy(&(T),gmtime(&time_now),sizeof(struct tm));}
//===================================================================
int production_start_tests(production_sequence_st* prod)
{
char line1[128], line2[128];
prod->current_tests_pass = true;
for ( prod->current_test_number = 0;
prod->current_test_number < prod->number_of_tests;
prod->current_test_number ++ )
{
production_test_st* current_test = &prod->tests[prod->current_test_number];
ZF_LOGI("Starting test No. %d ['%s']", prod->current_test_number, current_test->test_name);
sprintf(line1, "Testing [%d]", prod->current_test_number);
sprintf(line2, "%s", current_test->name_short);
lcd_writeln(&prod->lcd, line1, line2, true);
current_test->test_number = prod->current_test_number;
PROD_GET_TIME(current_test->start_time_of_test);
current_test->started = true;
if (current_test->func != NULL)
{
current_test->test_pass = current_test->func(prod->context, prod, prod->current_test_number);
sprintf(line2, "%d %s", prod->current_test_number, current_test->name_short);
lcd_writeln(&prod->lcd, line2, current_test->test_pass?"Pass":"Fail", true);
if (!current_test->test_pass)
{
ZF_LOGD("Test '%s' Failed: '%s'", current_test->test_name, current_test->test_result_textual);
prod->current_tests_pass = false;
}
}
current_test->finished = true;
PROD_GET_TIME(current_test->end_time_of_test);
ZF_LOGI("Finished test No. %d ['%s'] => %s", prod->current_test_number, current_test->test_name,
current_test->test_pass ? "PASS" : "FAIL");
if (!prod->current_tests_pass) break;
}
hat_powermon_set_power_state(&prod->powermon, false);
return prod->current_tests_pass;
}
//===================================================================
int production_generate_event_file(char* path, char* event, char* tester)
{
char filename[256] = {0};
char date1[128] = {0};
struct tm event_time;
PROD_GET_TIME(event_time);
strftime(date1, 128, "%Y_%m_%d__%H_%M_%S", &event_time);
sprintf(filename, "%s/events/%s__%s.yml", path, date1, tester);
FILE* fid = fopen(filename, "w");
if (fid == NULL)
{
ZF_LOGE("File opening failed for results generation");
return -1;
}
fprintf(fid, "%s", event);
fflush(fid);
fclose(fid);
return 0;
}
//===================================================================
int production_generate_report(production_sequence_st* prod, char* path, uint32_t serial_number)
{
uint32_t i;
char filename[256] = {0};
char date1[128] = {0};
char date[256] = {0};
lcd_writeln(&prod->lcd, "Generating", "Report", true);
strftime(date1, 128, "%Y_%m_%d__%H_%M_%S", &prod->tests[0].start_time_of_test);
strftime(date, 256, "%d/%m/%Y %H:%M:%S", &prod->tests[0].start_time_of_test);
sprintf(filename, "%s/boards/%s__%08x.yml", path, date1, serial_number);
FILE* fid = fopen(filename, "w");
if (fid == NULL)
{
ZF_LOGE("File opening failed for results generation");
return -1;
}
fprintf(fid, "version: 1\n");
fprintf(fid, "file_type: cariboulite_test_results\n");
fprintf(fid, "date: %s\n", date);
fprintf(fid, "product_name: %s\n", prod->product_name);
fprintf(fid, "rpi_serial_number: %s\n", prod->tester.rpi_info.serial_number);
fprintf(fid, "summary_test_results: %s\n", prod->current_tests_pass?"PASS":"FAIL");
fprintf(fid, "test_results:\n");
for (i = 0; i < prod->number_of_tests; i++)
{
fprintf(fid, "\t%s: \"%s\"\n", prod->tests[i].test_name, prod->tests[i].test_result_textual);
fflush(fid);
}
fclose(fid);
return 0;
}
//===================================================================
int production_wait_for_button(production_sequence_st* prod, lcd_button_en but, char* top_line, char* bottom_line)
{
int key1, key2;
lcd_writeln(&prod->lcd, top_line, bottom_line, true);
while (1)
{
io_utils_usleep(100000);
lcd_get_keys(&prod->lcd, &key1, &key2);
if (but == lcd_button_bottom && key1)
{
return 1;
}
else if (but == lcd_button_top && key2)
{
return 1;
}
}
return 0;
}
//===================================================================
int production_wait_input(production_sequence_st* prod, lcd_button_en *but, char* top_line, char* bottom_line)
{
int key1, key2;
lcd_writeln(&prod->lcd, top_line, bottom_line, true);
while (1)
{
io_utils_usleep(100000);
lcd_get_keys(&prod->lcd, &key1, &key2);
if (key1)
{
if (but) *but = lcd_button_bottom;
return 1;
}
if (key2)
{
if (but) *but = lcd_button_top;
return 1;
}
}
return 0;
}
//===================================================================
int production_monitor_power_fault(production_sequence_st* prod, bool* fault, float *i, float* v, float* p)
{
char line2[32];
if (hat_powermon_read_fault(&prod->powermon, fault) != 0)
{
//ZF_LOGI("HAT Power-Monitor reader thread finished");
return -1;
}
if (hat_powermon_read_data(&prod->powermon, i, v, p) != 0)
{
return -1;
}
sprintf(line2, "%s %.1f mA", (*fault)?"FLT":"Okay", *i);
lcd_writeln(&prod->lcd, "Power on...", line2, true);
return 0;
}