Compare commits

...

13 Commits

Author SHA1 Message Date
weiting2 9db0984a92 attempt to support "on change" for every register 2020-09-09 10:26:13 +08:00
weiting2 b9c9cc0bbc attempt to support "on change" for every register 2020-09-08 18:06:17 +08:00
weiting2 cd44c2ecaa attempt to support "on change" for every register 2020-09-08 17:47:12 +08:00
weiting2 3bb5cee129 attempt to support "on change" for every register 2020-09-08 17:42:08 +08:00
weiting2 2480d7775f attempt to support "on change" for every register 2020-09-08 17:19:13 +08:00
weiting2 3b9e972397 attempt to support "on change" for every register 2020-09-04 16:28:34 +08:00
weiting2 36df3abed1 attempt to support "on change" for every register 2020-09-02 19:19:05 +08:00
weiting2 918584c915 attempt to support "on change" for every register 2020-09-02 17:16:00 +08:00
weiting2 cc0a21c364 attempt to support "on change" for every register 2020-09-02 11:56:12 +08:00
weiting2 388c06efe7 attempt to support "on change" for every register 2020-08-31 16:35:12 +08:00
weiting2 8bcb4cd27e attempt to support "on change" for every register 2020-08-31 11:34:45 +08:00
weiting2 5d88871e58 attempt to support "on change" for every register 2020-08-28 18:25:02 +08:00
weiting2 8635b1b878 attempt to support "on change" for every register 2020-08-28 18:24:56 +08:00
8 changed files with 449 additions and 130 deletions
@@ -0,0 +1,138 @@
#ifndef DBS_OBJECT_H
#define DBS_OBJECT_H
#include "neu/headstage_spi.h"
#define SYS_RESERVED_INDEX 0
#define SYS_GENERAL_ENABLE_INDEX 1
#define SYS_LNA_BIOS1_INDEX 2
#define SYS_LNA_BIOS2_INDEX 3
#define REC_CHANNEL_INDEX 0
#define REC_GAIN_INDEX 1
#define REC_ADC_CLOCK_INDEX 2
#define STI_ENABLE_INDEX 0
#define STI_DURATION0_INDEX 1
#define STI_DURATION1_INDEX 2
#define STI_DURATION2_INDEX 3
#define STI_DURATION3_INDEX 4
#define STI_AMP_POS_INDEX 5
#define STI_AMP_NEG_INDEX 6
#define STI_POLARITY_INDEX 7
#define STI_CYCLE_CH01_INDEX 8
#define STI_CYCLE_CH23_INDEX 9
#define STI_CYCLE_CH45_INDEX 10
#define STI_CYCLE_CH67_INDEX 11
#define STI_CLK_RATIO_INDEX 12
#define STI_ARBITRARY_EN_INDEX 13
#define STI_MODE_INDEX 14
//#define DBS_REGISTER \
// uint8_t address; \
// void (*write_reg) (DBSRegister *self, uint32_t reg_value); \
// uint32_t (*read_reg) (DBSRegister *self)
typedef struct _DBSRegister{
uint8_t address;
bool WriteRegister, CheckRegister;
void (*write_reg) (struct _DBSRegister *self, uint16_t reg_value);
void (*read_reg) (struct _DBSRegister *self);
}DBSRegister;
void write_reg(DBSRegister *self, uint16_t reg_value){
spi_txbuf[0] = 0x80 | self->address;
spi_txbuf[1] = (reg_value >> 8) & 0xFF ;
spi_txbuf[2] = reg_value & 0xFF;
SPICallBack = ONE_SHOT_SPI;
headstage_spi_transaction(SPI_BUFFER_SIZE);
}
void read_reg(DBSRegister *self){
spi_txbuf[0] = 0x7F & self->address;
spi_txbuf[1] = 0x7F & self->address; // it's don't care actually
spi_txbuf[2] = 0x7F & self->address; // it's don't care actually
SPICallBack = READ_REG;
headstage_spi_transaction(SPI_BUFFER_SIZE);
}
static uint16_t sys_register_default_value[4] = {
0x0000,
0x40F2,
0x0210,
0x4210
};
static uint16_t rec_register_value[3];
static uint16_t sti_register_value[15];
static DBSRegister sys_register[4];
static DBSRegister rec_register[3];
static DBSRegister sti_register[15];
static void InitSysRegister(){
sys_register[SYS_RESERVED_INDEX].address = 0x00;
sys_register[SYS_GENERAL_ENABLE_INDEX].address = 47; // general enable
sys_register[SYS_LNA_BIOS1_INDEX].address = 57;
sys_register[SYS_LNA_BIOS2_INDEX].address = 58;
for(int i=0 ; i<sizeof(sys_register)/sizeof(DBSRegister) ; i++){
sys_register[i].WriteRegister = false;
sys_register[i].CheckRegister = false;
sys_register[i].write_reg = &write_reg;
sys_register[i].read_reg = &read_reg;
}
}
static void InitRecRegister(){
rec_register[REC_CHANNEL_INDEX].address = 48;
rec_register[REC_GAIN_INDEX].address = 49;
rec_register[REC_ADC_CLOCK_INDEX].address = 51; // sampling rate
for(int i=0 ; i<sizeof(rec_register)/sizeof(DBSRegister) ; i++){
rec_register[i].WriteRegister = false;
rec_register[i].CheckRegister = false;
rec_register[i].write_reg = &write_reg;
rec_register[i].read_reg = &read_reg;
}
}
static void InitStiRegister(){
sti_register[STI_ENABLE_INDEX].address = 46;
sti_register[STI_DURATION0_INDEX].address = 1;
sti_register[STI_DURATION1_INDEX].address = 2;
sti_register[STI_DURATION2_INDEX].address = 3;
sti_register[STI_DURATION3_INDEX].address = 4;
sti_register[STI_AMP_POS_INDEX].address = 37;
sti_register[STI_AMP_NEG_INDEX].address = 38;
sti_register[STI_POLARITY_INDEX].address = 40;
sti_register[STI_CYCLE_CH01_INDEX].address = 42;
sti_register[STI_CYCLE_CH23_INDEX].address = 43;
sti_register[STI_CYCLE_CH45_INDEX].address = 44;
sti_register[STI_CYCLE_CH67_INDEX].address = 45;
sti_register[STI_CLK_RATIO_INDEX].address = 52;
sti_register[STI_ARBITRARY_EN_INDEX].address = 54;
sti_register[STI_MODE_INDEX].address = 56;
for(int i=0 ; i<sizeof(sti_register)/sizeof(DBSRegister) ; i++){
sti_register[i].WriteRegister = false;
sti_register[i].CheckRegister = false;
sti_register[i].write_reg = &write_reg;
sti_register[i].read_reg = &read_reg;
}
}
static void InitDBSRegister(){
InitSysRegister();
InitRecRegister();
InitStiRegister();
// for(int i=1 ; i<sizeof(sys_register)/sizeof(DBSRegister) ; i++){
for(int i=1 ; i<4 ; i++){
sys_register[i].WriteRegister = true;
}
flag_notify(EVT_NEU_SPI);
}
#endif
@@ -160,13 +160,17 @@ static void FlushNotify();
#define NEU_REC_PARAM 0x20
#define NEU_MULTI_STI 0x40
#define NEU_TEST_INS 0x60
#define RIS_STOP_STI 0x80
#define RIS_REC_ON_CHANGE 0x80
#define RIS_STI_ON_CHANGE 0xA0
/** event */
#define EVT_NEU_SPI 0x0001 /**< spi transaction event */
#define EVT_NEU_LED 0x0002 /**< set led event */
#define EVT_NEU_CHECK 0x0004 /**< check neulive single instruction */
#define EVT_NEU_REG_SPI 0x0008 /** register spi event */
#define EVT_NEU_PREPARE 0x0010 /** prepare to record or stimulate **/
#define EVT_NEU_REC 0x0020
#define EVT_NEU_STI 0x0040
/** clock setting */
#define NEU_SYS_CLK 2000000 /**< 10Mhz */
@@ -298,7 +302,7 @@ typedef enum{
#include "string.h"
#include "headstage_rec_ins.h"
#include "headstage_sti_ins.h"
#include "headstage_dbs_object.h"
/*
* todo: need to define some procedure to detect this device status
@@ -338,53 +342,8 @@ static void headstage_init() {
#undef THREE_POINT_THREE_VOLT
}
/**
* @fn headstage_neu_append_notify_data
*/
#define CHANNEL_VALID (INSTRUCTION.recording_channel & (0x0001 << channel))
static void headstage_neu_append_notify_data() {
uint8_t channel = spi_rxbuf[0];
// close-reopen SPI, if the first channel received is invalid
if(IsFirstData){
// start record
if((INSTRUCTION.recording_channel & (0x0001 << channel)) && (channel < 16)){
IsFirstData = false;
}
// restart SPI
else{
SPI_close(headstage_spi_handle);
ReopenSPI();
IsFirstData = true;
return;
}
}
// discard illegal channel
// uint16_t valid_channel = INSTRUCTION.recording_channel & (0x0001 << channel);
if(!(INSTRUCTION.recording_channel & (0x0001 << channel)) || (channel > 15)){
// illegal channel
return;
}
uint8_t not_buf[3];
not_buf[0] = channel; // ch
not_buf[1] = spi_rxbuf[1];
not_buf[2] = spi_rxbuf[2];
// not_buf[1] = (INSTRUCTION.recording_channel | 0xFF00) >> 8;
// not_buf[2] = (INSTRUCTION.recording_channel | 0x00FF);
uint8_t data_size = headstage_notify_append_data(not_buf);
if (data_size >= BLE_NOT_BUFF_SIZE) {
headstage_notify_flip_buffer();
headstage_notify_send();
}
}
static void headstage_neu_state_spi();
static void headstage_neu_spi();
/**
* @fn headstage_neu_event
@@ -393,93 +352,27 @@ static void headstage_neu_state_spi();
*/
static void headstage_neu_event() {
if (EVENT_MASK == 0) {
// fast return
return;
}
if (flag_mask(EVT_NEU_SPI)) {
flag_disable(EVT_NEU_SPI);
headstage_neu_state_spi();
// headstage_neu_state_spi();
headstage_neu_spi();
}
if (flag_mask(EVT_NEU_LED)) {
flag_disable(EVT_NEU_LED); /** reserved to set led power and set color manually */
}
if (EVENT_MASK == 0) {
// fast return
}
if (flag_mask(EVT_DISCONNECTED)) {
ConnectState = false;
headstage_update_vis_instruction(VIS_INT);
}
}
/**
* @fn headstage_spi_callback
*
* description: callback function to deal with data transmission between DBS and CC2650
*/
static void headstage_spi_callback(SPI_Handle handle, SPI_Transaction* transaction) {
switch(SPICallBack){
case CONTINUOUS_TRANS:{
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
flag_notify(EVT_NEU_SPI);
break;
}
case FLUSH_BUFFER:{
SPICallBack = FLUSH_BUFFER2;
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
headstage_spi_transaction(SPI_BUFFER_SIZE);
break;
}
case FLUSH_BUFFER2:{
SPICallBack = ONE_SHOT_SPI;
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
flag_notify(EVT_NEU_SPI);
// headstage_spi_transaction(SPI_BUFFER_SIZE);
break;
}
case ONE_SHOT_SPI:{
SPICallBack = FLUSH_BUFFER;
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
headstage_spi_transaction(SPI_BUFFER_SIZE);
break;
}
case READ_MOSI:{
flag_notify(EVT_NEU_SPI);
break;
}
case READ_REG:{
check_reg_counter ++;
break;
}
case CLOSE_SPI:{
SPICallBack = ONE_SHOT_SPI;
SPI_close(headstage_spi_handle);
break;
}
case END_TRANSMIT:{
tx_put_u24(0, 0);
SPICallBack = CONTINUOUS_TRANS;
break;
}
default:{
break;
}
}
}
/**
* @fn headstage_update_ris_instruction
*
@@ -614,6 +507,37 @@ static void headstage_update_ris_instruction(uint8_t ins_len, uint8_t* instructi
break;
}
case RIS_REC_ON_CHANGE:{
uint16_t reg_value = instruction[2] << 8 | instruction[3];
switch(instruction[1]){
case REC_CHANNEL_INDEX:{
rec_register[REC_CHANNEL_INDEX].WriteRegister = true;
rec_register_value[REC_CHANNEL_INDEX] = reg_value;
flag_notify(EVT_NEU_SPI);
break;
}
case REC_GAIN_INDEX:{
rec_register[REC_GAIN_INDEX].WriteRegister = true;
rec_register_value[REC_GAIN_INDEX] = reg_value;
flag_notify(EVT_NEU_SPI);
break;
}
case REC_ADC_CLOCK_INDEX:{
rec_register[REC_ADC_CLOCK_INDEX].WriteRegister = true;
rec_register_value[REC_ADC_CLOCK_INDEX] = reg_value;
flag_notify(EVT_NEU_SPI);
break;
}
default:{
break;
}
}
break;
}
default: {
break;
}
@@ -1035,7 +959,7 @@ static void headstage_neu_state_spi() {
}
case NEU_READ_DATA: {
// recv sti enable command
// sti enable command
if( (rec_sti_command & ENABLE_STI) && !(rec_sti_command & STATUS_STI) ){
// go to send sti instruction
NEULIVE_STATE.state = NEU_WRITE_STI_INS;
@@ -1047,7 +971,7 @@ static void headstage_neu_state_spi() {
headstage_spi_transaction(SPI_BUFFER_SIZE);
}
// recv disable stimulation
// disable stimulation
else if( !(rec_sti_command & ENABLE_STI) && (rec_sti_command & STATUS_STI) ){
NEULIVE_STATE.state = NEU_STI_INT;
SPICallBack = ONE_SHOT_SPI;
@@ -1059,7 +983,6 @@ static void headstage_neu_state_spi() {
// recv disable recording
else if( !(rec_sti_command & ENABLE_REC) ){
rec_sti_command &= ~STATUS_REC;
headstage_led_color(COLOR_WHITE);
headstage_led_control();
if(rec_sti_command & STATUS_STI){
@@ -1274,4 +1197,142 @@ static void headstage_neu_state_spi() {
}
}
static uint8_t check_register_value(DBSRegister *dbs_register, uint8_t reg_size, uint16_t *value_to_fit);
static uint8_t write_register(DBSRegister *dbs_register, uint8_t reg_size, uint16_t *value_to_write);
typedef enum{
dbs_idle = 0x00,
dbs_prepare = 0x01,
dbs_recording = 0x02,
dbs_stimulate = 0x04
}dbs_status;
static void headstage_neu_spi(){
static dbs_status status;
// check system register if we have written it before
if( check_register_value(sys_register, sizeof(sys_register)/sizeof(DBSRegister), sys_register_default_value) ){
return;
}
// write system register
if (write_register(sys_register, sizeof(sys_register)/sizeof(DBSRegister), sys_register_default_value)){
return;
}
if(check_register_value(rec_register, sizeof(rec_register)/sizeof(DBSRegister), rec_register_value)){
return;
}
if(write_register(rec_register, sizeof(rec_register)/sizeof(DBSRegister), rec_register_value)){
return;
}
if(check_register_value(sti_register, sizeof(sti_register)/sizeof(DBSRegister), sti_register_value)){
return;
}
if(write_register(sti_register, sizeof(sti_register)/sizeof(DBSRegister), sti_register_value)){
return;
}
// enable recording channel
if(rec_register[REC_CHANNEL_INDEX].WriteRegister){
status |= dbs_prepare;
rec_register[REC_CHANNEL_INDEX].WriteRegister = false;
rec_register[REC_CHANNEL_INDEX].CheckRegister = true;
rec_register[REC_CHANNEL_INDEX].write_reg(rec_register+REC_CHANNEL_INDEX, rec_register_value[REC_CHANNEL_INDEX]);
return;
}
if(status & dbs_prepare){
status &= ~dbs_prepare;
if(rec_sti_command & ENABLE_REC){
status |= dbs_recording;
rec_sti_command |= STATUS_REC; // neu is recording now
}
// change LED base on working status
headstage_led_control();
AppendSPITX(0, 0);
SPICallBack = ONE_SHOT_SPI;
headstage_spi_transaction(SPI_BUFFER_SIZE);
return;
}
if(rec_sti_command & STATUS_REC){
if(!(rec_sti_command & ENABLE_REC)){
// terminate record
}
else{
headstage_neu_append_notify_data();
AppendSPITX(0, 0);
headstage_spi_transaction(SPI_BUFFER_SIZE);
}
}
//
// // it's recording
// if(rec_sti_command & STATUS_REC){
// if(!(rec_sti_command & ENABLE_REC)){
// // stop recording
// rec_register[REC_CHANNEL_INDEX].WriteRegister = false;
// rec_register[REC_CHANNEL_INDEX].CheckRegister = true;
// rec_register[REC_CHANNEL_INDEX].write_reg(rec_register+REC_CHANNEL_INDEX, value_to_write[REC_CHANNEL_INDEX]);
// }
// else{
// // keep recording
// headstage_neu_append_notify_data();
// AppendSPITX(0, 0);
// headstage_spi_transaction(SPI_BUFFER_SIZE);
// }
// }
}
#define RESEND_SPI_READ_NUMBER 3
static uint8_t check_register_value(DBSRegister *dbs_register, uint8_t reg_size, uint16_t *value_to_fit){
for(int i=0 ; i<reg_size ; i++){
if(dbs_register[i].CheckRegister){
if(check_reg_counter < RESEND_SPI_READ_NUMBER){
dbs_register[i].read_reg(dbs_register+i);
}
else{
// check register value
check_reg_counter = 0;
dbs_register[i].CheckRegister = false;
uint16_t ins_to_fit = value_to_fit[i];
uint16_t ins_recv = spi_rxbuf[1] << 8 | spi_rxbuf[2];
if(ins_recv != ins_to_fit){
SPI_close(headstage_spi_handle);
dbs_register[i].WriteRegister = true;
ReopenSPI();
dbs_register[i].write_reg(dbs_register+i, value_to_fit[i]);
}
else{
AppendSPITX(0, 0);
SPICallBack = ONE_SHOT_SPI;
headstage_spi_transaction(SPI_BUFFER_SIZE);
}
}
return 1;
}
}
return 0;
}
static uint8_t write_register(DBSRegister *dbs_register, uint8_t reg_size, uint16_t *value_to_write){
// start from index 1, since 0 is rec/sti enable
for(int i=1 ; i<reg_size ; i++){
if(dbs_register[i].WriteRegister){
dbs_register[i].WriteRegister = false;
dbs_register[i].CheckRegister = true;
dbs_register[i].write_reg(dbs_register+i, value_to_write[i]);
return 1;
}
}
return 0;
}
#endif
@@ -3,15 +3,15 @@
#define VERSION_DATE
#define VERSION_DATE_YEAR 20
#define VERSION_DATE_MONTH 7
#define VERSION_DATE_DAY 20
#define VERSION_DATE_HOUR 17
#define VERSION_DATE_MINUTE 48
#define VERSION_DATE_MONTH 9
#define VERSION_DATE_DAY 9
#define VERSION_DATE_HOUR 10
#define VERSION_DATE_MINUTE 26
// this is NOT the version hash !!
// it's the last version hash
#define VERSION_HASH 81d5d86890d1da5dfb3ccc7e1756261c3ecbf485
#define VERSION_GIT_BRANCH Neulive20_developement_linux
#define VERSION_HASH b9c9cc0bbcdb1ad375f9f5966577ca34ef3fd6d1
#define VERSION_GIT_BRANCH neulive20_development_without_central
static void get_board_name(char *board_name_ch, uint8 *board_name_int, uint8 name_size){
uint8 name_offset = 18;
@@ -13,6 +13,57 @@
static uint8_t not_buf_offset = NOT_BUF_OFFSET_INIT;
static uint32_t not_time_stamp = 0;
static void headstage_notify_set_timestamp();
static void headstage_notify_flip_buffer();
static uint8_t headstage_notify_append_data(uint8_t *data_value);
/**
* @fn headstage_neu_append_notify_data
*/
#define CHANNEL_VALID (INSTRUCTION.recording_channel & (0x0001 << channel))
static void headstage_neu_append_notify_data() {
uint8_t channel = spi_rxbuf[0];
// close-reopen SPI, if the first channel received is invalid
if(IsFirstData){
// start record
if((INSTRUCTION.recording_channel & (0x0001 << channel)) && (channel < 16)){
IsFirstData = false;
}
// restart SPI
else{
SPI_close(headstage_spi_handle);
ReopenSPI();
IsFirstData = true;
return;
}
}
// discard illegal channel
// uint16_t valid_channel = INSTRUCTION.recording_channel & (0x0001 << channel);
if(!(INSTRUCTION.recording_channel & (0x0001 << channel)) || (channel > 15)){
// illegal channel
return;
}
uint8_t not_buf[3];
not_buf[0] = channel; // ch
not_buf[1] = spi_rxbuf[1];
not_buf[2] = spi_rxbuf[2];
// not_buf[1] = (INSTRUCTION.recording_channel | 0xFF00) >> 8;
// not_buf[2] = (INSTRUCTION.recording_channel | 0x00FF);
uint8_t data_size = headstage_notify_append_data(not_buf);
if (data_size >= BLE_NOT_BUFF_SIZE) {
headstage_notify_flip_buffer();
headstage_notify_send();
}
}
static void headstage_notify_set_timestamp() {
not_time_stamp = headstage_time_stamp_us();
@@ -120,4 +120,72 @@ static void AppendSPITX(uint8_t index, uint32_t value){
}
}
/**
* @fn headstage_spi_callback
*
* description: callback function to deal with data transmission between DBS and CC2650
*/
static void headstage_spi_callback(SPI_Handle handle, SPI_Transaction* transaction) {
switch(SPICallBack){
case CONTINUOUS_TRANS:{
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
flag_notify(EVT_NEU_SPI);
break;
}
case FLUSH_BUFFER:{
SPICallBack = FLUSH_BUFFER2;
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
headstage_spi_transaction(SPI_BUFFER_SIZE);
break;
}
case FLUSH_BUFFER2:{
SPICallBack = ONE_SHOT_SPI;
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
flag_notify(EVT_NEU_SPI);
// headstage_spi_transaction(SPI_BUFFER_SIZE);
break;
}
case ONE_SHOT_SPI:{
SPICallBack = FLUSH_BUFFER;
for(int i=0 ; i<SPI_BUFFER_SIZE ; i++){
spi_txbuf[i] = 0x00;
}
headstage_spi_transaction(SPI_BUFFER_SIZE);
break;
}
case READ_MOSI:{
flag_notify(EVT_NEU_SPI);
break;
}
case READ_REG:{
check_reg_counter ++;
flag_notify(EVT_NEU_SPI);
break;
}
case CLOSE_SPI:{
SPICallBack = ONE_SHOT_SPI;
SPI_close(headstage_spi_handle);
break;
}
case END_TRANSMIT:{
tx_put_u24(0, 0);
SPICallBack = CONTINUOUS_TRANS;
break;
}
default:{
break;
}
}
}
#endif
@@ -561,6 +561,7 @@ static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1) {
headstage_init_device_info();
headstage_init();
InitDBSRegister();
for (;;) {
// Waits for a signal to the semaphore associated with the calling thread.