#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, ¶ms.e1_e2_amplitude_mA_u32, sizeof(e1_e2_amplitude_mA_f)); memcpy(&e3_e4_amplitude_mA_f, ¶ms.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(¶ms); 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