Files
2025-03-28 15:35:02 +08:00

1085 lines
34 KiB
C

#include "cpg.h"
#include "elite_board.h"
#include "elite_def.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "nrf_log.h"
#include "tw1508.h"
#if (DEF_ELITE_MODEL == DEF_ELITE_CPG_V1_1)
// ExN: electrode x negative
// ExP: electrode x positive
#define ELEC_CH_ALL_HIGHZ 0x0000
#define ELEC_CH_E1_HIGHZ 0x0001
#define ELEC_CH_E2_HIGHZ 0x0002
#define ELEC_CH_E3_HIGHZ 0x0003
#define ELEC_CH_E4_HIGHZ 0x0004
#define ELEC_CH_ALL_IDLE 0x0005
#define ELEC_CH_E1_IDLE 0x0006
#define ELEC_CH_E2_IDLE 0x0007
#define ELEC_CH_E3_IDLE 0x0008
#define ELEC_CH_E4_IDLE 0x0009
#define PULSE_GEN_NUMB 4
static pulse_gen_t pulse_gen[PULSE_GEN_NUMB];
typedef struct
{
uint32_t gpio;
const char *desc;
} pin_func_name_t;
typedef struct
{
uint8_t dev_opcode;
uint8_t item_opcode;
uint8_t e1_e2_which_to_set;
uint32_t e1_e2_amplitude_mA_u32;
uint32_t e1_e2_pulse_width_us;
uint32_t e1_e2_freq_hz;
uint8_t e3_e4_which_to_set;
uint32_t e3_e4_amplitude_mA_u32;
uint32_t e3_e4_pulse_width_us;
uint32_t e3_e4_freq_hz;
uint32_t countdown_timer_seconds;
uint16_t select_which_electrode;
} two_set_electrodes_task_t;
static const pin_func_name_t pin_to_gpio_table[] = {
[1] = { UNDEF_GPIO, "UNDEF_GPIO" },
[2] = { UNDEF_GPIO, "UNDEF_GPIO" },
[3] = { UNDEF_GPIO, "UNDEF_GPIO" },
[4] = { UNDEF_GPIO, "UNDEF_GPIO" },
[5] = { UNDEF_GPIO, "UNDEF_GPIO" },
[6] = { NRF_GPIO_PIN_MAP(0, 22), "GPIO(0, 22)" },
[7] = { UNDEF_GPIO, "UNDEF_GPIO" },
[8] = { NRF_GPIO_PIN_MAP(0, 25), "GPIO(0, 25)" },
[9] = { NRF_GPIO_PIN_MAP(0, 19), "GPIO(0, 19)" },
[10] = { NRF_GPIO_PIN_MAP(0, 21), "GPIO(0, 21)" },
[11] = { NRF_GPIO_PIN_MAP(1, 0), "GPIO(1, 0)" },
[12] = { NRF_GPIO_PIN_MAP(0, 18), "GPIO(0, 18)" },
[13] = { NRF_GPIO_PIN_MAP(0, 17), "GPIO(0, 17)" },
[14] = { NRF_GPIO_PIN_MAP(0, 20), "GPIO(0, 20)" },
[15] = { UNDEF_GPIO, "UNDEF_GPIO" },
[16] = { NRF_GPIO_PIN_MAP(0, 14), "GPIO(0, 14)" },
[17] = { NRF_GPIO_PIN_MAP(0, 13), "GPIO(0, 13)" },
[18] = { NRF_GPIO_PIN_MAP(0, 11), "GPIO(0, 11)" },
[19] = { UNDEF_GPIO, "UNDEF_GPIO" },
[20] = { NRF_GPIO_PIN_MAP(0, 15), "GPIO(0, 15)" },
[21] = { UNDEF_GPIO, "UNDEF_GPIO" },
[22] = { UNDEF_GPIO, "UNDEF_GPIO" },
[23] = { UNDEF_GPIO, "UNDEF_GPIO" },
[24] = { UNDEF_GPIO, "UNDEF_GPIO" },
[25] = { NRF_GPIO_PIN_MAP(1, 8), "GPIO(1, 8)" },
[26] = { NRF_GPIO_PIN_MAP(0, 12), "GPIO(0, 12)" },
[27] = { NRF_GPIO_PIN_MAP(0, 7), "GPIO(0, 7)" },
[28] = { NRF_GPIO_PIN_MAP(1, 9), "GPIO(1, 9)" },
[29] = { NRF_GPIO_PIN_MAP(0, 8), "GPIO(0, 8)" },
[30] = { NRF_GPIO_PIN_MAP(0, 6), "GPIO(0, 6)" },
[31] = { NRF_GPIO_PIN_MAP(0, 5), "GPIO(0, 5)" },
[32] = { NRF_GPIO_PIN_MAP(0, 27), "GPIO(0, 27)" },
[33] = { NRF_GPIO_PIN_MAP(0, 26), "GPIO(0, 26)" },
[34] = { NRF_GPIO_PIN_MAP(0, 4), "GPIO(0, 4)" },
[35] = { UNDEF_GPIO, "UNDEF_GPIO" },
[36] = { NRF_GPIO_PIN_MAP(0, 1), "GPIO(0, 1)" },
[37] = { NRF_GPIO_PIN_MAP(0, 29), "GPIO(0, 29)" },
[38] = { NRF_GPIO_PIN_MAP(0, 0), "GPIO(0, 0)" },
[39] = { NRF_GPIO_PIN_MAP(0, 31), "GPIO(0, 31)" },
[40] = { NRF_GPIO_PIN_MAP(1, 15), "GPIO(1, 15)" },
[41] = { NRF_GPIO_PIN_MAP(0, 2), "GPIO(0, 2)" },
[42] = { NRF_GPIO_PIN_MAP(0, 30), "GPIO(0, 30)" },
[43] = { NRF_GPIO_PIN_MAP(0, 28), "GPIO(0, 28)" },
[44] = { NRF_GPIO_PIN_MAP(1, 12), "GPIO(1, 12)" },
[45] = { NRF_GPIO_PIN_MAP(1, 14), "GPIO(1, 14)" },
[46] = { NRF_GPIO_PIN_MAP(0, 3), "GPIO(0, 3)" },
[47] = { NRF_GPIO_PIN_MAP(1, 13), "GPIO(1, 13)" },
[48] = { NRF_GPIO_PIN_MAP(1, 3), "GPIO(1, 3)" },
[49] = { NRF_GPIO_PIN_MAP(1, 10), "GPIO(1, 10)" },
[50] = { NRF_GPIO_PIN_MAP(1, 6), "GPIO(1, 6)" },
[51] = { NRF_GPIO_PIN_MAP(1, 11), "GPIO(1, 11)" },
[52] = { NRF_GPIO_PIN_MAP(0, 10), "GPIO(0, 10)" },
[53] = { NRF_GPIO_PIN_MAP(0, 9), "GPIO(0, 9)" },
[54] = { UNDEF_GPIO, "UNDEF_GPIO" },
[55] = { UNDEF_GPIO, "UNDEF_GPIO" },
[56] = { UNDEF_GPIO, "UNDEF_GPIO" },
[57] = { UNDEF_GPIO, "UNDEF_GPIO" },
[58] = { UNDEF_GPIO, "UNDEF_GPIO" },
[59] = { NRF_GPIO_PIN_MAP(1, 2), "GPIO(1, 2)" },
[60] = { NRF_GPIO_PIN_MAP(0, 24), "GPIO(0, 24)" },
[61] = { NRF_GPIO_PIN_MAP(0, 23), "GPIO(0, 23)" },
[62] = { NRF_GPIO_PIN_MAP(0, 16), "GPIO(0, 16)" },
[63] = { UNDEF_GPIO, "UNDEF_GPIO" },
};
static void set_single_pin_as_output(uint16_t pin_number, uint16_t high_low)
{
if (pin_number < 1 || pin_number >= ARRAY_SIZE(pin_to_gpio_table))
{
NRF_LOG_INFO("pin_number(%d) out of range", pin_number);
return;
}
uint32_t gpio = pin_to_gpio_table[pin_number].gpio;
if (gpio == UNDEF_GPIO)
{
NRF_LOG_INFO("pin_number(%d) is not used", pin_number);
}
else
{
nrf_gpio_cfg_output(gpio);
nrf_gpio_pin_write(gpio, high_low);
NRF_LOG_INFO("pin_number(%d) = %d // pin_function_name: %s",
pin_number,
high_low,
pin_to_gpio_table[pin_number].desc);
}
}
static uint16_t current_mA_convert_tw1508_value(float current_mA)
{
#define TW1508_REXR 1.5 // 1.5kohm
#define TW1508_BOUNDARY_GAIN0 13.3
#define TW1508_BOUNDARY_GAIN1 26.6
#define TW1508_BOUNDARY_GAIN2 39.9
#define TW1508_BOUNDARY_GAIN3 53.3
#define TW1508_BOUNDARY_GAIN4 66.6
#define TW1508_BOUNDARY_GAIN5 79.9
#define TW1508_BOUNDARY_GAIN6 93.3
#define TW1508_BOUNDARY_GAIN7 106.6
uint16_t tw1508_value;
uint8_t dac_7bit;
uint8_t dac_3bit;
float rext;
if (current_mA > TW1508_BOUNDARY_GAIN7)
{
current_mA = TW1508_BOUNDARY_GAIN7;
NRF_LOG_INFO("current is too large");
}
if (current_mA <= TW1508_BOUNDARY_GAIN0)
{
dac_3bit = 0b000;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN1)
{
dac_3bit = 0b001;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN2)
{
dac_3bit = 0b010;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN3)
{
dac_3bit = 0b011;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN4)
{
dac_3bit = 0b100;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN5)
{
dac_3bit = 0b101;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN6)
{
dac_3bit = 0b110;
rext = TW1508_REXR;
}
else if (current_mA <= TW1508_BOUNDARY_GAIN7)
{
dac_3bit = 0b111;
rext = TW1508_REXR;
}
dac_7bit = current_mA * 8 * TW1508_REXR / 1.25 / (dac_3bit + 1);
tw1508_value = dac_3bit << 7 | dac_7bit;
return tw1508_value;
}
static void tw1508_set_mA(float out_0_mA, float out_1_mA)
{
uint16_t out_0;
uint16_t out_1;
{
char str[128];
snprintf(str, sizeof(str), "%s: %.3f", "out_0_mA float", out_0_mA);
NRF_LOG_INFO("%s", str);
snprintf(str, sizeof(str), "%s: %.3f", "out_1_mA float", out_1_mA);
NRF_LOG_INFO("%s", str);
}
out_0 = current_mA_convert_tw1508_value(out_0_mA);
out_1 = current_mA_convert_tw1508_value(out_1_mA);
tw1508_set(out_0, out_1);
}
static void electrode_pulse_channel(uint16_t elec_ch_setting)
{
switch (elec_ch_setting)
{
case ELEC_CH_ALL_HIGHZ: {
NRF_LOG_INFO("ELEC_CH_ALL_HIGHZ()");
electrode_pulse_channel(ELEC_CH_E1_HIGHZ);
electrode_pulse_channel(ELEC_CH_E2_HIGHZ);
electrode_pulse_channel(ELEC_CH_E3_HIGHZ);
electrode_pulse_channel(ELEC_CH_E4_HIGHZ);
break;
}
case ELEC_CH_E1_HIGHZ: {
NRF_LOG_INFO("ELEC_CH_E1_HIGHZ()");
nrf_gpio_pin_write(VB1L_PIN, 0);
nrf_gpio_pin_write(VB1H_PIN, 0);
nrf_gpio_pin_write(VA1L_PIN, 0);
nrf_gpio_pin_write(VA1H_PIN, 0);
break;
}
case ELEC_CH_E2_HIGHZ: {
NRF_LOG_INFO("ELEC_CH_E2_HIGHZ()");
nrf_gpio_pin_write(VB2L_PIN, 0);
nrf_gpio_pin_write(VB2H_PIN, 0);
nrf_gpio_pin_write(VA2L_PIN, 0);
nrf_gpio_pin_write(VA2H_PIN, 0);
break;
}
case ELEC_CH_E3_HIGHZ: {
NRF_LOG_INFO("ELEC_CH_E3_HIGHZ()");
nrf_gpio_pin_write(VB3L_PIN, 0);
nrf_gpio_pin_write(VB3H_PIN, 0);
nrf_gpio_pin_write(VA3L_PIN, 0);
nrf_gpio_pin_write(VA3H_PIN, 0);
break;
}
case ELEC_CH_E4_HIGHZ: {
NRF_LOG_INFO("ELEC_CH_E4_HIGHZ()");
nrf_gpio_pin_write(VB4L_PIN, 0);
nrf_gpio_pin_write(VB4H_PIN, 0);
nrf_gpio_pin_write(VA4L_PIN, 0);
nrf_gpio_pin_write(VA4H_PIN, 0);
break;
}
case ELEC_CH_ALL_IDLE: {
NRF_LOG_INFO("ELEC_CH_ALL_IDLE()");
electrode_pulse_channel(ELEC_CH_E1_IDLE);
electrode_pulse_channel(ELEC_CH_E2_IDLE);
electrode_pulse_channel(ELEC_CH_E3_IDLE);
electrode_pulse_channel(ELEC_CH_E4_IDLE);
break;
}
case ELEC_CH_E1_IDLE:
NRF_LOG_INFO("ELEC_CH_E1_IDLE()");
nrf_gpio_pin_write(VB1L_PIN, 0);
nrf_gpio_pin_write(VB1H_PIN, 1);
nrf_gpio_pin_write(VA1L_PIN, 0);
nrf_gpio_pin_write(VA1H_PIN, 1);
break;
case ELEC_CH_E2_IDLE:
NRF_LOG_INFO("ELEC_CH_E2_IDLE()");
nrf_gpio_pin_write(VB2L_PIN, 0);
nrf_gpio_pin_write(VB2H_PIN, 1);
nrf_gpio_pin_write(VA2L_PIN, 0);
nrf_gpio_pin_write(VA2H_PIN, 1);
break;
case ELEC_CH_E3_IDLE:
NRF_LOG_INFO("ELEC_CH_E3_IDLE()");
nrf_gpio_pin_write(VB3L_PIN, 0);
nrf_gpio_pin_write(VB3H_PIN, 1);
nrf_gpio_pin_write(VA3L_PIN, 0);
nrf_gpio_pin_write(VA3H_PIN, 1);
break;
case ELEC_CH_E4_IDLE:
NRF_LOG_INFO("ELEC_CH_E4_IDLE()");
nrf_gpio_pin_write(VB4L_PIN, 0);
nrf_gpio_pin_write(VB4H_PIN, 1);
nrf_gpio_pin_write(VA4L_PIN, 0);
nrf_gpio_pin_write(VA4H_PIN, 1);
break;
}
}
static void adapter_channel(uint16_t channel)
{
union
{
uint16_t val;
struct
{
uint16_t adpt0_s1 : 1;
uint16_t adpt0_s2 : 1;
uint16_t adpt0_s3 : 1;
uint16_t adpt0_s4 : 1;
uint16_t adpt1_s1 : 1;
uint16_t adpt1_s2 : 1;
uint16_t adpt1_s3 : 1;
uint16_t adpt1_s4 : 1;
uint16_t adpt_rsvd : 8;
};
} adap_ch;
adap_ch.val = channel;
NRF_LOG_INFO("ADPT0_S1_PIN(%d)", adap_ch.adpt0_s1);
NRF_LOG_INFO("ADPT0_S2_PIN(%d)", adap_ch.adpt0_s2);
NRF_LOG_INFO("ADPT0_S3_PIN(%d)", adap_ch.adpt0_s3);
NRF_LOG_INFO("ADPT0_S4_PIN(%d)", adap_ch.adpt0_s4);
NRF_LOG_INFO("ADPT1_S1_PIN(%d)", adap_ch.adpt1_s1);
NRF_LOG_INFO("ADPT1_S2_PIN(%d)", adap_ch.adpt1_s2);
NRF_LOG_INFO("ADPT1_S3_PIN(%d)", adap_ch.adpt1_s3);
NRF_LOG_INFO("ADPT1_S4_PIN(%d)", adap_ch.adpt1_s4);
adap_ch.adpt0_s1 ? nrf_gpio_pin_set(ADPT0_S1_PIN) : nrf_gpio_pin_clear(ADPT0_S1_PIN);
adap_ch.adpt0_s2 ? nrf_gpio_pin_set(ADPT0_S2_PIN) : nrf_gpio_pin_clear(ADPT0_S2_PIN);
adap_ch.adpt0_s3 ? nrf_gpio_pin_set(ADPT0_S3_PIN) : nrf_gpio_pin_clear(ADPT0_S3_PIN);
adap_ch.adpt0_s4 ? nrf_gpio_pin_set(ADPT0_S4_PIN) : nrf_gpio_pin_clear(ADPT0_S4_PIN);
adap_ch.adpt1_s1 ? nrf_gpio_pin_set(ADPT1_S1_PIN) : nrf_gpio_pin_clear(ADPT1_S1_PIN);
adap_ch.adpt1_s2 ? nrf_gpio_pin_set(ADPT1_S2_PIN) : nrf_gpio_pin_clear(ADPT1_S2_PIN);
adap_ch.adpt1_s3 ? nrf_gpio_pin_set(ADPT1_S3_PIN) : nrf_gpio_pin_clear(ADPT1_S3_PIN);
adap_ch.adpt1_s4 ? nrf_gpio_pin_set(ADPT1_S4_PIN) : nrf_gpio_pin_clear(ADPT1_S4_PIN);
}
static void high_volt_channel(uint16_t channel)
{
sw_t sw;
sw.val = channel;
NRF_LOG_INFO("HV_sw.val= 0x%04X", sw.val);
{
char str[128];
snprintf(str, sizeof(str), "%4d, %4d, %4d, %4d, %4d, %4d, %3d, %3d", sw.sw15, sw.sw14, sw.sw13, sw.sw12, sw.sw11, sw.sw10, sw.sw9, sw.sw8);
NRF_LOG_INFO("sw15, sw14, sw13, sw12, sw11, sw10, sw9, sw8");
NRF_LOG_INFO("%s", str);
snprintf(str, sizeof(str), "%3d, %3d, %3d, %3d, %3d, %3d, %3d, %3d", sw.sw7, sw.sw6, sw.sw5, sw.sw4, sw.sw3, sw.sw2, sw.sw1, sw.sw0);
NRF_LOG_INFO("sw7, sw6, sw5, sw4, sw3, sw2, sw1, sw0");
NRF_LOG_INFO("%s", str);
}
sw_write(sw);
}
static void set_cpg_pulse_parameter(two_set_electrodes_task_t *params)
{
NRF_LOG_INFO("%s", __FUNCTION__);
uint8_t electrodes_sel[4];
for (int i = 0; i < 4; i++)
{
electrodes_sel[i] = ((params->e1_e2_which_to_set | params->e3_e4_which_to_set) >> (7 - i)) & 0x01;
}
uint32_t pulse_width_us;
uint32_t freq_hz;
uint32_t half_idle_us;
pulse_width_us = params->e1_e2_pulse_width_us;
freq_hz = params->e1_e2_freq_hz;
if (electrodes_sel[0])
{
pulse_gen[0] = (pulse_gen_t) {
.VBxH = VB1H_PIN,
.VBxL = VB1L_PIN,
.VAxH = VA1H_PIN,
.VAxL = VA1L_PIN,
.point_us[0] = 1,
.point_us[1] = pulse_width_us,
.point_us[2] = 1,
.point_us[3] = 0,
.point_us[4] = 1,
.point_us[5] = pulse_width_us,
.point_us[6] = 1,
.idle_us = 0,
.pulse_cnt = UINT32_MAX,
.pulse_id = PULSE_ID_A,
};
if (freq_hz == 0)
{
pulse_gen[0].idle_us = 0;
}
else
{
pulse_gen[0].idle_us = 1000000 / freq_hz - (pulse_gen[0].point_us[0] + pulse_gen[0].point_us[1] + pulse_gen[0].point_us[2] + pulse_gen[0].point_us[3] + pulse_gen[0].point_us[4] + pulse_gen[0].point_us[5] + pulse_gen[0].point_us[6]);
}
}
if (electrodes_sel[1])
{
pulse_gen[1] = (pulse_gen_t) {
.VBxH = VB2H_PIN,
.VBxL = VB2L_PIN,
.VAxH = VA2H_PIN,
.VAxL = VA2L_PIN,
.point_us[0] = 1,
.point_us[1] = pulse_width_us,
.point_us[2] = 1,
.point_us[3] = 0,
.point_us[4] = 1,
.point_us[5] = pulse_width_us,
.point_us[6] = 1,
.idle_us = 0,
.pulse_cnt = UINT32_MAX,
.pulse_id = PULSE_ID_B,
};
if (freq_hz == 0)
{
pulse_gen[1].idle_us = 0;
}
else
{
pulse_gen[1].idle_us = 1000000 / freq_hz - (pulse_gen[1].point_us[0] + pulse_gen[1].point_us[1] + pulse_gen[1].point_us[2] + pulse_gen[1].point_us[3] + pulse_gen[1].point_us[4] + pulse_gen[1].point_us[5] + pulse_gen[1].point_us[6]);
}
}
if (electrodes_sel[0] && electrodes_sel[1] && freq_hz != 0)
{
half_idle_us = (1000000 / freq_hz - (pulse_gen[0].point_us[0] + pulse_gen[0].point_us[1] + pulse_gen[0].point_us[2] + pulse_gen[0].point_us[3] + pulse_gen[0].point_us[4] + pulse_gen[0].point_us[5] + pulse_gen[0].point_us[6]) - (pulse_gen[1].point_us[0] + pulse_gen[1].point_us[1] + pulse_gen[1].point_us[2] + pulse_gen[1].point_us[3] + pulse_gen[1].point_us[4] + pulse_gen[1].point_us[5] + pulse_gen[1].point_us[6])) / 2;
pulse_gen[0].idle_us = half_idle_us;
pulse_gen[1].idle_us = half_idle_us;
}
pulse_width_us = params->e3_e4_pulse_width_us;
freq_hz = params->e3_e4_freq_hz;
if (electrodes_sel[2])
{
pulse_gen[2] = (pulse_gen_t) {
.VBxH = VB3H_PIN,
.VBxL = VB3L_PIN,
.VAxH = VA3H_PIN,
.VAxL = VA3L_PIN,
.point_us[0] = 1,
.point_us[1] = pulse_width_us,
.point_us[2] = 1,
.point_us[3] = 0,
.point_us[4] = 1,
.point_us[5] = pulse_width_us,
.point_us[6] = 1,
.idle_us = 0,
.pulse_cnt = UINT32_MAX,
.pulse_id = PULSE_ID_C,
};
if (freq_hz == 0)
{
pulse_gen[2].idle_us = 0;
}
else
{
pulse_gen[2].idle_us = 1000000 / freq_hz - (pulse_gen[2].point_us[0] + pulse_gen[2].point_us[1] + pulse_gen[2].point_us[2] + pulse_gen[2].point_us[3] + pulse_gen[2].point_us[4] + pulse_gen[2].point_us[5] + pulse_gen[2].point_us[6]);
}
}
if (electrodes_sel[3])
{
pulse_gen[3] = (pulse_gen_t) {
.VBxH = VB4H_PIN,
.VBxL = VB4L_PIN,
.VAxH = VA4H_PIN,
.VAxL = VA4L_PIN,
.point_us[0] = 1,
.point_us[1] = pulse_width_us,
.point_us[2] = 1,
.point_us[3] = 0,
.point_us[4] = 1,
.point_us[5] = pulse_width_us,
.point_us[6] = 1,
.idle_us = 0,
.pulse_cnt = UINT32_MAX,
.pulse_id = PULSE_ID_D,
};
if (freq_hz == 0)
{
pulse_gen[3].idle_us = 0;
}
else
{
pulse_gen[3].idle_us = 1000000 / freq_hz - (pulse_gen[3].point_us[0] + pulse_gen[3].point_us[1] + pulse_gen[3].point_us[2] + pulse_gen[3].point_us[3] + pulse_gen[3].point_us[4] + pulse_gen[3].point_us[5] + pulse_gen[3].point_us[6]);
}
}
if (electrodes_sel[2] && electrodes_sel[3] && freq_hz != 0)
{
half_idle_us = (1000000 / freq_hz - (pulse_gen[2].point_us[0] + pulse_gen[2].point_us[1] + pulse_gen[2].point_us[2] + pulse_gen[2].point_us[3] + pulse_gen[2].point_us[4] + pulse_gen[2].point_us[5] + pulse_gen[2].point_us[6]) - (pulse_gen[3].point_us[0] + pulse_gen[3].point_us[1] + pulse_gen[3].point_us[2] + pulse_gen[3].point_us[3] + pulse_gen[3].point_us[4] + pulse_gen[3].point_us[5] + pulse_gen[3].point_us[6])) / 2;
pulse_gen[2].idle_us = half_idle_us;
pulse_gen[3].idle_us = half_idle_us;
}
for (int i = 0; i < PULSE_GEN_NUMB; i++)
{
if (electrodes_sel[i])
{
if (i == 0 || i == 1)
{
pulse_width_us = params->e1_e2_pulse_width_us;
freq_hz = params->e1_e2_freq_hz;
}
else if (i == 2 || i == 3)
{
pulse_width_us = params->e3_e4_pulse_width_us;
freq_hz = params->e3_e4_freq_hz;
}
NRF_LOG_INFO("set electrodes %d pulse_gen", i + 1);
NRF_LOG_INFO("[%d]user pulse_width = %u us", 1, pulse_width_us);
NRF_LOG_INFO("[%d]user freq_hz = %u Hz (Period = %dus)", 1, freq_hz, 1 * 1000000 / freq_hz);
NRF_LOG_INFO("pulse_gen[%d] VAxH = %d, VAxL = %d, VBxH = %d, VBxL = %d",
i,
pulse_gen[i].VAxH,
pulse_gen[i].VAxL,
pulse_gen[i].VBxH,
pulse_gen[i].VBxL);
for (int j = 0; j < 7; j++)
{
NRF_LOG_INFO("pulse_gen[%d] %c = %u us", i, 'a' + j, pulse_gen[i].point_us[j]);
}
NRF_LOG_INFO("pulse_gen[%d] %-9s = %u us", i, "idle", pulse_gen[i].idle_us);
NRF_LOG_INFO("pulse_gen[%d] %-9s = 0x%08X", i, "pulse_cnt", pulse_gen[i].pulse_cnt);
NRF_LOG_INFO("pulse_gen[%d] %-9s = %u\n", i, "pulse_id", pulse_gen[i].pulse_id);
}
}
NRF_LOG_INFO("set ok......");
}
static void start_which_electrodes(uint16_t channel)
{
NRF_LOG_INFO("%s", __FUNCTION__);
uint8_t enabled_electrodes[4];
for (int i = 0; i < 4; i++)
{
enabled_electrodes[i] = (channel >> (7 - i)) & 0x01;
}
// clear GPIO
for (int i = 0; i < 4; i++)
{
if (enabled_electrodes[i])
{
nrf_gpio_pin_clear(pulse_gen[i].VBxL);
nrf_gpio_pin_clear(pulse_gen[i].VBxH);
nrf_gpio_pin_clear(pulse_gen[i].VAxL);
nrf_gpio_pin_clear(pulse_gen[i].VAxH);
}
}
// initialize and start the pulse
for (int i = 0; i < 2; i++) // two sets of electrodes (e1-e2, e3-e4)
{
uint8_t e1 = enabled_electrodes[i * 2];
uint8_t e2 = enabled_electrodes[i * 2 + 1];
if (e1 && e2)
{
cpg11_pulse_init(i, &pulse_gen[i * 2], 2);
cpg11_pulse_start(i, &pulse_gen[i * 2]);
}
else if (e1)
{
cpg11_pulse_init(i, &pulse_gen[i * 2], 1);
cpg11_pulse_start(i, &pulse_gen[i * 2]);
}
else if (e2)
{
cpg11_pulse_init(i, &pulse_gen[i * 2 + 1], 1);
cpg11_pulse_start(i, &pulse_gen[i * 2 + 1]);
}
}
for (int i = 0; i < PULSE_GEN_NUMB; i++)
{
if (enabled_electrodes[i])
{
NRF_LOG_INFO("start electrodes %d pulse_gen", i + 1);
NRF_LOG_INFO("pulse_gen[%d] VAxH = %d, VAxL = %d, VBxH = %d, VBxL = %d",
i,
pulse_gen[i].VAxH,
pulse_gen[i].VAxL,
pulse_gen[i].VBxH,
pulse_gen[i].VBxL);
for (int j = 0; j < 7; j++)
{
NRF_LOG_INFO("pulse_gen[%d] %c = %u us", i, 'a' + j, pulse_gen[i].point_us[j]);
}
NRF_LOG_INFO("pulse_gen[%d] %-9s = %u us", i, "idle", pulse_gen[i].idle_us);
NRF_LOG_INFO("pulse_gen[%d] %-9s = 0x%08X", i, "pulse_cnt", pulse_gen[i].pulse_cnt);
NRF_LOG_INFO("pulse_gen[%d] %-9s = %u\n", i, "pulse_id", pulse_gen[i].pulse_id);
}
}
}
static void stop_which_electrodes(uint16_t channel)
{
NRF_LOG_INFO("%s", __FUNCTION__);
uint8_t disabled_electrodes[4];
for (int i = 0; i < 4; i++)
{
disabled_electrodes[i] = (channel >> (7 - i)) & 0x01;
}
if (disabled_electrodes[0] || disabled_electrodes[1])
{
cpg11_pulse_stop(0);
NRF_LOG_INFO("stop electrodes 1 & 2 pulse_gen");
}
if (disabled_electrodes[2] || disabled_electrodes[3])
{
cpg11_pulse_stop(1);
NRF_LOG_INFO("stop electrodes 3 & 4 pulse_gen");
}
}
static void suspend_which_electrodes(uint16_t channel)
{
NRF_LOG_INFO("%s", __FUNCTION__);
uint8_t suspend_electrodes[4];
for (int i = 0; i < 4; i++)
{
suspend_electrodes[i] = (channel >> (7 - i)) & 0x01;
}
for (int i = 0; i < 4; i++)
{
if (suspend_electrodes[i])
{
cpg11_pulse_suspend_by_pulse_id(pulse_gen[i].pulse_id);
NRF_LOG_INFO("suspend electrodes %d pulse_gen", i + 1);
}
}
}
static void resume_which_electrodes(uint16_t channel)
{
NRF_LOG_INFO("%s", __FUNCTION__);
uint8_t resume_electrodes[4];
for (int i = 0; i < 4; i++)
{
resume_electrodes[i] = (channel >> (7 - i)) & 0x01;
}
for (int i = 0; i < 4; i++)
{
if (resume_electrodes[i])
{
cpg11_pulse_resume_by_pulse_id(pulse_gen[i].pulse_id);
NRF_LOG_INFO("resume electrodes %d pulse_gen", i + 1);
}
}
}
static void start_electrodes_api(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t dev_feat;
uint8_t opcode;
uint8_t param[];
} *p_ins = (void *)ins;
two_set_electrodes_task_t params;
params.e1_e2_which_to_set = p_ins->param[0];
params.e1_e2_amplitude_mA_u32 = u8_to_u32(p_ins->param[1], p_ins->param[2], p_ins->param[3], p_ins->param[4]);
params.e1_e2_pulse_width_us = u8_to_u32(p_ins->param[5], p_ins->param[6], p_ins->param[7], p_ins->param[8]);
params.e1_e2_freq_hz = u8_to_u32(p_ins->param[9], p_ins->param[10], p_ins->param[11], p_ins->param[12]);
params.e3_e4_which_to_set = p_ins->param[13];
params.e3_e4_amplitude_mA_u32 = u8_to_u32(p_ins->param[14], p_ins->param[15], p_ins->param[16], p_ins->param[17]);
params.e3_e4_pulse_width_us = u8_to_u32(p_ins->param[18], p_ins->param[19], p_ins->param[20], p_ins->param[21]);
params.e3_e4_freq_hz = u8_to_u32(p_ins->param[22], p_ins->param[23], p_ins->param[24], p_ins->param[25]);
params.countdown_timer_seconds = u8_to_u32(p_ins->param[26], p_ins->param[27], p_ins->param[28], p_ins->param[29]);
params.select_which_electrode = p_ins->param[30];
// set current
float e1_e2_amplitude_mA_f;
float e3_e4_amplitude_mA_f;
memcpy(&e1_e2_amplitude_mA_f, &params.e1_e2_amplitude_mA_u32, sizeof(e1_e2_amplitude_mA_f));
memcpy(&e3_e4_amplitude_mA_f, &params.e3_e4_amplitude_mA_u32, sizeof(e3_e4_amplitude_mA_f));
tw1508_set_mA(e1_e2_amplitude_mA_f, e3_e4_amplitude_mA_f);
NRF_LOG_INFO("...........................");
// set elec pulse param
set_cpg_pulse_parameter(&params);
NRF_LOG_INFO("...........................");
nrf_gpio_pin_set(HV_EN_PIN);
NRF_LOG_INFO("HV_EN_PIN(1)");
start_which_electrodes(params.select_which_electrode);
NRF_LOG_INFO("...........................");
}
static void stop_electrodes_api(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t dev_feat;
uint8_t opcode;
uint8_t param[];
} *p_ins = (void *)ins;
two_set_electrodes_task_t params;
params.select_which_electrode = p_ins->param[0];
stop_which_electrodes(params.select_which_electrode);
nrf_gpio_pin_clear(HV_EN_PIN);
NRF_LOG_INFO("HV_EN_PIN(0)");
}
static void cis_version(uint8_t *ins, uint16_t size)
{
NRF_LOG_INFO("%s", __FUNCTION__);
uint8_t cis_ver[] = {
CIS_VERSION,
VERSION_DATE_YEAR,
VERSION_DATE_MONTH,
VERSION_DATE_DAY,
VERSION_DATE_HOUR,
VERSION_DATE_MINUTE,
};
extern ret_code_t le_data_update(uint8_t * p_value, uint16_t len);
le_data_update((void *)cis_ver, sizeof(cis_ver));
}
static void vis_rst(uint8_t *ins, uint16_t size)
{
NRF_LOG_INFO("%s", __FUNCTION__);
}
static void dev_mode_ctrl_electrodes_task(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t dev_feat;
uint8_t opcode;
uint8_t param[];
} *p_ins = (void *)ins;
switch (p_ins->opcode)
{
case 0x05: {
// ctrl_electrodes_task suspend which elec pulse
// 3000FF 0205 80
uint16_t channel = p_ins->param[0];
suspend_which_electrodes(channel);
break;
}
case 0x06: {
// ctrl_electrodes_task resume which elec pulse
// 3000FF 0206 80
uint16_t channel = p_ins->param[0];
resume_which_electrodes(channel);
break;
}
case 0xA0:
// ctrl_electrodes_task set and start elec pulse
// 3000FF 02A0 C0 3F800000 000000FA 00000050
// 20 41200000 0000012C 00000000 0000001E E0 |....
start_electrodes_api(ins);
break;
case 0xA1:
// ctrl_electrodes_task stop elec pulse
// 3000FF 02A1 E0
stop_electrodes_api(ins);
break;
}
}
static void dev_mode_tw1508(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t mode_opcode; // dev mode could ignore
uint8_t dev_feat;
uint8_t dev_feat_opcode;
uint8_t param[];
} *p_ins = (void *)ins;
switch (u8_to_u16(p_ins->dev_feat, p_ins->dev_feat_opcode))
{
case 0x0100: {
// tw1508 init
// 3000FFFF 0100
tw1508_init();
break;
}
case 0x0101: {
// tw1508 set raw value
// 3000FFFF 0101 0005 0008
uint16_t out_0 = u8_to_u16(p_ins->param[0], p_ins->param[1]);
uint16_t out_1 = u8_to_u16(p_ins->param[2], p_ins->param[3]);
tw1508_set(out_0, out_1);
break;
}
case 0x0102: {
// tw1508 set mA float value
// 3000FFFF 0102 3F800000 40B00000
uint32_t out_0_mA_u32 = u8_to_u32(p_ins->param[0], p_ins->param[1], p_ins->param[2], p_ins->param[3]);
uint32_t out_1_mA_u32 = u8_to_u32(p_ins->param[4], p_ins->param[5], p_ins->param[6], p_ins->param[7]);
float out_0_mA_f;
float out_1_mA_f;
memcpy(&out_0_mA_f, &out_0_mA_u32, sizeof(out_0_mA_f));
memcpy(&out_1_mA_f, &out_1_mA_u32, sizeof(out_1_mA_f));
tw1508_set_mA(out_0_mA_f, out_1_mA_f);
break;
}
}
}
static void dev_mode_electrode_switch(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t mode_opcode; // dev mode could ignore
uint8_t dev_feat;
uint8_t dev_feat_opcode;
uint8_t param[];
} *p_ins = (void *)ins;
switch (u8_to_u16(p_ins->dev_feat, p_ins->dev_feat_opcode))
{
case 0x0400: {
// electrode_switch default
// 3000FFFF 0400
electrode_pulse_channel(ELEC_CH_ALL_HIGHZ);
break;
}
case 0x0401: {
// electrode_switch set val
// 3000FFFF 0401 0000
uint16_t elec_ch_setting = u8_to_u16(p_ins->param[0], p_ins->param[1]);
electrode_pulse_channel(elec_ch_setting);
break;
}
}
}
static void dev_mode_adapter_block_switch(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t mode_opcode; // dev mode could ignore
uint8_t dev_feat;
uint8_t dev_feat_opcode;
uint8_t param[];
} *p_ins = (void *)ins;
switch (u8_to_u16(p_ins->dev_feat, p_ins->dev_feat_opcode))
{
case 0x0200: {
// adapter_block_switch reset ADPT0/1 switch
// 3000FFFF 0200
adapter_channel(0b00000000);
break;
}
case 0x0201: {
// adapter_block_switch set ADPT0/1 switch
// 3000FFFF 0201 00FF
uint16_t channel = u8_to_u16(p_ins->param[0], p_ins->param[1]);
adapter_channel(channel);
break;
}
case 0x0202: {
// adapter_block_switch reset hv switch
// 3000FFFF 0202
sw_reset();
break;
}
case 0x0203: {
// adapter_block_switch set hv switch
// 3000FFFF 0203 00FF
uint16_t channel = u8_to_u16(p_ins->param[0], p_ins->param[1]);
high_volt_channel(channel);
break;
}
}
}
static void dev_mode_gpio(uint8_t *ins)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t mode_opcode; // dev mode could ignore
uint8_t dev_feat;
uint8_t dev_feat_opcode;
uint8_t param[];
} *p_ins = (void *)ins;
switch (u8_to_u16(p_ins->dev_feat, p_ins->dev_feat_opcode))
{
case 0xA000: {
// gpio - CPGv1.1 default gpio state
// 3000FFFF A000
cpg11_io_init();
break;
}
case 0xA001: {
// gpio - set single pin as output
// 3000FFFF A001 0006 0001
uint16_t pin_number = u8_to_u16(p_ins->param[0], p_ins->param[1]);
uint16_t high_low = u8_to_u16(p_ins->param[2], p_ins->param[3]);
set_single_pin_as_output(pin_number, high_low);
break;
}
case 0xA002: {
// gpio - set all pin as output
// 3000FFFF A002 0001
uint16_t high_low = u8_to_u16(p_ins->param[0], p_ins->param[1]);
for (int i = 1; i < ARRAY_SIZE(pin_to_gpio_table); i++)
{
set_single_pin_as_output(i, high_low);
nrf_delay_us(100);
}
break;
}
}
}
void dev_mode(uint8_t *ins, uint16_t size)
{
struct __PACKED
{
uint8_t id : 4;
uint8_t ins_type : 4;
uint8_t pkg_size;
uint8_t mode;
uint8_t mode_opcode; // dev mode could ignore
uint8_t dev_feat;
uint8_t dev_feat_opcode;
uint8_t param[];
} *p_ins = (void *)ins;
if (u8_to_u16(p_ins->mode, p_ins->mode_opcode) == 0xFF02)
{
dev_mode_ctrl_electrodes_task(ins);
return;
}
if (u8_to_u16(p_ins->mode, p_ins->mode_opcode) != 0xFFFF)
return;
switch (p_ins->dev_feat)
{
case 0x01:
dev_mode_tw1508(ins);
break;
case 0x02:
dev_mode_adapter_block_switch(ins);
break;
case 0x04:
dev_mode_electrode_switch(ins);
break;
// 0xA0 to 0xBF are reserved for controlling the BMD380
case 0xA0:
dev_mode_gpio(ins);
break;
case 0xA1:
// spi
break;
case 0xA2:
// i2c
break;
// 0xF0 to 0xFF are reserved for calibration
case 0xF0:
// cali
break;
default:
break;
}
}
const elite_instance_t cpg_elite_instance = {
.cis_func = {
[CIS_VERSION] = cis_version,
},
.vis_func = {
[VIS_RST] = vis_rst,
},
.ris_func = {
[DEV_MODE] = dev_mode,
}
};
const elite_instance_t *cpg_init(void)
{
NRF_LOG_INFO("[Board] FW ver: %02d%02d%02d %02d:%02d", VERSION_DATE_YEAR, VERSION_DATE_MONTH, VERSION_DATE_DAY, VERSION_DATE_HOUR, VERSION_DATE_MINUTE);
tw1508_init();
tw1508_set(5, 5); // 5*0.104= 0.52mA, formula:value*0.104=mA
return &cpg_elite_instance;
}
#endif