#include "globals.h" #include "lcd.h" #include "i2c.h" #include "version.h" #include "flash.h" #include #include #include #include #include #include #include #include #include #include #include #include #define MAINFILE "/root/flash.copy" #define BACKUPFILE "/root/flash.bup" #define PERSIST_ERR_COULDNTREADHDR 1 #define PERSIST_ERR_HDRLENMISMATCH 2 #define PERSIST_ERR_VERSIONMISMATCH 3 #define PERSIST_ERR_COULDNTREADDATA 4 #define PERSIST_ERR_BADCRC32 5 #define PERSIST_ERR_BADARGS 6 #define PERSIST_ERR_COULDNTALLOCATEBUFFER 7 #define PERSIST_ERR_COULDNTSEEK 8 #define PERSIST_ERR_COULDNTWRITE 9 #define PERSIST_ERR_COUNDNTOPENFILE 10 // safety check toggles #define FROZENSMALLEROK 1 #define FROZENBIGGEROK 0 // flash writing queue bits #define MAXQUEUEDJOBS 1 // This makes the queue a little bit pointless // but you might want to queue a few more typedef struct { FlashStruct *mem; int addr; int numbytes; } userflashjob; static bool alive = true; static GMutex writermutex; static GCond writerwakeup; static GCond writerqueueopen; static GThread* userflashwritethread; static GAsyncQueue* userflashwritequeue; // // crc32 routine static uint32_t crc32(uint8_t* buf, int count) { MHASH context = mhash_init(MHASH_CRC32B); mhash(context, buf, count); uint32_t hash; mhash_deinit(context, &hash); return hash; } // header to prepend to stashed objects typedef struct { uint32_t version; uint32_t length; uint32_t crc32; } persistencehdr; static void persistence_printheader(persistencehdr* hdr) { printf("Frozen struct has version %d, is %d bytes long and has the CRC32 0x%08"PRIx32"\n", hdr->version, hdr->length, hdr->crc32); } // copy a file from one place to another.. this is not portable, linux only // this returns true if it is safe to continue. If there was nothing to backup // that is considered "safe to continue" bool persistence_copyfile(char* source, char* dest) { mode_t filemode = S_IRUSR | S_IWUSR; int src = open(source, O_RDONLY); if (src < 0 && errno == ENOENT) { // If the source file doesn't exist, there isn't anything to copy close(src); return true; } int dst = open(dest, O_SYNC | O_RDWR | O_CREAT, filemode); if (src < 0 || dst < 0) { return false; } struct stat s; fstat(src, &s); ftruncate(dst, 0); sendfile(dst, src, NULL, s.st_size); close(src); close(dst); return true; } // store an object bool persistence_freeze(char* dest, void* data, unsigned int offset, unsigned int len, unsigned int total, uint32_t version) { // don't write past the end of the file.. if (offset + len > total) { errno = PERSIST_ERR_BADARGS; return false; } bool newfile = false; uint32_t crc; // open the target file with O_SYNC so that write blocks until it's on disk // fingers crossed the FS actually does what it's told.. int fd = open(dest, O_SYNC | O_RDWR); if (fd < 0) { // this is to catch if the file didn't exist and if it needed to be created mode_t filemode = S_IRUSR | S_IWUSR; fd = open(dest, O_SYNC | O_RDWR | O_CREAT, filemode); if (fd < 0) { errno = PERSIST_ERR_COUNDNTOPENFILE; return false; } newfile = true; } // if this is a new file or we're overwriting everything we can just calculate the CRC from the data passed in if (newfile || len == total) { // if this a new file we want to write everything irrespective of the offset and len passed in if (newfile) { offset = 0; len = total; } crc = crc32((uint8_t*) data, total); } // this is a modification within an existing file so we need to merge the existing data with the // new data to calculate the new crc for the file because it seems the struct getting passed in // only contains the changed data. else if (len != total) { // create a buffer for the existing data void* payload = malloc(total); if (payload == NULL) { close(fd); errno = PERSIST_ERR_COULDNTALLOCATEBUFFER; return false; } // get the header persistencehdr hdr; if (read(fd, &hdr, sizeof(persistencehdr)) != sizeof(persistencehdr)) { errno = PERSIST_ERR_COULDNTREADHDR; free(payload); close(fd); return false; } // load the data persistence_printheader(&hdr); if (read(fd, payload, hdr.length) != hdr.length) { errno = PERSIST_ERR_COULDNTREADDATA; free(payload); close(fd); return false; } // check the existing data isn't already corrupt. uint32_t calculatedcrc32 = crc32((uint8_t*) payload, hdr.length); if (calculatedcrc32 != hdr.crc32) { errno = PERSIST_ERR_BADCRC32; free(payload); close(fd); return false; } // overlay the payload with the existing data memcpy(((char*) payload) + offset, ((char*) data) + offset, len); crc = crc32((uint8_t*) payload, total); free(payload); lseek(fd, 0, SEEK_SET); // rewind } // build the header persistencehdr hdr; hdr.version = version; hdr.length = total; hdr.crc32 = crc; persistence_printheader(&hdr); // write the data to disk ftruncate(fd, sizeof(hdr) + total); // not really needed but if we did have a file thats bigger than it // should be put a stop to that // write the header if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) { errno = PERSIST_ERR_COULDNTWRITE; close(fd); return false; } // seek to the offset.. which could mean not seeking at all if (lseek(fd, offset, SEEK_CUR) < 0) { errno = PERSIST_ERR_COULDNTSEEK; // shouldn't ever happen really because if we're actually // seeking the file should already be the total size. close(fd); return false; } // write the data out to disk if (write(fd, ((char*) data) + offset, len) != len) { errno = PERSIST_ERR_COULDNTWRITE; close(fd); return false; } // pack up and go home close(fd); return true; } // try to load an object from disk bool persistence_unfreeze(char* dest, void* result, unsigned int len, uint32_t version) { int fd = open(dest, O_RDONLY); // get the header persistencehdr hdr; if (read(fd, &hdr, sizeof(persistencehdr)) != sizeof(persistencehdr)) { errno = PERSIST_ERR_COULDNTREADHDR; close(fd); return false; } persistence_printheader(&hdr); // check that the length of this frozen object is what we are expecting if (hdr.length != len) { #if FROZENSMALLEROK if (hdr.length < len) { printf("frozen struct is %d bytes smaller than the requested size, removing end byte\n", len - hdr.length); hdr.length -= 1; goto hdrlengthok; } #endif #if FROZENBIGGEROK if(hdr.length > len) { printf("frozen struct is bigger than the requested size, %d bytes will be truncated\n", hdr.length - len); goto hdrlengthok; } #endif errno = PERSIST_ERR_HDRLENMISMATCH; close(fd); return false; } hdrlengthok: // check that it's the same version.. the version isn't used at the moment // but if you want to change the header at some point it'll be useful if (hdr.version != version) { errno = PERSIST_ERR_VERSIONMISMATCH; close(fd); return false; } // read in the data for the object.. if we couldn't read the amount of data // that the header said there was the header is either wrong or the file is truncated. char* tempresult = g_malloc(hdr.length); if (read(fd, tempresult, hdr.length) != hdr.length) { errno = PERSIST_ERR_COULDNTREADDATA; close(fd); return false; } // check it's crc32 to make sure it's not corrupt uint32_t calculatedcrc32 = crc32(tempresult, hdr.length); if (calculatedcrc32 != hdr.crc32) { printf("Calculated CRC is 0x%08"PRIx32"\n", calculatedcrc32); errno = PERSIST_ERR_BADCRC32; close(fd); return false; } close(fd); memcpy(result, tempresult, MIN(len, hdr.length)); g_free(tempresult); return true; } static int readUserBlock(FlashStruct *mem) { // put the default values into the the struct; // what should happen here is that if we load // a smaller struct from disk it will replace // the top part and leave the defaults for newly // added values at the end initFlashValues(mem); // try to unfreeze the main file if (persistence_unfreeze(MAINFILE, mem, sizeof(*mem), 0)) { return sizeof(*mem); } // something went wrong else { printf("Error unfreezing %d.. trying backup\n", errno); // hopefully we can use the backup.. if (persistence_unfreeze(BACKUPFILE, mem, sizeof(*mem), 0)) { // if the backup was good overwrite the main file if (!globals.Sys.shutdown_started) { globals.Sys.flash_write_in_progress = TRUE; persistence_copyfile(BACKUPFILE, MAINFILE); globals.Sys.flash_write_in_progress = FALSE; } return sizeof(*mem); } // deadend :( else { printf("Error unfreezing backup %d.\n", errno); } } return 0; } void writeUserBlockNow(FlashStruct *mem, int addr, int numbytes) { // *** There is a potential issue here.. if the mainfile is corrupt *** // *** and this gets called before readUserBlock then the *** // *** potentially workable backup will be lost .. we could check *** // *** that the main file is valid before backing it up I guess... *** // *** but I don't think this situation should arise. *** static GStaticMutex mutex = G_STATIC_MUTEX_INIT; g_static_mutex_lock (&mutex); if (!globals.Flags.flash_writes_suspended) { // backup the main copy of the file if (!globals.Sys.shutdown_started) { globals.Sys.flash_write_in_progress = TRUE; bool backup_ok = persistence_copyfile(MAINFILE, BACKUPFILE); globals.Sys.flash_write_in_progress = FALSE; if (backup_ok && !globals.Sys.shutdown_started) { globals.Sys.flash_write_in_progress = TRUE; if (!persistence_freeze(MAINFILE, mem, addr, numbytes, sizeof(*mem), 0)) { if (errno != PERSIST_ERR_COULDNTWRITE) { printf("Error while trying to write, %d. **Write did not happen!!!**\n", errno); } else { printf("Error while writing data to disk. **File is potentially corrupt!**\n"); } } globals.Sys.flash_write_in_progress = FALSE; } else { printf("Could not backup current file. **Write did not happen!!!**\n"); } } } g_static_mutex_unlock (&mutex); } void writeUserBlock(FlashStruct *mem, int addr, int numbytes) { if (alive) { g_mutex_lock(&writermutex); if (g_async_queue_length(userflashwritequeue) >= MAXQUEUEDJOBS) { //printf("Queue closed, waiting\n"); g_cond_wait(&writerqueueopen, &writermutex); } g_mutex_unlock(&writermutex); userflashjob* job = g_malloc(sizeof(userflashjob)); job->mem = g_malloc(sizeof(FlashStruct)); memcpy(job->mem, mem, sizeof(FlashStruct)); job->addr = addr; job->numbytes = numbytes; g_async_queue_push(userflashwritequeue, job); g_cond_broadcast(&writerwakeup); } } static void initFlashValues(FlashStruct *mem) { int i,j,k,m; float power_of_ten, power_of_two; mem->flash_start=1; mem->turn_on_dly=5; mem->logic_level_enabled=0; mem->ChanKey_logic_level=0; strcpy(mem->model_num,"unprogrammed"); strcpy(mem->serial_num,"00000"); mem->fully_programmed=Being_Programmed; mem->gpib_address=8; mem->channels=1; mem->web_session_timeout=120; /* two minutes */ mem->telnet_session_timeout=600; /* ten minutes */ mem->telnet_logon_timeout=30; /* thirty seconds */ mem->baud = 1200; mem->parity = rs232_parity_none; // no longer used mem->stopbits = 1; // no longer used mem->databits = 8; // no longer used mem->hardhand = 1; mem->echo = 1; // no longer used mem->on_off_used=1; mem->ampl_ranges_for_ch2_only=0; mem->ChanKey_frequency=0; mem->ChanKey_delay=0; mem->ChanKey_pw=0; mem->ChanKey_current_limit=0; mem->ChanKey_rise_time=0; mem->ChanKey_amplitude=0; mem->ChanKey_offset=0; mem->ChanKey_Curr_Mon_value=0; mem->ChanKey_Curr_Mon_offset=0; mem->ChanKey_zout=0; mem->ChanKey_hold_setting=0; mem->ChanKey_double_pulse=0; mem->ChanKey_route=0; mem->ChanKey_slew=0; mem->ChanKey_func_mode=0; mem->ChanKey_polarity=0; mem->ChanKey_output_state=0; mem->ChanKey_gate_type=0; mem->ChanKey_trigger_source=0; mem->ChanKey_amp_mode=0; mem->ChanKey_gate_level=0; mem->ChanKey_load_type=0; mem->ChanKey_test_delay_mode=0; mem->ChanKey_os_mode=0; mem->ChanKey_Burst_Count=0; mem->ChanKey_Burst_Time=0; mem->vxi_enabled=0; mem->self_cal=0; mem->self_cal_interval=5; mem->self_cal_startups=0; mem->self_cal_pause=300; mem->self_cal_typical_time_min=6; mem->self_cal_typical_time_sec=0; mem->prf_limiter=1; mem->pcb116c_mon=1; /* more recent ADC, different reading code */ mem->warn_even_if_output_off=0; strcpy(mem->spec_func_lib,"Not used"); strcpy(mem->firmware,FW_VERSION); mem->enable_avrq_extra_ampls=0; for (i=0; ivcc1_pwl_Vc_norm4095[0][0][0][i]=0; mem->vcc1_pwl_amp[0][0][0][i]=0.0; mem->vcc2_pwl_Vc_norm4095[0][0][0][i]=0; mem->vcc2_pwl_amp[0][0][0][i]=0.0; } mem->vcc1_pwl_Vc_norm4095[0][0][0][1]=dac_max; mem->vcc1_pwl_amp[0][0][0][1]=10.0; mem->vcc2_pwl_Vc_norm4095[0][0][0][1]=dac_max; mem->vcc2_pwl_amp[0][0][0][1]=25; for (i=0; islew_pwl_time[i][j][k][m]=0.0; mem->slew_pwl_Vc_norm4095[i][j][k][m]=0; int temp_int_pw_dly, temp_int_prf; if (m==0) { /* these values have been determined by experiment */ temp_int_pw_dly=dac_max; temp_int_prf=dac_max; mem->period_pwl_time[i][j][k][m]=(47e-9*power_of_ten)+41e-9; mem->pw_pwl_time[i][j][k][m]=(6e-9*power_of_ten)+5e-9; mem->delay_pwl_time[i][j][k][m]=(6e-9*power_of_ten)+10e-9; mem->burst_pwl_time[i][j][k][m]=(22e-9*power_of_ten)+25e-9; } else if (m==1) { temp_int_pw_dly=dac_max/2.15; temp_int_prf=dac_max/2.15; mem->period_pwl_time[i][j][k][m]=(100e-9*power_of_ten)+50e-9; mem->pw_pwl_time[i][j][k][m]=(14e-9*power_of_ten)+10e-9; mem->delay_pwl_time[i][j][k][m]=(14e-9*power_of_ten)+30e-9; mem->burst_pwl_time[i][j][k][m]=(33e-9*power_of_ten)+10e-9; } else if (m==2) { temp_int_pw_dly=dac_max/4.6; temp_int_prf=dac_max/4.6; mem->period_pwl_time[i][j][k][m]=(230e-9*power_of_ten)+100e-9; mem->pw_pwl_time[i][j][k][m]=(28e-9*power_of_ten)+20e-9; mem->delay_pwl_time[i][j][k][m]=(28e-9*power_of_ten)+60e-9; mem->burst_pwl_time[i][j][k][m]=(50e-9*power_of_ten)+10e-9; } else if (m==3) { temp_int_pw_dly=dac_min; temp_int_prf=dac_min; mem->period_pwl_time[i][j][k][m]=(470e-9*power_of_ten)+160e-9; mem->pw_pwl_time[i][j][k][m]=(70e-9*power_of_ten)+40e-9; mem->delay_pwl_time[i][j][k][m]=(70e-9*power_of_ten)+90e-9; mem->burst_pwl_time[i][j][k][m]=(110e-9*power_of_ten)+10e-9; } else { temp_int_pw_dly=0; temp_int_prf=0; mem->pw_pwl_time[i][j][k][m]=0.0; mem->delay_pwl_time[i][j][k][m]=0.0; mem->period_pwl_time[i][j][k][m]=0.0; mem->burst_pwl_time[i][j][k][m]=0.0; } mem->pw_pwl_Vc_norm4095[i][j][k][m]=temp_int_pw_dly; mem->delay_pwl_Vc_norm4095[i][j][k][m]=temp_int_pw_dly; mem->burst_pwl_Vc_norm4095[i][j][k][m]=temp_int_pw_dly; mem->period_pwl_Vc_norm4095[i][j][k][m]=temp_int_prf; } } power_of_ten*=10.0; power_of_two*=2.0; } power_of_two=20.0e-9; for (j=0; jrise_time_pwl_Vc_norm4095[i][j][k][m]=dac_max; mem->rise_time_pwl_time[i][j][k][m]=(1e-9+power_of_two); } else if (m==1) { mem->rise_time_pwl_Vc_norm4095[i][j][k][m]=dac_max/2; mem->rise_time_pwl_time[i][j][k][m]=(1e-9+(power_of_two*1.5)); } else if (m==2) { mem->rise_time_pwl_Vc_norm4095[i][j][k][m]=dac_max/4.6; mem->rise_time_pwl_time[i][j][k][m]=(1e-9+(power_of_two*3.0)); } else { mem->rise_time_pwl_Vc_norm4095[i][j][k][m]=0; mem->rise_time_pwl_time[i][j][k][m]=0.0; } } } power_of_two*=2.0; } for (j=0; jpw_range_pol_tweaks[i][j][k] = 0.0; } } for (j=0; j<10; j++) for (k=0; k<5; k++) for (m=0; m<2; m++) { mem->ampl_pwl_Vc_norm4095[i][k][m][j]=0; mem->ampl_pwl_amp[i][k][m][j]=0.0; } mem->ampl_pwl_Vc_norm4095[i][0][0][1]=dac_max; mem->ampl_pwl_amp[i][0][0][1]=100.0; for (j=0; jrcl_frequency[i][j]=10000.0; mem->rcl_delay[i][j]=0e-9; mem->rcl_pw[i][j]=20e-9; mem->rcl_amplitude[i][j]=0.0; mem->rcl_offset[i][j]=0.0; mem->rcl_misc[i][j]=9; mem->rcl_misc2[i][j]=0; mem->rcl_burst_count[i][j]=1 && !mem->burst_func[i]; mem->rcl_burst_time[i][j]=500e-9; mem->rcl_rise_time[i][j]=50e-9; mem->rcl_soft_current_limit[i][j]=0.0; mem->rcl_route_primary[i][j]=1; mem->rcl_route_secondary[i][j]=1; mem->rcl_slew[i][j]=100e6; mem->rcl_load[i][j]=50.0; mem->rcl_vcc1[i][j]=0.0; mem->rcl_vcc2[i][j]=0.0; mem->rcl_vlogic[i][j]=0.0; } for (j=0; j<5; j++) for (k=0; k<2; k++) { mem->mon_vi_ratio[i][j][k]=0.050*(j+1); } mem->load_type_pwl_time[i][0][0][0] = 200; mem->load_type_pwl_time[i][0][0][1] = 10000; mem->load_type_pwl_Vc_norm4095[i][0][0][0] = dac_max; mem->load_type_pwl_Vc_norm4095[i][0][0][1] = dac_max / 60; for (j=2; j<10; j++) { mem->load_type_pwl_time[i][0][0][j] = 0; mem->load_type_pwl_Vc_norm4095[i][0][0][j] = 0; } mem->slew_pwl_time[i][4][0][0]=80e6; mem->slew_pwl_time[i][4][0][1]=240e6; mem->slew_pwl_time[i][3][0][0]=40e6; mem->slew_pwl_time[i][3][0][1]=120e6; mem->slew_pwl_time[i][2][0][0]=20e6; mem->slew_pwl_time[i][2][0][1]=60e6; mem->slew_pwl_time[i][1][0][0]=10e6; mem->slew_pwl_time[i][1][0][1]=30e6; mem->slew_pwl_time[i][0][0][0]=5e6; mem->slew_pwl_time[i][0][0][1]=15e6; mem->slew_pwl_Vc_norm4095[i][0][0][1]=dac_max; mem->slew_pwl_Vc_norm4095[i][1][0][1]=dac_max; mem->slew_pwl_Vc_norm4095[i][2][0][1]=dac_max; mem->slew_pwl_Vc_norm4095[i][3][0][1]=dac_max; mem->slew_pwl_Vc_norm4095[i][4][0][1]=dac_max; } /* special consideration for CH2 delay */ mem->delay_pwl_time[1][0][0][0]=-0.1e-9; for (i=0; irouting_required[i]=0; mem->routing_max_pins[i]=16; mem->min_ampl[i]=0.0; mem->max_ampl[i]=100.0; mem->min_offset[i]=0.0; mem->max_offset[i]=100.0; mem->min_vout[i]=0.0; mem->max_vout[i]=100.0; mem->min_freq[i]=1.0; mem->max_freq[i]=8e6; mem->min_pw[i]=25e-9; mem->max_pw[i]=1.0; mem->min_rise_time[i]=50e-9; mem->max_rise_time[i]=500e-9; mem->min_soft_current_limit[i]=10.0; mem->max_soft_current_limit[i]=530.0; mem->max_delay[i]=1.0; mem->min_delay[i]=0.0; mem->propagation_delay[i]=10.0e-9; mem->delay_shrink[i]=40.0e-9; mem->ampl_zero_equiv[i]=0.1; mem->max_duty_low[i]=110.0; mem->max_duty_high[i]=110.0; mem->duty_ampl[i]=30.0; mem->max_duty_mid1[i]=0.0; mem->duty_ampl_mid1[i]=0.0; mem->max_duty_mid2[i]=0.0; mem->duty_ampl_mid2[i]=0.0; mem->min_slew[i]=90e6; mem->max_slew[i]=210e6; mem->max_high_rl_duty[i]=80.0; mem->max_peak_power[i]=0.0; mem->max_avg_power[i]=0.0; mem->duty_highRL_above_v[i]=110.0; mem->duty_highRL_below_v[i]=110.0; mem->mon_pw_threshold[i]=-1.0; mem->monitor_step[i]=1.0; mem->sep_posneg_mon_ratio[i]=0; mem->volt_ctrl_pw[i]=0; mem->voltage_enabled[i]=1; mem->voltage_offset_enabled[i]=0; mem->current_enabled[i]=0; mem->current_offset_enabled[i]=0; mem->switchable_zout[i]=1; mem->dc_mode_allowed[i]=1; mem->pw_ab_mode_enabled[i]=1; mem->double_pulse_allowed[i]=1; mem->invert_allowed[i]=1; mem->ea_enabled[i]=1; mem->ew_enabled[i]=0; mem->switchable_load[i]=1; mem->monitor_enabled[i]=0; mem->use_pos_ampl_data_only[i]=0; mem->ampl_min_max_only[i]=0; mem->eo_enabled[i]=1; mem->ext_amplify_enabled[i]=1; mem->zout_min[i]=2; mem->zout_max[i]=50; for (j=0; j<10; j++) { for (k=0; k<5; k++) { mem->os_pwl_Vc_norm4095[i][k][0][j]=0; mem->os_pwl_amp[i][k][0][j]=0.0; } } mem->os_pwl_Vc_norm4095[i][0][0][1]=dac_max; mem->os_pwl_amp[i][0][0][1]=100.0; mem->ampl_DAC[i]=0; mem->os_DAC[i]=1; mem->polarity_xtra_rly[i]=1; mem->fixed_pw[i]=0; mem->fixed_rise_time[i]=1; mem->pcb_203a_rise_time[i]=1; mem->ext_amplify_xtra_rly[i]=4; mem->ea_xtra_rly[i]=5; mem->ew_xtra_rly[i]=5; mem->ignore_ampl_polarity[i]=0; mem->curr_slew[i]=0; mem->distort_X[i]=0.0; mem->distort_Y[i]=0.0; mem->distort_Z[i]=0.0; mem->distort_max_ampl[i]=0.0; mem->distort_max_os[i]=0.0; mem->ampl_os_ranges_related[i]=0; mem->ampl_coupled_to_os[i]=0; mem->pulse_width_pol_tweak[i][0]=0.0; mem->pulse_width_pol_tweak[i][1]=0.0; mem->delay_pol_tweak[i][0]=0.0; mem->delay_pol_tweak[i][1]=0.0; mem->max_burst_count[i]=1; mem->max_burst_duty[i]=50.0; mem->min_burst_per[i]=100e-9; mem->min_burst_gap[i]=100e-9; mem->max_burst_gap[i]=1.0; mem->is_func_gen[i]=0; mem->burst_func[i]=0; mem->freq_dac[i]=7; mem->is_monocycle[i]=0; mem->monocycle_dac[i]=6; mem->rise_time_dac[i]=6; mem->slew_dac[i]=6; mem->load_type_dac[i]=3; mem->output_timer[i]=0; mem->current_limit_pulse_mode[i]=220.0; mem->current_limit_dc_mode[i]=120.0; mem->current_limit_full_scale[i]=501.0; mem->current_limit_dac[i]=3; mem->hard_current_limit_enabled[i]=0; mem->soft_current_limit_enabled[i]=0; mem->invert_by_default[i]=pol_norm; mem->max_avg_ampl[i]=0.0; mem->pol_relay_high_for_pos[i]=1; mem->special_pw_range_minimum[i]=0.0; mem->pw_shift_below_this_ampl[i]=0.0; mem->pw_shift_below_ampl_by[i]=0.0; mem->ampl_min_abs_value[i]=0.0; mem->ampl_step_size[i]=0.0; mem->low_load_type[i]=50.0; mem->high_load_type[i]=10000.0; mem->fix_pw_dac_val[i]=dac_max/8; mem->max_pw_pol[i][0]=0.0; mem->max_pw_pol[i][1]=0.0; mem->vcc1_max[i]=5.1; mem->vcc2_max[i]=24.4; mem->vcc2_min[i]=3.0; mem->use_high_ampl_ranges_for_high_pw_ranges[i]=0; mem->couple_first_N_pw_ranges_to_ampl_ranges[i]=0; for (j=0; jattenuators[i][j] = 0.0; } mem->atten_percent_max_ampl[i] = 0.93; mem->force_monotonic_ext_trig_delay[i] = 0; } mem->relay_delay_in_sec=0.5; mem->extended_relay_delay_in_sec=0.5; strcpy(mem->aux_error_message,"PRF too high! Output disabled."); /* default PW DACs */ mem->pw_dac[0]=2; /* channel 1: ONLY used for EXTERNAL voltage-controlled PW */ /* DAC 4 is normally used for internally controlled PW */ mem->pw_dac[1]=2; /* channel 2: varies - normally 2 (for control of PCB 107C or 174) */ /* default delay DACs */ mem->delay_dac[0]=5; /* channel 1: on OP1B board - not to be changed, as a rule */ mem->delay_dac[1]=6; /* channel 2: varies (for control of PCB107C) */ /* originally Second_Dly_Port (for obsolete AVX-DD-A3-PS-TC) */ mem->I2C_port_for_CH2_delay = Second_PW_Port; // standard address for PCB 205A now mem->flash_end=99; for (i=0; i<8; i++) { mem->initial_dac_settings[i]=0L; } mem->copy_max_channels=max_channels; /* copy to flash, so it can be read by diag:eprom:int? */ /* avrq tests mem->enable_avrq_extra_ampls=1; mem->channels=2; mem->ChanKey_amplitude=1; mem->current_enabled[1]=1; mem->voltage_enabled[1]=0; mem->fully_programmed=2; mem->ampl_DAC[0]=-1; mem->ampl_pwl_amp[1][0][0][1]=0.025; mem->max_ampl[1]=0.022; mem->max_vout[1]=0.022; mem->ampl_zero_equiv[1]=0.001; */ } static gpointer userflashwritethreadfunc(gpointer data) { //printf("userflash write thread start\n"); while (alive || g_async_queue_length(userflashwritequeue) > 0) { // make sure the last job in the queue gets written if (g_async_queue_length(userflashwritequeue) == 0) { // go into a sleep g_mutex_lock(&writermutex); g_cond_wait(&writerwakeup, &writermutex); g_mutex_unlock(&writermutex); } else { userflashjob* job = (userflashjob*) g_async_queue_pop(userflashwritequeue); if (job != NULL ) { // process job //printf("processing write\n"); writeUserBlockNow(job->mem, job->addr, job->numbytes); g_free(job->mem); g_free(job); } // If someone is waiting for the queue to start accepting // jobs again and we are tell them about it.. if (g_async_queue_length(userflashwritequeue) < MAXQUEUEDJOBS) { g_mutex_lock(&writermutex); g_cond_broadcast(&writerqueueopen); g_mutex_unlock(&writermutex); } } } //printf("userflash write thread stop\n"); return NULL ; } void startFlashWriterThread() { alive= true; userflashwritequeue = g_async_queue_new(); userflashwritethread = g_thread_create(userflashwritethreadfunc, NULL, true, NULL); } void initFlash(FlashStruct *mem, gboolean reset_to_defaults, int starting_location) { startFlashWriterThread(); atexit(stopFlashWriterThread); int read_size = readUserBlock(mem); if ( (read_size == 0) || (mem->fully_programmed == Not_Programmed) || (reset_to_defaults && (starting_location >= 0) && (starting_location < sizeof(*mem))) ) { g_print_debug ("initializing flash memory\n"); LCD_write(0,0,"Initialize Flash Memory ..."); gchar *message = g_strdup_printf ("Initialize Flash Memory, %d - %d", starting_location, (int) sizeof(*mem)); LCD_write(0,0,message); g_free (message); // uninitialized device! initFlashValues(mem); // save the default Flash config, for nonvolatile persistence writeUserBlock(mem, starting_location, sizeof(*mem) - starting_location); LCD_write(1,0,"Flash Init, Done! "); } } void stopFlashWriterThread() { alive = false; g_cond_broadcast(&writerwakeup); g_thread_join(userflashwritethread); // block until the write thread is totally finished. g_async_queue_unref(userflashwritequeue); } void fixFlash(FlashStruct *mem) { int i, fix_initial_constants; float composite_min_burst_time[max_channels]; for (i=0; imin_burst_gap[i]; if ((mem->min_burst_per[i] - mem->min_pw[i]) > composite_min_burst_time[i]) { composite_min_burst_time[i] = mem->min_burst_per[i] - mem->min_pw[i]; } int j; for (j=0; jrcl_burst_time[i][j] < composite_min_burst_time[i]) { mem->rcl_burst_time[i][j]=composite_min_burst_time[i]; ++fix_initial_constants; } if (mem->rcl_rise_time[i][j] < mem->min_rise_time[i]) { mem->rcl_rise_time[i][j]=mem->min_rise_time[i]; ++fix_initial_constants; } if (mem->rcl_slew[i][j] < mem->min_slew[i]) { mem->rcl_slew[i][j]=mem->min_slew[i]; ++fix_initial_constants; } if (mem->rcl_soft_current_limit[i][j] < mem->min_soft_current_limit[i]) { mem->rcl_soft_current_limit[i][j]=mem->max_soft_current_limit[i]; ++fix_initial_constants; } } // for AVM-6-B in particular if ((mem->max_freq[i] >= 5e6) && (mem->fix_pw_dac_val[i] < dac_max/4)) { mem->fix_pw_dac_val[i] = dac_max/4; ++fix_initial_constants; } } if (fix_initial_constants) { int eprom_loc; eprom_loc = (char *) &(mem->rcl_burst_time) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->rcl_burst_time)); eprom_loc = (char *) &(mem->rcl_rise_time) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->rcl_rise_time)); eprom_loc = (char *) &(mem->rcl_slew) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->rcl_slew)); eprom_loc = (char *) &(mem->rcl_soft_current_limit) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->rcl_soft_current_limit)); } }