int main(int argc, char *argv[]) { uint8_t *tab_rp_bits; uint16_t *tab_rp_registers; uint16_t *rd_position_registers; uint16_t *tab_rp_registers_bad; modbus_t *ctx; /*********************************************************************** * feedback is used to store the return value of every called function * rc is used to store the return value of the modbus command * resend is used to define the resend times if the command is failed * i is used for the loop parameter * insert_bit is used to indicate the calibarate function if there is value to set * num is used to store the number of data blocks in database * use_backend is used to indicate the modbus mode is rtu * next_option is used to take the command options * pre_step, curr_step are used to indicate the previous step number and current position step number * pre_length and value indicate the latest posiotion in database and current position * SLEN is a kind of struct used to store the database blocks ************************************************************************/ int feedback,i; int insert_bit, nb_points,num =0; int next_option; long curr_step; double value; double pdepth,pspacing,pdwell,pinterval; double profiled,stopped; double depth,dwell,spacing,interval; double last_position; int profilebit =0,feedback1,feedback2; int modbus=0; int motor_stop = 0; char * command_arg = ""; char * return_value; double in_position = 0; SLEN *examp; ARF *config, *profile,*off_set; modbus_mapping_t *mb_mapping; int ShmID; int *ShmPTR; int stop_indicator = 0; key_t MyKey; MyKey = ftok(".", 's'); ShmID = shmget(MyKey, sizeof(int), IPC_CREAT | 0666); ShmPTR = (int *) shmat(ShmID, NULL, 0); tab_rp_registers = (uint16_t *) malloc(4 * sizeof(uint16_t)); rd_position_registers = (uint16_t *) malloc(2 * sizeof(uint16_t)); tab_rp_registers_bad = (uint16_t *) malloc(2 * sizeof(uint16_t)); config = (ARF*)malloc( 10 * sizeof(ARF) ); if ( config == NULL ) { printf("Error: Out of Memory, use ./master reset to reset memory\n"); exit(1); } const char *const short_options = "hd::u::l:p::cD::w::s::i::gSmt::"; const struct option long_options[] = { { "help", 0,NULL, 'h'}, { "down", 2,NULL, 'd'}, { "up", 2,NULL, 'u'}, { "length", 1,NULL, 'l'}, { "position", 2,NULL, 'p'}, { "count", 0,NULL, 'c'}, { "Depth", 2,NULL, 'D'}, { "well", 2,NULL, 'w'}, { "spacing", 2,NULL, 's'}, { "interval", 2,NULL, 'i'}, { "go", 0,NULL, 'g'}, { "System", 0,NULL, 'S'}, { "motor", 0,NULL, 'm'}, { "time", 2,NULL, 't'}, { NULL, 0, NULL, 0 }, }; if (argc < 2) { print_comusage (stderr, 1); return_value = json_option("status:",-1); return return_value; } program_name = argv[0]; /*Get the first argument that passed through main function but does not contain*/ command_name = argv[1]; if(argc > 2) { command_arg = argv[2]; } /******************************************************************************************* * The next three command_name are used to control the motor through modbus (need modbus) * ********************************************************************************************/ if ( strcmp(command_name, "go") == 0 ) { double curr_position; char *recd = (char*)malloc(10*sizeof(char)); double offset; int re_send = 0; *ShmPTR = 0; modbus = 1; next_option = getopt_long (argc, argv, short_options, long_options, NULL); if (next_option == -1) print_comusage (stderr, 1); while (next_option != -1) { switch (next_option) { case 'h': print_comusage(stdout, 0); case 'd': godown: enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); modbus = 1; feedback = godown(ctx); if((feedback == -1)&&(re_send <1)) { enable(0); initbus(0); re_send++; goto godown; } return_value = json_option("status",feedback); printf("%s\n",return_value); break; case 'u': goup: enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); modbus = 1; feedback = goup(ctx); if((feedback == -1)&&(re_send <1)) { enable(0); initbus(0); re_send++; goto goup; } return_value = json_option("status",feedback); printf("%s\n",return_value); break; case 'p': enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); modbus = 1; in_position = atof(optarg); off_set = (ARF*)malloc(15*sizeof(ARF)); off_set = getconfig(&num,off_set); offset = off_set[10].value; in_position = in_position - offset; free(off_set); //system("/home/sampler/kingkong.sh"); gotoposition: if (in_position <= 0)gotoposition(ctx,0,rd_position_registers); else { curr_position = checkposition(ctx,rd_position_registers); //printf("Position is %lf\n",curr_position); if ( !(( (in_position -0.1) <= curr_position ) && ( curr_position <= (in_position + 0.1) )) ) { feedback = gotoposition(ctx, in_position,rd_position_registers); return_value = json_option("status",feedback); //printf("%s\n",return_value); } } if((feedback == -1)&&(re_send <1)) { enable(0); initbus(0); enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); re_send++; } break; case '?': print_comusage (stderr, 1); default: abort (); } next_option = getopt_long (argc, argv, short_options, long_options, NULL); } //If the go command is failed, then exit the current process and power off the controller if(feedback == -1) { *ShmPTR = 1; enable(0); initbus(0); return_value = json_option("status",-1); return return_value; } //wait_stop(ShmPTR,ctx,tab_rp_registers); do { sleep(1); stop_indicator = *ShmPTR; }while ((checkmotorstatus(ctx,tab_rp_registers)!= 0 ) && (stop_indicator != 1)); sleep(1); //In order to avoid loop in checking position, get rid of using do-while curr_position = checkposition(ctx,rd_position_registers); if(curr_position != -1) { login("Go to command set last position"); curr_position = curr_position + offset; setconfig(9,curr_position); // In order to avoid "Read status command shutdown the power by accident" if( *ShmPTR == 0) { enable(0); initbus(0); *ShmPTR = 1; } return_value = json_option("status",1); } else return_value = json_option("status",-1); } if ( strcmp(command_name, "stop") == 0 ) { if(check_power() == 1) { sleep(1); ctx = modbusconnection(ctx); modbus = 1; feedback = stop(ctx); if(feedback == -1)stop(ctx); } } if ( strcmp(command_name, "position") == 0 ) { login("Check position command"); int resend = 0; double temp_position,offset; char *rec = (char*)malloc(10*sizeof(char)); stop_indicator = *ShmPTR; uint16_t * position_registers = (uint16_t *) malloc(2 * sizeof(uint16_t)); off_set = (ARF*)malloc(15*sizeof(ARF)); off_set = getconfig(&num,off_set); offset = off_set[10].value; checkposition: if (check_power()== 1) { ctx = modbusconnection(ctx); modbus = 1; temp_position = checkposition(ctx,position_registers); sprintf(rec,"The position read is %f",temp_position); login(rec); if(temp_position != -1) { login("Check position set last position"); //This sentence is used to show the position with offset temp_position = temp_position + offset; feedback = setconfig(9,temp_position); } else { if(resend < 2) { resend++; goto checkposition; } else return -100; } } else { config = getconfig(&num,config); temp_position = config[8].value; } return_value = json_float_option("status",temp_position); printf("%s\n",return_value); } /*********************************************************************** * 0: motor is stopped * * 1: motor is going down * * 2: motor is going up * * 3: motor is ramp up * * 4: motor is ramp down * * (need modbus) * * * ************************************************************************/ if(strcmp(command_name, "status") == 0) { stop_indicator = *ShmPTR; if (check_power()== 1) { sleep(1); ctx = modbusconnection(ctx); modbus = 1; next_option = getopt_long (argc, argv, short_options, long_options, NULL); if(next_option == -1) print_comusage (stderr, 1); while(next_option != -1) { switch (next_option) { case 'h': print_comusage(stdout, 0); case 'S': feedback = checksystemstatus(ctx,tab_rp_registers); return_value = json_option("status",feedback); break; case 'm': feedback = checkmotorstatus(ctx,tab_rp_registers); return_value = json_option("status",feedback); break; case '?': print_comusage (stderr, 1); default: abort (); } next_option = getopt_long (argc, argv, short_options, long_options, NULL); } if(feedback == -1) { return_value = json_option("status",0); } } else { return_value = json_option("status",0); //login("Check status from database"); } printf("%s\n",return_value); } /**************************************************************************************** * The next three command_name are used to control the database through sqlite3 * *****************************************************************************************/ if ( strcmp(command_name, "factory_default") == 0 ) { feedback1 = reset(0); feedback2 = dbinit(0); if ( (feedback1 == 1) && (feedback2 == 1)) { return_value = json_float_option("status",1); printf("%s\n",return_value); } else { return_value = json_float_option("status",-1); printf("%s\n",return_value); } } if ( strcmp(command_name, "reset") == 0 ) { feedback = reset(0); if(feedback == 1) { feedback = expected_time_reset(); } return_value = json_float_option("status",feedback); printf("%s\n",return_value); } if ( strcmp(command_name, "init") == 0 ) { feedback = -1; if ( strcmp(command_arg, "all") == 0 ) { feedback = dbinit(0); if(feedback == 1) { feedback = expected_time_init(); } } if ( strcmp(command_arg, "calibrate" ) == 0 ) { setconfig(6,0); feedback = dbinit(1); } if ( strcmp(command_arg, "configure" ) == 0 ) { feedback = dbinit(2); } if ( feedback == -1 ) { return_value = json_float_option("status",-1); print_comusage (stderr, 1); } else return_value = json_float_option("status",feedback); printf("%s\n",return_value); } if ( strcmp(command_name,"get") == 0 ) { examp = getall(&num,examp); return_value = json_array_option(num,examp); free(examp); printf("%s",return_value); } if ( strcmp(command_name,"set_offset") == 0 ) { double offset; next_option = getopt_long (argc, argv, short_options, long_options, NULL); if ( next_option == -1 ) print_comusage (stderr, 1); while( next_option != -1 ) { switch (next_option) { case 'h': print_comusage(stdout, 0); case 'l': if(optarg!=0)offset = strtod(optarg,NULL); insert_bit = 1; break; case '?': print_comusage (stderr, 1); default: abort (); } next_option = getopt_long (argc, argv, short_options, long_options, NULL); } feedback = setconfig(11,offset); return_value = json_option("status",feedback); printf("%s",return_value); } if ( strcmp(command_name,"get_offset") == 0 ) { double offset; off_set = (ARF*)malloc(15*sizeof(ARF)); off_set = getconfig(&num,off_set); offset = off_set[10].value; return_value = json_float_option("status",offset); printf("%s",return_value); free(off_set); } /************************************************************************** * The next three command_name are used to calibrate (need modbus) * ***************************************************************************/ if ( strcmp(command_name, "calibrate") == 0 ) { double calibrate; enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); modbus = 1; next_option = getopt_long (argc, argv, short_options, long_options, NULL); if ( next_option == -1 ) print_comusage (stderr, 1); config = getconfig(&num,config); calibrate = config[5].value; if ( calibrate == 0 ) { reset(1); setconfig(6,1.0); set(num,0,0); } while( next_option != -1 ) { switch (next_option) { case 'h': print_comusage(stdout, 0); case 'l': if(optarg!=0)value = atof(optarg); insert_bit = 1; break; case 'c': getall(&num,examp); return_value = json_option("status",num); printf("%s\n",return_value); break; case '?': print_comusage (stderr, 1); default: abort (); } next_option = getopt_long (argc, argv, short_options, long_options, NULL); } if ( insert_bit == 1 ) { curr_step = checksteps(ctx,rd_position_registers); if ( curr_step < 0 ) curr_step =0;//do not need feedback = checkvalue(curr_step,value); if ( feedback == 1 ) { feedback = set(num,curr_step,value); return_value = json_option("status",feedback); } else { return_value = json_option("status",-1); } } /*if ( checkmotorstatus(ctx,tab_rp_registers) == 0 ) { enable(0); initbus(0); }*/ printf("%s\n",return_value); } /*********************************************************************** * The following functions are used for profile * * * ************************************************************************/ if ( strcmp(command_name, "profile") == 0 ) { next_option = getopt_long (argc, argv, short_options, long_options, NULL); if ( next_option == -1 ) print_comusage (stderr, 1); while ( next_option != -1 ) { switch (next_option) { case 'h': print_comusage(stdout, 0); case 'd': if(optarg!=0)depth = atof(optarg); profilebit = 1; break; case 's': if(optarg!=0)spacing = atof(optarg); profilebit = 1; break; case 'w': if(optarg!=0)dwell = atof(optarg); profilebit = 1; break; case 'i': //if(optarg!=0)interval = atof(optarg); if(optarg!=0)interval = strtod(optarg,NULL); profilebit = 1; break; case '?': print_comusage (stderr, 1); default: abort (); } next_option = getopt_long (argc, argv, short_options, long_options, NULL); } if ( profilebit == 1 ) { feedback = set_profile(depth,spacing,dwell,interval); } //Want to get the expected profile time and save it in database profile_time_check(interval); return_value = json_float_option("status",feedback); printf("%s\n",return_value); } if ( strcmp(command_name, "profileget" ) == 0) { profile = getconfig(&num,config); return_value = json_profile_option(num-2,profile); free(profile); printf("%s",return_value); } if ( strcmp(command_name, "profile_check" ) == 0) { int *expected_profile_time; long remain_profile_time; config = getconfig(&num,config); pinterval = config[3].value; if(pinterval == 0) { printf("-999\n"); return -999; } expected_profile_time = (int*)malloc(10*sizeof(int)); if(expected_profile_time == NULL){printf("error\n");exit(1);} expected_time_get(expected_profile_time); remain_profile_time = auto_run(0,expected_profile_time); if(remain_profile_time <=0 )remain_profile_time = 0; printf("%d\n",remain_profile_time); free(expected_profile_time); return remain_profile_time; } if ( strcmp(command_name, "profile_reset") == 0 ) { //feedback = dbinit(2); //reading_hourly(); system("ps aux | grep -e 'master profilego' | grep -v grep | awk '{print $2}' | xargs -i kill {}"); feedback = set_profile(0,0,0,0); return_value = json_float_option("status",feedback); printf("%s\n",return_value); } if ( strcmp(command_name, "profilego") == 0 ) { double stayposition, curr_position,tmp,cal_position; double sdl_read,offset; long wait_time,motor_status; int year; time_t fail_time; modbus_t *sdl; int count,fini_count,re_try1 = 0,re_power1 =0,re_try = 0,re_send=0; int i=1,sample = 0,profile_times,sample_indicator; int * expected_tm, *curr_time,inter_val; *ShmPTR = 0; setconfig(10,0); //Will get the expected time from database and compare if it is roughly profile: config = getconfig(&num,config); pdepth = config[0].value; pspacing = config[1].value; pdwell = config[2].value; pinterval = config[3].value; profiled = config[4].value; sample = config[9].value; offset = config[10].value; profile_times = 1+(pdepth - offset)/pspacing; inter_val = (int)pinterval; if(pinterval == 0) exit(1); if(profiled == 0) { config = getconfig(&num,config); pdepth = config[0].value; pspacing = config[1].value; pdwell = config[2].value; pinterval = config[3].value; profiled = config[4].value; sample = config[9].value; expected_tm = (int*)malloc(10*sizeof(int)); curr_time = (int*)malloc(10*sizeof(int)); if(curr_time == NULL){printf("error\n");exit(1);} if(expected_tm == NULL){printf("error\n");exit(1);} do{ config = getconfig(&num,config); sample = config[9].value; expected_time_get(expected_tm); printf("Profile %d %d %d %d %d %d\n",expected_tm[0],expected_tm[1],expected_tm[2],expected_tm[3],expected_tm[4],expected_tm[5]); wait_time= auto_run(0,expected_tm); printf("Wait for %ds to profile\n",wait_time); curr_time = check_time(curr_time); printf("NOW %d %d %d %d %d %d\n",curr_time[0],curr_time[1],curr_time[2],curr_time[3],curr_time[4],curr_time[5]); sample_indicator = curr_time[3]%inter_val; //printf("%d\n",sample_indicator); if(wait_time < -600) { profile_time_check(pinterval); goto profile; } }while(wait_time>0); printf("quit\n"); free(expected_tm); printf("free\n"); four_minute_delay: sleep(1); curr_time = check_time(curr_time); if((curr_time[4]>=4) &&(curr_time[4]<=10))goto start_profile; if(curr_time[4]<4)goto four_minute_delay; if(curr_time[4]>10)goto profile; } start_profile: printf("start profile\n"); if(profiled == 0)process_profile(3,1,profile_times,0); enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); if(ctx == NULL)goto profile; modbus = 1; sleep(1); if ( profiled == 0 ) { printf("Start Profiling\n"); //Before go home, we do not need to check if it is home. gotoposition(ctx, 0,rd_position_registers); wait_for_stop(ctx, tab_rp_registers); //Set the profile flag setconfig(5,1); modbus_close(sdl); initbus(0); sleep(pdwell); } printf("After go home\n"); enable(0); printf("1\n"); initbus(1); sleep(1); ctx = modbusconnection(ctx); //This following part is used to determine where is destination curr_position = checkposition(ctx,tab_rp_registers) + offset; cal_position = i*pspacing + offset; if ( cal_position < pdepth ) { stayposition = cal_position; } else stayposition = pdepth; i++; stayposition = stayposition - offset; gotoposition(ctx,stayposition,tab_rp_registers); wait_for_stop(ctx, tab_rp_registers); //Here check position in order to determine if it is destination now curr_position = checkposition(ctx,tab_rp_registers)+offset; printf("before ser database\n"); setconfig(9,curr_position); printf("After set database\n"); printf("Go to sleep for dwell time\n"); initbus(0); sleep(pdwell); if (((pdepth -0.1) <= curr_position) && (curr_position <= (pdepth + 0.1))) { setconfig(5,0); profile_time_check(pinterval); printf("2\n"); enable(0); printf("3\n"); initbus(1); ctx = modbusconnection(ctx); gotoposition(ctx, 0,rd_position_registers); wait_for_stop(ctx, tab_rp_registers); sleep(1); enable(0); printf("4\n"); initbus(0); enable(1); //Save the position 0, set need_sleep to 0 and set stop indicate bit ShmPTR eqaul 1 printf("5before set datababase\n"); setconfig(9,offset); //Read the SDL data and store it in database sleep(40); } goto profile; } /*********************************************************************** * The next three command_name are used * * to control the date and time * ************************************************************************/ if ( strcmp(command_name, "checktime") == 0 ) { /*char *sdate; if ( (sdate = malloc( 80 * sizeof(char) ) )== NULL)return NULL; sdate = current_time(sdate); return_value = json_option_string("status",sdate); printf("%s\n",return_value); free(sdate); */ process_profile(3,1,3,1); } if ( strcmp(command_name, "settime") == 0 ) { if ( argc < 4 ) { print_comusage (stderr, 1); } char *date = argv[2]; char *time = argv[3]; int *buf = (int*)malloc(6*sizeof(int)); parse(buf,date,time); int i,m_buf[6]; for(i=0;i<=5;i++) { m_buf[i]=*(buf+i); } feedback = set_time(&m_buf); return_value = json_option("status:",feedback); printf("%s\n",return_value); login("Set local time"); login(return_value); sleep(5); } if ( strcmp(command_name, "voltage") == 0 ) { double voltage; voltage = voltage_read(); return_value = json_float_option("status",voltage); printf("%s\n",return_value); } if ( strcmp(command_name, "temp") == 0 ) { double temp; temp = temp_read(); return_value = json_float_option("status",temp); printf("%s\n",return_value); } if(strcmp(command_name, "enable_power") == 0) { enable(0); initbus(1); return_value = json_option("status:",1); } if(strcmp(command_name, "disable_power") == 0) { enable(0); initbus(0); return_value = json_option("status:",1); } if ( strcmp(command_name, "backup") == 0 ) { feedback = system("cp /home/sampler/lr.sl3 /home/sampler/lr_default.sl3"); if(feedback == -1) { return_value = json_float_option("status",-1); } else return_value = json_float_option("status",1); printf("%s\n",return_value); } if ( strcmp(command_name, "restore") == 0 ) { feedback = system("cp /home/sampler/lr_default.sl3 /home/sampler/lr.sl3"); if(feedback == -1) { return_value = json_float_option("status",-1); } else return_value = json_float_option("status",1); printf("%s\n",return_value); } if ( strcmp(command_name, "debug") == 0 ) { long return_steps; char *debug_result; enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); modbus = 1; uint16_t *debug_position_registers = (uint16_t*)malloc(2*sizeof(uint16_t)); debug_result = (char*)malloc(50*sizeof(char)); return_steps = checksteps(ctx,debug_position_registers); sprintf(debug_result,"%x,%x,%x\n",debug_position_registers[0],debug_position_registers[1],return_steps); json_option_string("status",debug_result); printf("%s\n",debug_result); initbus(0); } if ( strcmp(command_name, "power_check") == 0 ) { int power_status = check_power(); printf("Power is %d\n",power_status); } if ( strcmp(command_name, "sdl") == 0 ) { modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl != NULL) { double vol = sdltest(sdl); return_value = json_float_option("status",vol); printf("%s\n",return_value); setsdl(30000,vol); login("Read SDL"); login(return_value); } else setsdl(30000,-100000); modbus_close(sdl); modbus_free(sdl); } if ( strcmp(command_name, "sdl_reset") == 0 ) { resetsdl(); } if ( strcmp(command_name, "sdl_get") == 0 ) { int num_records; SLEN * sdl_records; sdl_records = (SLEN*)malloc(100*sizeof(SLEN)); sdl_records = getsdl(&num_records, sdl_records); return_value = json_sdl_option(num_records,sdl_records); printf("%s\n",return_value); free(sdl_records); } if ( strcmp(command_name, "sdl_uploadtime") == 0 ) { modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl == NULL) { setsdl(30000,-100000); } else sdl_setuploadtime(sdl,12,5,21,12,50,0); } if ( strcmp(command_name, "sdl_settime") == 0 ) { modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl == NULL) { setsdl(30000,-100000); } else sdl_rtc_time(sdl,12,5,25,7,58,0); } if ( strcmp(command_name, "sdl_readsize") == 0 ) { modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl == NULL) { setsdl(30000,-100000); } else sdl_readbuffsize(sdl); } if ( strcmp(command_name, "sdl_readsensor") == 0 ) { modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl == NULL) { setsdl(30000,-100000); } else sdl_read_sensor(sdl,1,1); } if ( strcmp(command_name, "sdl_upload") == 0 ) { //sdl_read_log_data(16); int number; modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl == NULL) { setsdl(30000,-100000); } else { profile_save_data(sdl); } modbus_close(sdl); } if ( strcmp(command_name, "sdl_sample") == 0 ) { int number; modbus_t * sdl; sdl = sdl_connection(sdl); if(sdl == NULL) { setsdl(30000,-100000); } else { sdl_read_sensor(sdl,1,1); sleep(60); sample_save_data(sdl); //sdl_start_profile(sdl,2); } modbus_close(sdl); } if ( strcmp(command_name, "shutdown") == 0 ) { feedback = system("/sbin/shutdown now"); } if ( strcmp(command_name, "maxstep") == 0 ) { enable(0); initbus(1); sleep(1); ctx = modbusconnection(ctx); modbus = 1; feedback = set_max_step(ctx,rd_position_registers); return_value = json_option("status",feedback); initbus(0); } if(strcmp(command_name, "slave") == 0) { slave(); } if(strcmp(command_name, "motor_status") == 0) { if (check_power()== 1) { sleep(1); ctx = modbusconnection(ctx); modbus = 1; feedback = checkmotorstatus(ctx,tab_rp_registers); if(feedback == -1) { printf("0\n"); return 0; } else { printf("%d\n",feedback); return feedback; } } else { printf("0\n"); return 0; } } close: /* Free the memory */ //free(tab_rp_bits); free(config); free(tab_rp_registers); free(rd_position_registers); //modbus_mapping_free(mb_mapping); /* Close the connection */ if (modbus == 1) { modbus_close(ctx); } if (motor_stop == 1) { printf("stop setting\n"); setconfig(9,last_position); } return return_value; }
void public_process_profile(std::shared_ptr<profiler> &p) { process_profile(p,0); };
/*---------------------------------------------------------------------------*/ static int vpc_route(vpc_route_t route) { vpc_lock.lock(); int ret; #ifdef CUSTOM_BOARD_WITH_AUDIENCE long session = 0; #endif uint32_t device_profile; /* -------------------------------------------------------------- */ /* Enter in this loop only for output device as they trig the */ /* establishment of the route */ /* -------------------------------------------------------------- */ if (current_device & AudioSystem::DEVICE_OUT_ALL) { LOGD("mode = %d device = 0x%X modem status = %d\n", current_mode, current_device, modem_status); LOGD("previous mode = %d previous device = 0x%X\n", prev_mode, prev_device); LOGD("current tty = %d previous tty = %d\n", current_tty_call, previous_tty_call); if (route == VPC_ROUTE_OPEN) { LOGD("VPC_ROUTE_OPEN request\n"); #ifdef CUSTOM_BOARD_WITH_AUDIENCE if (vpc_wakeup_audience()) goto return_error; #endif /* --------------------------------------------- */ /* Voice paths control for MODE_IN_CALL */ /* --------------------------------------------- */ if (current_mode == AudioSystem::MODE_IN_CALL) { LOGD("VPC IN_CALL\n"); if(modem_status != MODEM_UP) { LOGD("MODEM_DOWN or IN_RESET, cannot set a voicecall path!!!\n"); goto return_error; } /* MODEM is UP, apply the changes only if devices, or mode, or audio is not route due to modem reset or call disconnected */ if (vpc_route_conditions_changed()) { IFX_TRANSDUCER_MODE_SOURCE mode_source; IFX_TRANSDUCER_MODE_DEST mode_dest; switch (current_device) { /* ------------------------------------ */ /* Voice paths control for MSIC devices */ /* ------------------------------------ */ case AudioSystem::DEVICE_OUT_EARPIECE: case AudioSystem::DEVICE_OUT_SPEAKER: case AudioSystem::DEVICE_OUT_WIRED_HEADSET: case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: /* If VPC was not routed previously, avoid uncessary steps!!! */ if (vpc_get_audio_routed()) { amc_mute(); msic::pcm_disable(); /* Disable SCO path if a MSIC device is in use */ bt::pcm_disable(); amc_off(); } #ifdef CUSTOM_BOARD_WITH_AUDIENCE // Apply audience profile in separated thread process_profile(&session); mode_source = IFX_USER_DEFINED_15_S; mode_dest = IFX_USER_DEFINED_15_D; #else // No Audience, Acoustics in modem translate_to_amc_device(current_device, &mode_source, &mode_dest); #endif #ifdef ENABLE_TTY_PROFILE // Configure modem I2S1 amc_conf_i2s1(translate_vpc_to_amc_tty[current_tty_call], mode_source, mode_dest); #else // Configure modem I2S1 amc_conf_i2s1(current_tty_call, mode_source, mode_dest); #endif if ((prev_mode != AudioSystem::MODE_IN_CALL) || (prev_device & DEVICE_OUT_BLUETOOTH_SCO_ALL) || (!vpc_get_audio_routed())) { // Configure modem I2S2 and do the modem routing amc_conf_i2s2_route(); } amc_on(); #ifdef ENABLE_TTY_PROFILE msic::pcm_enable(current_mode, current_device, current_hac_setting, current_tty_call); #else msic::pcm_enable(current_mode, current_device, current_hac_setting); #endif mixing_enable = true; #ifdef CUSTOM_BOARD_WITH_AUDIENCE // Join with Audience thread wait_end_of_session(session); #endif #ifdef ENABLE_TTY_PROFILE #ifdef HAL_VPC_PLUS_6DB_MODEM_UL // TTY does not support the +6dB set on modem side. They must // be removed when TTY is used in FULL or HCO modes if (current_device == AudioSystem::DEVICE_OUT_WIRED_HEADSET && (current_tty_call == VPC_TTY_FULL || current_tty_call == VPC_TTY_HCO)) amc_unmute(modem_gain_dl, MODEM_GAIN_0dB); else #endif amc_unmute(modem_gain_dl, modem_gain_ul); #else //ENABLE_TTY_PROFILE amc_unmute(modem_gain_dl, modem_gain_ul); #endif break; /* ------------------------------------ */ /* Voice paths control for BT devices */ /* ------------------------------------ */ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO: case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET: case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT: /* If VPC was not routed previously, avoid uncessary steps!!! */ if (vpc_get_audio_routed()) { amc_mute(); msic::pcm_disable(); amc_off(); } // If is_acoustic_in_bt_device is true, bypass phone embedded algorithms // and use acoustic alogrithms from Bluetooth headset. device_profile = (is_acoustic_in_bt_device == true) ? device_out_defaut : current_device; #ifdef CUSTOM_BOARD_WITH_AUDIENCE ret = acoustic::process_profile(device_profile, current_mode, CURRENT_BAND_FOR_MODE(current_mode)); if (ret) goto return_error; mode_source = IFX_USER_DEFINED_15_S; mode_dest = IFX_USER_DEFINED_15_D; #else // No Audience, Acoustics in modem translate_to_amc_device(device_profile, &mode_source, &mode_dest); #endif // Do the modem config for BT devices amc_modem_conf_bt_dev(mode_source, mode_dest); amc_on(); bt::pcm_enable(); mixing_enable = true; amc_unmute(modem_gain_dl, modem_gain_ul); break; default: break; } // Restore record path if required handle_voice_call_record(); // Update internal state variables vpc_set_audio_routed(true); } /* Else: nothing to do, input params of VPC did not change */ } /* --------------------------------------------- */ /* Voice paths control for MODE_IN_COMMUNICATION */ /* --------------------------------------------- */ else if (current_mode == AudioSystem::MODE_IN_COMMUNICATION) { LOGD("VPC IN_COMMUNICATION\n"); if(modem_status == MODEM_COLD_RESET) { LOGD("MODEM_COLD_RESET, cannot set VoIP path !!!\n"); goto return_error; } /* MODEM is not in cold reset, apply the changes only if devices, or mode, or modem status was changed */ if (vpc_route_conditions_changed()) { switch (current_device) { /* ------------------------------------ */ /* Voice paths control for MSIC devices */ /* ------------------------------------ */ case AudioSystem::DEVICE_OUT_EARPIECE: case AudioSystem::DEVICE_OUT_SPEAKER: case AudioSystem::DEVICE_OUT_WIRED_HEADSET: case AudioSystem::DEVICE_OUT_WIRED_HEADPHONE: /* If VPC was not routed previously, avoid uncessary steps!!! */ if (vpc_get_audio_routed()) { msic::pcm_disable(); /* Disable SCO path if a MSIC device is in use */ bt::pcm_disable(); } #ifdef CUSTOM_BOARD_WITH_AUDIENCE #ifdef ENABLE_TTY_PROFILE ret = acoustic::process_profile(current_device, current_mode, CURRENT_BAND_FOR_MODE(current_mode)); #else //ENABLE_TTY_PROFILE if ((current_device & AudioSystem::DEVICE_OUT_WIRED_HEADSET) && current_tty_call != AMC_TTY_OFF) device_profile = device_out_defaut; else device_profile = current_device; ret = acoustic::process_profile(device_profile, current_mode, CURRENT_BAND_FOR_MODE(current_mode)); #endif if (ret) goto return_error; #endif #ifdef ENABLE_TTY_PROFILE msic::pcm_enable(current_mode, current_device, current_hac_setting, current_tty_call); #else msic::pcm_enable(current_mode, current_device, current_hac_setting); #endif break; /* ------------------------------------ */ /* Voice paths control for BT devices */ /* ------------------------------------ */ case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO: case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_HEADSET: case AudioSystem::DEVICE_OUT_BLUETOOTH_SCO_CARKIT: if (vpc_get_audio_routed()) { msic::pcm_disable(); } #ifdef CUSTOM_BOARD_WITH_AUDIENCE // If is_acoustic_in_bt_device is true, bypass phone embedded algorithms // and use acoustic alogrithms from Bluetooth headset. device_profile = (is_acoustic_in_bt_device == true) ? device_out_defaut : current_device; ret = acoustic::process_profile(device_profile, current_mode, CURRENT_BAND_FOR_MODE(current_mode)); if (ret) goto return_error; #endif bt::pcm_enable(); break; default: break; } // Update internal state variables vpc_set_audio_routed(true); } /* else: nothing to do, VPC input params did not change */ } /* else: nothing to do, mode not handled */ } /* Disable voice paths at the end of the call */ else if (route == VPC_ROUTE_CLOSE) { LOGD("VPC_ROUTE_CLOSE request\n"); if(current_mode == AudioSystem::MODE_IN_COMMUNICATION) { LOGD("current_mode: IN_COMMUNICATION\n"); /* * We are still in VoIP call but a modem cold reset * is going to be performed. * Need to close immediately MSIC / BT */ if(modem_status == MODEM_COLD_RESET) { LOGD("VPC IN_COMMUNICATION & MODEM COLD RESET\n"); vpc_unroute_voip(); vpc_suspend(); } else if(prev_mode == AudioSystem::MODE_IN_CALL && call_connected) { LOGD("VPC SWAP FROM IN_CALL TO IN_COMMUNICATION"); if (vpc_unroute_csvcall()) goto return_error; /* Keep audience awaken */ } /* Else: ignore this close request */ } else if(current_mode == AudioSystem::MODE_IN_CALL) { LOGD("current_mode: IN_CALL"); if(prev_mode == AudioSystem::MODE_IN_COMMUNICATION) { LOGD("VPC SWAP from IN_COMMUNICATION to IN_CALL"); vpc_unroute_voip(); /* Keep audience awaken */ } /* We are still in call but an accessory change occured * and a close request was initiated * Do not do anything except if the modem is not up anymore */ else if(modem_status != MODEM_UP || !call_connected) { LOGD("VPC from IN_CALL to IN_CALL with MODEM_DOWN or CALL NOT CONNECTED"); if (vpc_unroute_csvcall()) goto return_error; vpc_suspend(); } /* Else: ignore this close request */ } else { LOGD("current mode: out of CSV/VoIP call"); if (prev_mode == AudioSystem::MODE_IN_CALL) { LOGD("VPC from IN_CALL to NORMAL\n"); if (vpc_unroute_csvcall()) goto return_error; } else { LOGD("VPC from IN_COMMUNICATION to NORMAL\n"); vpc_unroute_voip(); } vpc_suspend(); } } else { LOGW("%s: Unknown route request %d: bail out\n", __FUNCTION__,route); } } else { LOGW("%s: VPC called for input device 0x%X in mode %d: should not occur\n", __FUNCTION__, current_device, current_mode); } vpc_lock.unlock(); return NO_ERROR; return_error: vpc_lock.unlock(); return NO_INIT; }