#include "globals.h" #include "lcd.h" #include "i2c.h" #include "flash.h" #include "device-functions.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 void initFlashValues(FlashStruct *mem); 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) { bool truncatelastbyte = false; 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); truncatelastbyte = true; 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, truncatelastbyte ? (hdr.length - 1) : hdr.length)); g_free(tempresult); return true; } void remount_root_as_writeable (gboolean start) { gchar *cmd; static GStaticMutex mutex = G_STATIC_MUTEX_INIT; if (start) { g_static_mutex_lock (&mutex); cmd = g_strdup_printf ("/usr/bin/mount -o remount,rw %s /", globals.HWDetect.remount_point); } else { cmd = g_strdup_printf ("/usr/bin/mount -o remount,ro %s /", globals.HWDetect.remount_point); } printf ("%s\n",cmd); system(cmd); g_free (cmd); if (!start) { g_static_mutex_unlock (&mutex); } } 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; printf ("start writeable: copy from backup\n"); remount_root_as_writeable (TRUE); persistence_copyfile(BACKUPFILE, MAINFILE); globals.Sys.flash_write_in_progress = FALSE; printf ("end writeable: copy from backup\n"); remount_root_as_writeable (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; printf ("start writeable: make backup\n"); remount_root_as_writeable (TRUE); bool backup_ok = persistence_copyfile(MAINFILE, BACKUPFILE); globals.Sys.flash_write_in_progress = FALSE; printf ("end writeable: make backup\n"); remount_root_as_writeable (FALSE); if (backup_ok && !globals.Sys.shutdown_started) { globals.Sys.flash_write_in_progress = TRUE; printf ("start writeable: write to main config file\n"); remount_root_as_writeable (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; printf ("end writeable: write to main config file\n"); remount_root_as_writeable (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,"AV-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->output_on_delay=DEFAULT_OUTPUT_ON_DELAY; // 0.8 seconds 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_inverted=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->self_cal_ref_freq = SELF_CAL_REF_FREQ; mem->self_cal_min_count = SELF_CAL_MIN_COUNT; mem->pcb116c_mon=1; /* more recent ADC, different reading code */ mem->warn_even_if_output_off=0; mem->enable_avrq_extra_ampls=0; for (i=0; islew_pwl[i][j][k][m]=0.0; mem->slew_dacval[i][j][k][m]=0; int temp_int; if (m==0) { /* These values have been determined by experiment. */ /* Double CH2 delays for -KMPF */ temp_int = dac_max; mem->period_pwl[i][j][k][m]=(47e-9*power_of_ten)+41e-9; mem->pw_pwl[i][j][k][m]=(6e-9*power_of_ten)+20e-9; mem->delay_pwl[i][j][k][m]=((6e-9*power_of_ten)+10e-9) * (i+1.0); mem->burst_pwl[i][j][k][m]=(22e-9*power_of_ten)+25e-9; } else if (m==1) { temp_int = dac_max/2.15; mem->period_pwl[i][j][k][m]=(100e-9*power_of_ten)+50e-9; mem->pw_pwl[i][j][k][m]=(14e-9*power_of_ten)+25e-9; mem->delay_pwl[i][j][k][m]=((14e-9*power_of_ten)+30e-9) * (i+1.0); mem->burst_pwl[i][j][k][m]=(33e-9*power_of_ten)+10e-9; } else if (m==2) { temp_int = dac_max/4.6; mem->period_pwl[i][j][k][m]=(230e-9*power_of_ten)+100e-9; mem->pw_pwl[i][j][k][m]=(28e-9*power_of_ten)+50e-9; mem->delay_pwl[i][j][k][m]=((28e-9*power_of_ten)+60e-9) * (i+1.0); mem->burst_pwl[i][j][k][m]=(50e-9*power_of_ten)+10e-9; } else if (m==3) { temp_int = dac_max / 10; mem->period_pwl[i][j][k][m]=(470e-9*power_of_ten)+160e-9; mem->pw_pwl[i][j][k][m]=(70e-9*power_of_ten)+80e-9; mem->delay_pwl[i][j][k][m]=((70e-9*power_of_ten))+90e-9 * (i+1.0); mem->burst_pwl[i][j][k][m]=(110e-9*power_of_ten)+10e-9; } else if (m==4) { temp_int = dac_max / 20 ; mem->period_pwl[i][j][k][m]=(900e-9*power_of_ten)+200e-9; mem->pw_pwl[i][j][k][m]=(140e-9*power_of_ten)+80e-9; mem->delay_pwl[i][j][k][m]=((140e-9*power_of_ten)+90e-9) * (i+1.0); mem->burst_pwl[i][j][k][m]=(220e-9*power_of_ten)+10e-9; } else { temp_int = 0; mem->pw_pwl[i][j][k][m]=0.0; mem->delay_pwl[i][j][k][m]=0.0; mem->period_pwl[i][j][k][m]=0.0; mem->burst_pwl[i][j][k][m]=0.0; } mem->pw_dacval[i][j][k][m]=temp_int; mem->delay_dacval[i][j][k][m]=temp_int; mem->period_dacval[i][j][k][m]=temp_int; mem->burst_dacval[i][j][k][m]=temp_int; // special overrides if ((m==4) && (j==0)) { // just 4 points in fastest PRF range, 5th point is flaky mem->period_dacval[i][j][k][m] = 0; mem->period_pwl[i][j][k][m] = 0.0; } } } power_of_ten*=10.0; power_of_two*=2.0; } power_of_two=20.0e-9; for (j=0; jrise_time_dacval[i][j][k][m]=dac_max; mem->rise_time_pwl[i][j][k][m]=(1e-9+power_of_two); } else if (m==1) { mem->rise_time_dacval[i][j][k][m]=dac_max/2; mem->rise_time_pwl[i][j][k][m]=(1e-9+(power_of_two*1.5)); } else if (m==2) { mem->rise_time_dacval[i][j][k][m]=dac_max/4.6; mem->rise_time_pwl[i][j][k][m]=(1e-9+(power_of_two*3.0)); } else { mem->rise_time_dacval[i][j][k][m]=0; mem->rise_time_pwl[i][j][k][m]=0.0; } } } power_of_two*=2.0; } for (j=0; jpw_range_pol_tweaks[i][j][k] = 0.0; } } for (k=0; k<5; k++) { for (m=0; m<2; m++) { j=0; mem->ampl_dacval[i][k][m][j]=0; mem->ampl_pwl[i][k][m][j]=0.0; mem->distort_dacval[i][k][m][j]=dac_max; /* EA shunt is max at zero ampl, zero at max ampl */ for (j=1; jampl_dacval[i][k][m][j]=0; mem->ampl_pwl[i][k][m][j]=0.0; mem->distort_dacval[i][k][m][j]=0; } } } mem->ampl_dacval[i][0][0][1]=dac_max; mem->ampl_pwl[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_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[i][0][0][0] = 200; mem->load_type_pwl[i][0][0][1] = 10000; mem->load_type_dacval[i][0][0][0] = dac_max; mem->load_type_dacval[i][0][0][1] = dac_max / 60; for (j=2; jload_type_pwl[i][0][0][j] = 0; mem->load_type_dacval[i][0][0][j] = 0; } mem->slew_pwl[i][4][0][0]=80e6; mem->slew_pwl[i][4][0][1]=240e6; mem->slew_pwl[i][3][0][0]=40e6; mem->slew_pwl[i][3][0][1]=120e6; mem->slew_pwl[i][2][0][0]=20e6; mem->slew_pwl[i][2][0][1]=60e6; mem->slew_pwl[i][1][0][0]=10e6; mem->slew_pwl[i][1][0][1]=30e6; mem->slew_pwl[i][0][0][0]=5e6; mem->slew_pwl[i][0][0][1]=15e6; mem->slew_dacval[i][0][0][1]=dac_max; mem->slew_dacval[i][1][0][1]=dac_max; mem->slew_dacval[i][2][0][1]=dac_max; mem->slew_dacval[i][3][0][1]=dac_max; mem->slew_dacval[i][4][0][1]=dac_max; } /* special consideration for CH2 delay */ mem->delay_pwl[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->os_zero_equiv[i]=0.01; 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->distort_fully_below_ampl[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->volt_ctrl_delay[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->rise_time_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; jos_dacval[i][k][0][j]=0; mem->os_pwl[i][k][0][j]=0.0; } } mem->os_dacval[i][0][0][1]=dac_max; mem->os_pwl[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->dead_time[i]=100e-9; 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]=NO; mem->max_avg_ampl[i]=0.0; mem->pol_relay_high_for_pos[i]=1; mem->zout_relay_high_for_max[i]=0; 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->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->max_freq_for_high_ot[i] = 0.0; mem->high_ot[i] = 0.0; for (j=0; jfixed_ampl_points[i][j] = 0.0; } mem->ext2_enabled[i] = 0; mem->toggle_trig_at_boot[i] = 1; mem->sequential_attenuators[i] = 0; mem->distort_dac[i] = 6; mem->distort_enabled[i] = 0; mem->double_pulse_extra_pw_margin[i] = 1.0; mem->double_pulse_extra_deadtime[i] = 100.0e-9; mem->double_pulse_min_sep[i] = 1.0e-6; } 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."); strcpy(mem->ot_error_message,"Over-heating problem. Output off."); strcpy(mem->ov_error_message,"Over-voltage/over-current. Output off."); /* 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? */ } 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; fix_initial_constants = 0; // handle change in model number location if ((mem->model_num[0] != 'A') && (mem->model_num[1] != 'V')) { strcpy(mem->model_num, mem->model_num_old); ++fix_initial_constants; } for (i=0; imin_burst_gap[i]; if ((mem->min_burst_per[i] - mem->min_pw[i]) > globals.Constraints.composite_min_burst_time[i]) { globals.Constraints.composite_min_burst_time[i] = mem->min_burst_per[i] - mem->min_pw[i]; } int j; float safe_val = 0.0; gboolean uses_fixed_ampl; uses_fixed_ampl = (number_of_fixed_ampl_points(i) > 0); safe_val = rst_ampl_value (i); for (j=0; jrcl_burst_time[i][j] < globals.Constraints.composite_min_burst_time[i]) { mem->rcl_burst_time[i][j]=globals.Constraints.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; } if (uses_fixed_ampl && !fixed_ampl_ok(i,mem->rcl_amplitude[i][j])) { // AVRQ-4-B mem->rcl_amplitude[i][j] = safe_val; ++fix_initial_constants; } if ((safe_val != 0.0) && (mem->rcl_amplitude[i][j] == 0.0)) { // AVR-D4-B, AVR-CD2-B CH2 mem->rcl_amplitude[i][j] = safe_val; ++fix_initial_constants; } } // for AVM-6-B in particular if ( (globals.Flash.fully_programmed==All_Programmed) && (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)); eprom_loc = (char *) &(mem->rcl_amplitude) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->rcl_amplitude)); eprom_loc = (char *) &(mem->model_num) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->model_num)); eprom_loc = (char *) &(mem->fix_pw_dac_val) - (char *) &(mem->flash_start); writeUserBlock(&globals.Flash, eprom_loc, sizeof(mem->fix_pw_dac_val)); } }