cariboulabs-cariboulite/software/libcariboulite/src/cariboulite_production.c

1076 wiersze
36 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 "CARIBOULITE Prod"
#include "zf_log/zf_log.h"
//=================================================
// INTERNAL INCLUDES
#include "production_utils/production_testing.h"
#include "cariboulite_setup.h"
#include "cariboulite_radio.h"
#include "cariboulite_events.h"
#include "cariboulite.h"
#include "hat/hat.h"
#include "cariboulite_dtbo.h"
#include "production_utils/production_utils.h"
#include "io_utils/io_utils_sys_info.h"
//=================================================
// EXTERNAL INCLUDES
#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <unistd.h>
//=================================================
// FLOW MANAGEMENT
CARIBOULITE_CONFIG_DEFAULT(cariboulite_sys);
//=================================================
hat_st hat =
{
.vendor_name = "CaribouLabs LTD",
.product_name = "CaribouLite RPI Hat",
.product_id = system_type_cariboulite_full,
.product_version = 0x01,
.device_tree_buffer = cariboulite_dtbo,
.device_tree_buffer_size = sizeof(cariboulite_dtbo),
.dev = {
.i2c_address = 0x50, // the i2c address of the eeprom chip
.eeprom_type = eeprom_type_24c32,
},
};
//=================================================
int stop_program ()
{
ZF_LOGD("program termination requested");
return 0;
}
//=================================================
void sighandler( struct sys_st_t *sys,
void* context,
int signal_number,
siginfo_t *si)
{
switch (signal_number)
{
case SIGINT:
case SIGTERM:
case SIGABRT:
case SIGILL:
case SIGSEGV:
case SIGFPE: stop_program (); break;
default: return; break;
}
}
//================================================================
//================================================================
//================================================================
// TEST TYPES
typedef enum
{
cariboulite_test_en_current_system = 0,
cariboulite_test_en_fpga_programming,
cariboulite_test_en_fpga_communication,
cariboulite_test_en_fpga_id_resistors,
cariboulite_test_en_fpga_reset,
cariboulite_test_en_fpga_switch,
cariboulite_test_en_fpga_leds,
cariboulite_test_en_fpga_smi,
cariboulite_test_en_rpi_id_eeprom,
cariboulite_test_en_mixer_communication,
cariboulite_test_en_mixer_versions,
cariboulite_test_en_modem_communication,
cariboulite_test_en_modem_versions,
cariboulite_test_en_modem_leds,
cariboulite_test_en_modem_interrupt,
cariboulite_test_en_current_modem_rx,
cariboulite_test_en_current_modem_tx,
cariboulite_test_en_system_smi_data,
cariboulite_test_en_system_rf_loopback,
cariboulite_test_en_system_rf_tx_power,
cariboulite_test_en_max,
} cariboulite_test_en;
//================================================================
// TEST FUNCTIONS
static int cariboulite_test_hat_eeprom(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_programming(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_communication(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_id_resistors(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_soft_reset(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_switch(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_leds(void* context, void* test_context, int test_num);
static int cariboulite_test_fpga_smi(void* context, void* test_context, int test_num);
static int cariboulite_test_mixer_communication(void* context, void* test_context, int test_num);
static int cariboulite_test_mixer_versions(void* context, void* test_context, int test_num);
static int cariboulite_test_modem_communication(void* context, void* test_context, int test_num);
static int cariboulite_test_modem_version(void* context, void* test_context, int test_num);
static int cariboulite_test_modem_leds(void* context, void* test_context, int test_num);
static int cariboulite_test_modem_interrupt(void* context, void* test_context, int test_num);
static int cariboulite_test_current_system(void* context, void* test_context, int test_num);
static int cariboulite_test_current_modem_rx(void* context, void* test_context, int test_num);
static int cariboulite_test_current_modem_tx(void* context, void* test_context, int test_num);
static int cariboulite_test_smi_data(void* context, void* test_context, int test_num);
static int cariboulite_test_rf_loopback(void* context, void* test_context, int test_num);
static int cariboulite_test_rf_tx_power(void* context, void* test_context, int test_num);
//================================================================
// TEST DEFINITIONS
production_test_st tests[] =
{
{.name_short = "CURR. SYS", .test_name = "current_system", .group = 4, .test_number = cariboulite_test_en_current_system, .func = cariboulite_test_current_system, },
{.name_short = "FPGA PROG", .test_name = "fpga_programming", .group = 1, .test_number = cariboulite_test_en_fpga_programming, .func = cariboulite_test_fpga_programming, },
{.name_short = "FPGA COMM", .test_name = "fpga_communication", .group = 1, .test_number = cariboulite_test_en_fpga_communication, .func = cariboulite_test_fpga_communication, },
{.name_short = "FPGA IDRES", .test_name = "fpga_id_resistors", .group = 1, .test_number = cariboulite_test_en_fpga_id_resistors, .func = cariboulite_test_fpga_id_resistors, },
{.name_short = "FPGA SFTRST", .test_name = "fpga_soft_reset", .group = 1, .test_number = cariboulite_test_en_fpga_reset, .func = cariboulite_test_fpga_soft_reset, },
{.name_short = "FPGA SWTCH", .test_name = "fpga_switch", .group = 1, .test_number = cariboulite_test_en_fpga_switch, .func = cariboulite_test_fpga_switch, },
{.name_short = "FPGA LEDS", .test_name = "fpga_leds", .group = 1, .test_number = cariboulite_test_en_fpga_leds, .func = cariboulite_test_fpga_leds, },
{.name_short = "FPGA SMI", .test_name = "fpga_smi", .group = 1, .test_number = cariboulite_test_en_fpga_smi, .func = cariboulite_test_fpga_smi, },
{.name_short = "EEPROM", .test_name = "hat_eeprom", .group = 0, .test_number = cariboulite_test_en_rpi_id_eeprom, .func = cariboulite_test_hat_eeprom, },
{.name_short = "MXR COMM", .test_name = "mixer_communication", .group = 2, .test_number = cariboulite_test_en_mixer_communication, .func = cariboulite_test_mixer_communication, },
{.name_short = "MXR VER", .test_name = "mixer_version_id", .group = 2, .test_number = cariboulite_test_en_mixer_versions, .func = cariboulite_test_mixer_versions, },
{.name_short = "MDM COMM", .test_name = "modem_communication", .group = 3, .test_number = cariboulite_test_en_modem_communication, .func = cariboulite_test_modem_communication, },
{.name_short = "MDM VER", .test_name = "modem_version", .group = 3, .test_number = cariboulite_test_en_modem_versions, .func = cariboulite_test_modem_version, },
{.name_short = "MDM LED", .test_name = "modem_leds", .group = 3, .test_number = cariboulite_test_en_modem_leds, .func = cariboulite_test_modem_leds, },
{.name_short = "MDM INT", .test_name = "modem_interrupt", .group = 3, .test_number = cariboulite_test_en_modem_interrupt, .func = cariboulite_test_modem_interrupt, },
{.name_short = "CURR. RX", .test_name = "current_modem_rx", .group = 4, .test_number = cariboulite_test_en_current_modem_rx, .func = cariboulite_test_current_modem_rx, },
{.name_short = "CURR. TX", .test_name = "current_modem_tx", .group = 4, .test_number = cariboulite_test_en_current_modem_tx, .func = cariboulite_test_current_modem_tx, },
{.name_short = "SMI DATA", .test_name = "system_smi_data", .group = 5, .test_number = cariboulite_test_en_system_smi_data, .func = cariboulite_test_smi_data, },
{.name_short = "RF LB", .test_name = "system_rf_loopback", .group = 5, .test_number = cariboulite_test_en_system_rf_loopback, .func = cariboulite_test_rf_loopback, },
{.name_short = "RF TXPWR", .test_name = "system_rf_tx_power", .group = 5, .test_number = cariboulite_test_en_system_rf_tx_power, .func = cariboulite_test_rf_tx_power, },
};
#define NUM_OF_TESTS (sizeof(tests)/sizeof(production_test_st))
//=================================================
int cariboulite_test_current_system(void *context, void* test_context, int test_num)
{
int k;
bool fault = false;
float current_ma = 0.0f, voltage_mv = 0.0f, power_mw = 0.0f;
float average_current = 0.0;
bool pass = true;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
caribou_fpga_hard_reset_keep(&sys->fpga, true);
//lcd_writeln(&prod.lcd, "Power on...", "", true);
hat_powermon_set_power_state(&prod->powermon, true);
io_utils_usleep(400000);
for (k = 0; k < 20; k++)
{
io_utils_usleep(100000);
production_monitor_power_fault(prod, &fault, &current_ma, &voltage_mv, &power_mw);
average_current += current_ma;
}
average_current /= (float)(k);
if (fault || average_current > 220.0f || voltage_mv < 2500.0f || current_ma < 10.0f)
{
tests[test_num].test_result_float = average_current;
sprintf(tests[test_num].test_result_textual, "Wrong current %.1f mA, low voltage (%.1f mV), fault: %d", average_current, voltage_mv, fault);
pass = false;
hat_powermon_set_power_state(&prod->powermon, false);
}
else
{
tests[test_num].test_result_float = average_current;
sprintf(tests[test_num].test_result_textual, "Pass - idle current - %.1f mA", average_current);
pass = true;
}
return pass;
}
//=================================================
int cariboulite_test_fpga_programming(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
ZF_LOGD("Programming FPGA");
if (cariboulite_configure_fpga (sys, cariboulite_firmware_source_blob, NULL/*sys->firmware_path_operational*/) < 0)
{
ZF_LOGE("FPGA programming failed");
caribou_fpga_close(&sys->fpga);
sprintf(tests[test_num].test_result_textual, "FPGA programming failed");
tests[test_num].test_result_float = -1;
return false;
}
sys->system_status = sys_status_minimal_init;
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_fpga_communication(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
caribou_fpga_versions_st vers = {0};
caribou_fpga_get_versions (&sys->fpga, &vers);
if (vers.sys_ver == 1 && vers.sys_manu_id == 1 && vers.sys_ctrl_mod_ver == 1
&& vers.io_ctrl_mod_ver == 1 && vers.smi_ctrl_mod_ver == 1)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
}
else
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual,
"Fail - sys_ver: %02X, sys_manu_id: %02X, sys_ctrl_mod_ver: %02X, io_ctrl_mod_ver: %02X, smi_ctrl_mod_ver: %02X",
vers.sys_ver, vers.sys_manu_id, vers.sys_ctrl_mod_ver, vers.io_ctrl_mod_ver, vers.smi_ctrl_mod_ver);
tests[test_num].test_pass = true;
}
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_fpga_id_resistors(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
// Reading the configuration from the FPGA (resistor set)
int led0 = 0, led1 = 0, btn = 0, cfg = 0;
caribou_fpga_get_io_ctrl_dig (&sys->fpga, &led0, &led1, &btn, &cfg);
ZF_LOGD("FPGA Digital Values: led0: %d, led1: %d, btn: %d, CFG[0..3]: [%d,%d,%d,%d]",
led0, led1, btn, (cfg >> 0) & 0x1, (cfg >> 1) & 0x1, (cfg >> 2) & 0x1, (cfg >> 3) & 0x1);
sys->fpga_config_resistor_state = cfg;
// 0xf = full, 0xe = ism
if (sys->fpga_config_resistor_state != 0xF && sys->fpga_config_resistor_state != 0xE)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Failed - unrecognized fpga id resistor config %01X (check R38, R39, R40, R41)", cfg);
tests[test_num].test_pass = false;
}
else
{
sys->sys_type = (cfg == 0xF) ? system_type_cariboulite_full : system_type_cariboulite_ism;
ZF_LOGD("System detected: %s, Operator set: %s", (sys->sys_type == system_type_cariboulite_full) ? "CaribouFull" : "CaribouISM",
(prod->operator_set_version == production_sys_version_ism) ? "CaribouISM" : "CaribouFull");
// mismatch
if (((prod->operator_set_version == production_sys_version_ism) && (sys->sys_type == system_type_cariboulite_full)) ||
((prod->operator_set_version == production_sys_version_full) && (sys->sys_type == system_type_cariboulite_ism)))
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Failed - version mismatch - detected %s, but operator set %s",
(cfg == 0xF) ? "CaribouFull" : "CaribouISM",
(prod->operator_set_version == production_sys_version_ism) ? "CaribouISM" : "CaribouFull");
tests[test_num].test_pass = false;
}
else
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass - detected %s", (cfg == 0xF) ? "CaribouFull" : "CaribouISM");
tests[test_num].test_pass = true;
prod->system_type_valid = true;
sprintf(prod->product_name, "%s", (cfg == 0xF) ? "CaribouFull" : "CaribouISM");
}
}
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_fpga_soft_reset(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
caribou_fpga_soft_reset(&sys->fpga);
return cariboulite_test_fpga_communication(context, test_context, cariboulite_test_en_fpga_reset);
}
//=================================================
int cariboulite_test_fpga_switch(void *context, void* test_context, int test_num)
{
bool pass = false;
int key1 = 0;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
lcd_writeln(&prod->lcd, "PRESS CARIBU SW", "<= OR CLICK FAIL", true);
int led0 = 0, led1 = 0, btn = 0, cfg = 0;
while (1)
{
io_utils_usleep(300000);
caribou_fpga_get_io_ctrl_dig (&sys->fpga, &led0, &led1, &btn, &cfg);
if (btn == 0)
{
pass = true;
break;
}
lcd_get_keys(&prod->lcd, &key1, NULL);
if (key1)
{
pass = false;
break;
}
}
if (pass)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
}
else
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail - didn't detect switch press - aborted by operator. Check switch assembly (S1)");
tests[test_num].test_pass = false;
}
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_fpga_leds(void *context, void* test_context, int test_num)
{
bool pass = false;
int led = 0;
int key1 = 0, key2 = 0;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
lcd_writeln(&prod->lcd, "<= YES BLINKING?", "<= NO", true);
int led0 = 0, led1 = 0, btn = 0, cfg = 0;
while (1)
{
io_utils_usleep(200000);
caribou_fpga_set_io_ctrl_dig (&sys->fpga, led, led);
led = !led;
lcd_get_keys(&prod->lcd, &key1, &key2);
if (key1)
{
pass = false;
break;
}
if (key2)
{
pass = true;
break;
}
}
if (pass)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
}
else
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail - CaribouLite LEDs didn't blink - check D11, D12");
tests[test_num].test_pass = false;
}
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_fpga_smi(void *context, void* test_context, int test_num)
{
caribou_fpga_smi_fifo_status_st status = {0};
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
caribou_fpga_get_smi_ctrl_fifo_status (&sys->fpga, &status);
ZF_LOGI("FPGA SMI FIFO: 09Empty: %d, 09Full: %d, 24Empty: %d, 24Full:%d",
status.rx_fifo_09_empty, status.rx_fifo_09_full,
status.rx_fifo_24_empty, status.rx_fifo_24_full);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass - 09Empty: %d, 09Full: %d, 24Empty: %d, 24Full:%d",
status.rx_fifo_09_empty, status.rx_fifo_09_full,
status.rx_fifo_24_empty, status.rx_fifo_24_full);
tests[test_num].test_pass = true;
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_prod_eeprom_programming(sys_st* sys)
{
int led0 = 0, led1 = 0, btn = 0, cfg = 0;
// get the configuration resistors
caribou_fpga_get_io_ctrl_dig (&sys->fpga, &led0, &led1, &btn, &cfg);
sys->sys_type = (cfg & 0x1) ? system_type_cariboulite_full : system_type_cariboulite_ism;
if (sys->sys_type == system_type_cariboulite_full) ZF_LOGI("Detected CaribouLite FULL Version");
else if (sys->sys_type == system_type_cariboulite_ism) ZF_LOGI("Detected CaribouLite ISM Version");
hat.product_id = sys->sys_type;
hat_generate_write_config(&hat);
sleep(1);
caribou_fpga_set_io_ctrl_dig (&sys->fpga, 0, 0);
return 0;
}
//=================================================
int cariboulite_test_hat_eeprom(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
// EEPROM programming
ZF_LOGI("Starting EEPROM programming sequence");
hat_init(&hat);
cariboulite_prod_eeprom_programming(&cariboulite_sys);
hat_close(&hat);
ZF_LOGI("Verifying EEPROM");
hat_init(&hat);
if (hat.eeprom_initialized == 0)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail - hat eeprom programming failed, check U26, R43, R44");
tests[test_num].test_pass = false;
}
else
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
hat_print(&hat);
prod->serial_number_written_and_valid = true;
prod->serial_number = hat.generated_serial;
}
hat_close(&hat);
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_mixer_communication(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
if (sys->sys_type != system_type_cariboulite_full)
{
ZF_LOGI("MIXER testing not applicable");
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "N/A - ISM");
tests[test_num].test_pass = true;
return true;
}
// initialize
ZF_LOGD("INIT MIXER - RFFC5072");
int res = rffc507x_init(&sys->mixer, &sys->spi_dev);
if (res < 0)
{
ZF_LOGE("Error initializing mixer 'rffc5072'");
rffc507x_release(&sys->mixer);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail");
tests[test_num].test_pass = false;
return false;
}
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
// calibrate
rffc507x_calibrate(&sys->mixer);
return true;
}
//=================================================
int cariboulite_test_mixer_versions(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
if (sys->sys_type != system_type_cariboulite_full)
{
ZF_LOGI("MIXER testing not applicable");
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "N/A - ISM");
tests[test_num].test_pass = true;
return true;
}
rffc507x_device_id_st dev_id;
rffc507x_device_status_st stat;
rffc507x_readback_status(&sys->mixer, &dev_id, &stat);
rffc507x_print_dev_id(&dev_id);
rffc507x_print_stat(&stat);
if (dev_id.device_rev == 1 || dev_id.device_id == 0x8A01)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
}
else
{
rffc507x_release(&sys->mixer);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail: dev-id = %04x, dev-rev = %04x", dev_id.device_id, dev_id.device_rev);
tests[test_num].test_pass = false;
}
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_modem_communication(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
int res = at86rf215_init(&sys->modem, &sys->spi_dev);
if (res < 0)
{
ZF_LOGE("Error initializing modem 'at86rf215'");
at86rf215_close(&sys->modem);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail");
tests[test_num].test_pass = false;
return false;
}
at86rf215_setup_rf_irq(&sys->modem, 0, 1, at86rf215_drive_current_2ma);
at86rf215_radio_set_state(&sys->modem, at86rf215_rf_channel_900mhz, at86rf215_radio_state_cmd_trx_off);
at86rf215_radio_set_state(&sys->modem, at86rf215_rf_channel_2400mhz, at86rf215_radio_state_cmd_trx_off);
at86rf215_radio_irq_st int_mask = {
.wake_up_por = 1,
.trx_ready = 1,
.energy_detection_complete = 1,
.battery_low = 1,
.trx_error = 1,
.IQ_if_sync_fail = 1,
.res = 0,
};
at86rf215_radio_setup_interrupt_mask(&sys->modem, at86rf215_rf_channel_900mhz, &int_mask);
at86rf215_radio_setup_interrupt_mask(&sys->modem, at86rf215_rf_channel_2400mhz, &int_mask);
at86rf215_iq_interface_config_st modem_iq_config = {
.loopback_enable = 0,
.drv_strength = at86rf215_iq_drive_current_4ma,
.common_mode_voltage = at86rf215_iq_common_mode_v_ieee1596_1v2,
.tx_control_with_iq_if = false,
.radio09_mode = at86rf215_iq_if_mode,
.radio24_mode = at86rf215_iq_if_mode,
.clock_skew = at86rf215_iq_clock_data_skew_4_906ns,
};
at86rf215_setup_iq_if(&sys->modem, &modem_iq_config);
at86rf215_radio_external_ctrl_st ext_ctrl = {
.ext_lna_bypass_available = 0,
.agc_backoff = 0,
.analog_voltage_external = 0,
.analog_voltage_enable_in_off = 1,
.int_power_amplifier_voltage = 2,
.fe_pad_configuration = 1,
};
at86rf215_radio_setup_external_settings(&sys->modem, at86rf215_rf_channel_900mhz, &ext_ctrl);
at86rf215_radio_setup_external_settings(&sys->modem, at86rf215_rf_channel_2400mhz, &ext_ctrl);
cariboulite_radio_ext_ref (sys, cariboulite_ext_ref_32mhz);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
return true;
}
//=================================================
int cariboulite_test_modem_version(void *context, void* test_context, int test_num)
{
uint8_t pn, vn;
char pn_st[15] = {0};
bool pass = false;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
at86rf215_get_versions(&sys->modem, &pn, &vn);
if ((pn == 0x34 || pn == 0x35) && vn > 0 && vn < 5) pass = true;
if (!pass)
{
at86rf215_close(&sys->modem);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail, PN: 0x%02X, VER: %d, wrong P/N", pn, vn);
tests[test_num].test_pass = false;
return pass;
}
if (pn==0x34)
sprintf(pn_st, "AT86RF215");
else if (pn==0x35)
sprintf(pn_st, "AT86RF215IQ");
else if (pn==0x36)
sprintf(pn_st, "AT86RF215M");
else
sprintf(pn_st, "UNKNOWN");
printf("TEST:AT86RF215:VERSIONS:PN=0x%02X\n", pn);
printf("TEST:AT86RF215:VERSIONS:VN=%d\n", vn);
printf("TEST:AT86RF215:VERSIONS:PASS=%d\n", pass);
printf("TEST:AT86RF215:VERSIONS:INFO=The component PN is %s (0x%02X), Version %d\n", pn_st, pn, vn);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass, PN: %s, VER: %d", pn_st, vn);
tests[test_num].test_pass = true;
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_prod_set_modems_state(sys_st* sys, int state) // state = 0 = off, 1 = rx, 2 = tx
{
double freq_lo = 900e6;
double freq_hi = 2400e6;
float power_lo = 14;
float power_hi = 14;
cariboulite_channel_dir_en chan = state == 2?cariboulite_channel_dir_tx:cariboulite_channel_dir_rx;
cariboulite_radio_state_st *radio_low = &sys->radio_low;
cariboulite_radio_state_st *radio_hi = &sys->radio_high;
// frequency
cariboulite_radio_set_frequency(radio_low, true, &freq_lo);
cariboulite_radio_set_frequency(radio_hi, true, &freq_hi);
// deactivate - just to be sure
cariboulite_radio_activate_channel(radio_low, chan, false);
cariboulite_radio_activate_channel(radio_hi, chan, false);
if (state == 0)
{
cariboulite_radio_set_cw_outputs(radio_low, false, false);
cariboulite_radio_set_cw_outputs(radio_hi, false, false);
// deactivate
cariboulite_radio_activate_channel(radio_low, chan, false);
cariboulite_radio_activate_channel(radio_hi, chan, false);
}
else if (state == 1)
{
cariboulite_radio_set_cw_outputs(radio_low, false, false);
cariboulite_radio_set_cw_outputs(radio_hi, false, false);
// synchronize
cariboulite_radio_sync_information(radio_low);
cariboulite_radio_sync_information(radio_hi);
// activate rx
cariboulite_radio_activate_channel(radio_low, chan, true);
cariboulite_radio_activate_channel(radio_hi, chan, true);
}
if (state == 2)
{
// output power
cariboulite_radio_set_tx_power(radio_low, power_lo);
cariboulite_radio_set_tx_power(radio_hi, power_hi);
// setup cw outputs from modem
cariboulite_radio_set_cw_outputs(radio_low, false, true);
cariboulite_radio_set_cw_outputs(radio_hi, false, true);
// synchronize
cariboulite_radio_sync_information(radio_low);
cariboulite_radio_sync_information(radio_hi);
// activate tx
cariboulite_radio_activate_channel(radio_low, chan, true);
cariboulite_radio_activate_channel(radio_hi, chan, true);
}
return 0;
}
//=================================================
int cariboulite_test_modem_leds(void *context, void* test_context, int test_num)
{
bool pass = false;
int key1, key2;
int state = 0;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
lcd_writeln(&prod->lcd, "<= YES BLINKING?", "<= NO", true);
while (1)
{
io_utils_usleep(500000);
cariboulite_prod_set_modems_state(sys, state);
state = (state + 1) % 3;
lcd_get_keys(&prod->lcd, &key1, &key2);
if (key1)
{
pass = false;
break;
}
if (key2)
{
pass = true;
break;
}
}
if (pass)
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
}
else
{
at86rf215_close(&sys->modem);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail - Modem LEDs didn't blink");
tests[test_num].test_pass = false;
}
// deactivate both
cariboulite_prod_set_modems_state(sys, 0);
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_modem_interrupt(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
if (sys->modem.num_interrupts == 0)
{
at86rf215_close(&sys->modem);
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Fail - didn't get modem interrupts");
tests[test_num].test_pass = false;
}
else
{
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
}
return tests[test_num].test_pass;
}
//=================================================
int cariboulite_test_current_modem_rx(void *context, void* test_context, int test_num)
{
bool fault = false;
float current_ma = 0.0f, voltage_mv = 0.0f, power_mw = 0.0f;
float current_ma_before = 0.0f;
float current_diff = 0.0;
float current_diff_avg = 0.0;
bool pass = true;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
int k = 0;
// deactivate
cariboulite_prod_set_modems_state(sys, 0);
io_utils_usleep(100000);
production_monitor_power_fault(prod, &fault, &current_ma, &voltage_mv, &power_mw);
current_ma_before = current_ma;
// activate rx
cariboulite_prod_set_modems_state(sys, 1);
io_utils_usleep(300000);
for (k = 0; k < 20; k ++)
{
io_utils_usleep(50000);
production_monitor_power_fault(prod, &fault, &current_ma, &voltage_mv, &power_mw);
current_diff = current_ma - current_ma_before;
current_diff_avg += current_diff;
}
current_diff_avg /= (float)(k);
if (fault || current_diff_avg > 150.0f)
{
at86rf215_close(&sys->modem);
tests[test_num].test_result_float = current_diff_avg;
sprintf(tests[test_num].test_result_textual, "High modem RX extra current %.1f mA, fault: %d", current_diff_avg, fault);
tests[test_num].test_pass = false;
pass = false;
}
else
{
tests[test_num].test_result_float = current_diff_avg;
sprintf(tests[test_num].test_result_textual, "Pass, RX extra current %.1f mA", current_diff_avg);
tests[test_num].test_pass = true;
pass = true;
}
// deactivate
cariboulite_prod_set_modems_state(sys, 0);
return pass;
}
//=================================================
int cariboulite_test_current_modem_tx(void *context, void* test_context, int test_num)
{
bool fault = false;
float current_ma = 0.0f, voltage_mv = 0.0f, power_mw = 0.0f;
float current_ma_before = 0.0f;
float current_diff = 0.0;
float current_diff_avg = 0.0;
bool pass = true;
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
int k = 0;
// deactivate
cariboulite_prod_set_modems_state(sys, 0);
io_utils_usleep(100000);
production_monitor_power_fault(prod, &fault, &current_ma_before, &voltage_mv, &power_mw);
// activate tx
cariboulite_prod_set_modems_state(sys, 2);
io_utils_usleep(300000);
// test the current
for (k = 0; k < 20; k++)
{
io_utils_usleep(100000);
production_monitor_power_fault(prod, &fault, &current_ma, &voltage_mv, &power_mw);
current_diff = current_ma - current_ma_before;
current_diff_avg += current_diff;
}
current_diff_avg /= (float)(k);
if (fault || current_diff_avg > 230.0f)
{
at86rf215_close(&sys->modem);
tests[test_num].test_result_float = current_diff_avg;
sprintf(tests[test_num].test_result_textual, "High modem TX extra current %.1f mA, fault: %d", current_diff_avg, fault);
tests[test_num].test_pass = false;
pass = false;
hat_powermon_set_power_state(&prod->powermon, false);
}
else
{
tests[test_num].test_result_float = current_diff_avg;
sprintf(tests[test_num].test_result_textual, "Pass, TX extra current %.1f mA", current_diff_avg);
tests[test_num].test_pass = true;
pass = true;
}
// deactivate
cariboulite_prod_set_modems_state(sys, 0);
return pass;
}
//=================================================
int cariboulite_test_smi_data(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
return true;
}
//=================================================
int cariboulite_test_rf_loopback(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
return true;
}
//=================================================
int cariboulite_test_rf_tx_power(void *context, void* test_context, int test_num)
{
sys_st* sys = (sys_st*)context;
production_sequence_st* prod = (production_sequence_st*)test_context;
tests[test_num].test_result_float = -1;
sprintf(tests[test_num].test_result_textual, "Pass");
tests[test_num].test_pass = true;
return true;
}
// GIT REPO
#define PRODUCTION_GIT_DIR "/home/pi/cariboulite_production_results"
#define PRODUCTION_PAT_PATH "/home/pi/manufacturing_PAT.txt"
//#define PRODUCTION_GIT_URI "github.com/cariboulabs/cariboulite_production_results.git"
#define PRODUCTION_GIT_URI "gitee.com/meexmachina/cariboulite_production_results.git"
//=================================================
int cariboulite_production_app_close(production_sequence_st* prod)
{
ZF_LOGI("CLOSING...");
production_close(prod);
return 0;
}
//=================================================
int cariboulite_production_clear_drivers(production_sequence_st* prod)
{
sys_st* sys = (sys_st*)prod->context;
rffc507x_release(&sys->mixer);
caribou_fpga_hard_reset_keep(&sys->fpga, true);
at86rf215_close(&sys->modem);
return 0;
}
//=================================================
int main(int argc, char *argv[])
{
bool fault = false;
char report_file_path[2048] = {0};
float i, v, p;
production_sequence_st prod = {};
cariboulite_init_system_production(&cariboulite_sys);
if (production_init(&prod, tests, NUM_OF_TESTS, &cariboulite_sys) != 0)
{
ZF_LOGE("Couldn't init production testing");
return 0;
}
production_generate_event_file(&prod, PRODUCTION_GIT_DIR, "tester started", prod.tester.rpi_info.serial_number);
production_set_git_repo(&prod, PRODUCTION_PAT_PATH, PRODUCTION_GIT_URI, PRODUCTION_GIT_DIR);
production_git_sync_sequence(&prod, "auto commit");
ZF_LOGI("WELLCOME!!");
lcd_writeln(&prod.lcd, "CaribouLite Tst", "WELLCOME! (3)", true);
sleep(1);
lcd_writeln(&prod.lcd, "CaribouLite Tst", "WELLCOME! (2)", true);
sleep(1);
lcd_writeln(&prod.lcd, "CaribouLite Tst", "WELLCOME! (1)", true);
sleep(1);
while (1)
{
int ret = 0;
char msg_cache[32];
lcd_button_en input_button = lcd_button_bottom;
production_wait_for_button(&prod, lcd_button_bottom, "MOUNT, START", "<== CLICK HERE");
lcd_writeln(&prod.lcd, "Starting Tests...", "", true);
sleep(2);
production_wait_input(&prod, &input_button, "<== FULL CHOOSE", "<== ISM");
prod.operator_set_version = input_button == lcd_button_bottom ? production_sys_version_ism : production_sys_version_full;
sprintf(msg_cache, "VER: %s", prod.operator_set_version == production_sys_version_ism? "ISM" : "FULL");
prod.serial_number_written_and_valid = false;
prod.system_type_valid = false;
// start the tests
ret = production_start_tests(&prod);
sleep(1);
hat_powermon_set_power_state(&prod.powermon, false);
// close the driver and release resources
production_utils_rpi_leds_init(0);
if (ret == false)
{
production_wait_for_button(&prod, lcd_button_bottom, "F A I L! UNMOUNT", "<== CLICK HERE");
production_generate_event_file(&prod, PRODUCTION_GIT_DIR, "board testing failed", prod.tester.rpi_info.serial_number);
}
else
{
production_wait_for_button(&prod, lcd_button_bottom, "P A S S! UNMOUNT", "<== CLICK HERE");
}
hat_powermon_set_power_state(&prod.powermon, false);
//sprintf(report_file_path, "%s/%08x_%s.yml", PRODUCTION_GIT_DIR, prod.prod->serial_number, ret?"PASS":"FAIL");
production_generate_report(&prod, PRODUCTION_GIT_DIR, prod.serial_number);
production_git_sync_sequence(&prod, "auto commit");
cariboulite_production_clear_drivers(&prod);
production_rewind(&prod);
}
production_generate_event_file(&prod, PRODUCTION_GIT_DIR, "tester stopped", prod.tester.rpi_info.serial_number);
cariboulite_production_app_close(&prod);
cariboulite_deinit_system_production(&cariboulite_sys);
return 0;
}