#include <string.h>
#include "FileReader.h"
#include "SequenceInput.h"
#include "StreamingInput.h"
FileReader::FileReader(int X, int Y, double tstep){
CorrectFile = true;
continueReading = true;
fileName = "";
}
void FileReader::reset(int X, int Y, double tstep){
CorrectFile = true;
continueReading = true;
fileName = "";
}
FileReader::FileReader(const FileReader& copy){
}
FileReader::~FileReader(void){
}
//-------------------------------------------------//
void FileReader::setDir(const char *s){
fileName = s;
}
//-------------------------------------------------//
bool FileReader::allocateValues(){
bool ret_correct;
fin.open(fileName);
if (!fin.good()) {
cout << "Could not open retina script file: " << fileName << ". Wrong retina file path?" << endl;
CorrectFile = false;
continueReading = false;
ret_correct = false;
} else
ret_correct = true;
return(ret_correct);
}
//-------------------------------------------------//
bool FileReader::nStringCopy(char *dest_buff, const char *src_str, size_t src_len, size_t dest_size){
bool correct_copy;
if(dest_size > 0 && dest_buff != NULL && src_str != NULL){ // Nothing to do if there is no space in destination buffer
size_t chars_to_copy;
if(src_len == (size_t)-1L) // If this paremeter is -1, we calculate the characters to copy from the source string length
chars_to_copy = strlen(src_str);
else
chars_to_copy = src_len; // Copy the number of chars specified through parameter src_len
if(chars_to_copy > dest_size-1){
correct_copy=false; // Not enough space in destination buffer
chars_to_copy = dest_size-1; // Copy as much characters as possible
} else
correct_copy=true;
memcpy(dest_buff, src_str, chars_to_copy); // Copy specified chars excluding the \0
dest_buff[chars_to_copy]='\0'; // Always add the \0 if there is some space in destinaton buffer
} else
correct_copy=false;
return(correct_copy);
}
//-------------------------------------------------//
char *FileReader::getNextToken(const char *str, const char *especial_tokens){
// fn state variables
static char ret_token[MAX_CHARS_PER_LINE+1]; // Internal buffer which is used to store tokens and return the last one
static const char *current_parsing_ptr = NULL; // Intenal fn state which remembers at which position of the input string the fn is parsing
static char *current_token_ptr; // Pointer to the remaining space of ret_token
// local variable
char *returned_token; // Pointer to the token returned
if(str == NULL){ // This fn has been called to inits its state (before first call to this fn for a new string)
current_parsing_ptr = NULL; // Reset internal pointer (fn state)
returned_token = NULL; // nothing to return
} else {
const char *next_token;
if(current_parsing_ptr == NULL){ // If it is first time we call this fn for a new string and init, the internal state is not initiallized yet
current_parsing_ptr = str; // Initialize internal state
current_token_ptr = ret_token; // Empty buffer of tokens
}
returned_token = current_token_ptr; // The current (returned) token will be stored in space pointed by current_token_ptr
next_token = strpbrk(current_parsing_ptr, especial_tokens); // Search for any of the tokens in str
if(next_token != NULL) { // especial token found
if(next_token > current_parsing_ptr) { // If there are characters before the found especial token:
nStringCopy(returned_token, current_parsing_ptr, next_token-current_parsing_ptr, MAX_CHARS_PER_LINE-(returned_token-ret_token)); // copy them as a new token
current_parsing_ptr = next_token; // Next parsing string position is the token found
} else { // No char before found especial token
nStringCopy(returned_token, next_token, 1, MAX_CHARS_PER_LINE-(returned_token-ret_token)); // copy especial token char as a new token
current_parsing_ptr = next_token + 1; // Next parsing string position is following the especial token found
}
} else { // No more tokens
size_t last_chars_len;
last_chars_len = strlen(current_parsing_ptr);
if(last_chars_len > 0) { // There was remaining chars in source string
nStringCopy(returned_token, current_parsing_ptr, -1, MAX_CHARS_PER_LINE-(returned_token-ret_token)); // copy all them (-1) as a new token
current_parsing_ptr += last_chars_len;
} else // No remaining chars
returned_token = NULL; // Return NULL
}
if(returned_token != NULL) // If a new token was found, update pointer to internal buffer
current_token_ptr = returned_token + strlen(returned_token)+1; // Next token will be stored following the current one
}
return(returned_token);
}
//-------------------------------------------------//
bool FileReader::parseLine(const char *in_line, char **out_tokens, int max_tokens){
const char * const espcial_tokens[] = { TOKENS_CMD, TOKENS_BLK, TOKENS_STR };
enum context_t {CTX_CMD=0, CTX_BLK, CTX_STR};
vector<enum context_t> context; // The status of the parser is a stack of contexts. Depending on the top context we use a different set of token delimiters
int token_ind; // Index to the currently parsed token
bool stop_parsing;
context.push_back(CTX_CMD); // We start parsing in the action command context
// parse subsequent tokens
token_ind = 0;
stop_parsing=false;
getNextToken(NULL, NULL); // Reset line parser
// Do while there is space in buffer and available tokens continue loop
while(!stop_parsing && token_ind < max_tokens && (out_tokens[token_ind]=getNextToken(in_line, espcial_tokens[context.back()])) != NULL) { // get token
// Process obtained token according to the current context:
switch(context.back()){
case CTX_CMD: // This is the outer context
switch(*out_tokens[token_ind]){ // Consider the first character of the token
case '#': // This a comment: stop parsing from here
out_tokens[token_ind] = NULL;
stop_parsing=true;
break;
case '{': // Start of block
context.push_back(CTX_BLK); // Change to block context
break;
case '}': // End of block
cout << "Syntax error: Found a } char which is not expected" << endl;
break;
case '\'': // Start of string
context.push_back(CTX_STR); // Change to string context
break;
case ' ': // Separators
case '\t':
case '.':
out_tokens[token_ind] = NULL;
token_ind--; // Discard these tokens in this context
break;
default: // Return the rest of tokens
break;
}
break;
case CTX_BLK: // This is the block context
switch(*out_tokens[token_ind]){
case '{': // Start of block
context.push_back(CTX_BLK); // Change to new block context
break;
case '}': // End of block
if(context.size() > 1) // There is more than one previous context
context.pop_back(); // Go back to previous context
else
cout << "Syntax error: Found a } char which is not expected" << endl;
break;
case '\'': // Start of string
context.push_back(CTX_STR); // Change to string context
break;
case ' ': // Separators
case '\t':
out_tokens[token_ind] = NULL;
token_ind--; // Discard these tokens in this context
break;
default: // Return the rest of tokens
break;
}
break;
case CTX_STR: // This is the string context
switch(*out_tokens[token_ind]){
case '\'': // End of string
if(context.size() > 1) // There is more than one previous context
context.pop_back(); // Go back to previous context
else
cout << "Syntax error: Found a ' char which is not expected" << endl;
break;
default: // Return the rest of tokens
break;
}
break;
}
token_ind++;
}
if(token_ind == max_tokens)
if(max_tokens > 0)
out_tokens[max_tokens-1] = NULL; // In case of implete parsing include token-list end mark
return (token_ind < max_tokens); // Return false if there was not enough space in out_tokens
}
//-------------------------------------------------//
// This method remove all the specified tokens from a token list
// token is a pointer to a list of pointers to string which contain the tokens to process. The
// last pointer of the pointer list must be NULL
// ign_tokens is a 0\-terminated string containing the tokens to discard
void FileReader::discardTokens(char **tokens, const char *ign_tokens){
size_t n_token;
size_t num_ign_tokens;
num_ign_tokens = strlen(ign_tokens); // Number of tokens in the ignore list
n_token=0;
while(tokens[n_token]){ // For each of the input tokens
size_t n_ign_token;
if(strlen(tokens[n_token]) == 1){ // All tokens to ignore have length 1, check if current token has length 1
// Search for the current input token in the token ignore list
for(n_ign_token=0; n_ign_token < num_ign_tokens && tokens[n_token][0] != ign_tokens[n_ign_token]; n_ign_token++); // Compare all the ignored tokens to the current token and loop while not found
if(n_ign_token < num_ign_tokens){ // Loop not finished, so current token has been found in the ignore list
size_t rem_token;
// Shift all the tokens in the list to remove the current token
for(rem_token=n_token; tokens[rem_token]; rem_token++) // After this loop the input token list now has one token less
tokens[rem_token]=tokens[rem_token+1];
} else
n_token++; // Pass to he next input token
} else
n_token++;
}
}
void FileReader::parseParameterBlock(char **block_tokens, module *new_module, int file_line) {
vector<double> param_values;
vector<string> param_ids;
size_t next_tok_idx; // Next token to parse in the received
next_tok_idx = 0;
// Check if we have more parameters to read
if(continueReading && block_tokens[next_tok_idx]){
if (strcmp(block_tokens[next_tok_idx], "{") == 0 && block_tokens[next_tok_idx+1]){ // parameter block start detected, read parameters
next_tok_idx++; // skip block-start token
while(continueReading && block_tokens[next_tok_idx]){
if(strcmp(block_tokens[next_tok_idx], "}") == 0){ // parameter block end detected, end reading parameters
break; // exit while loop
}else if (block_tokens[next_tok_idx+1]){ // There should be a value following the parameter name
param_ids.push_back(block_tokens[next_tok_idx]);
param_values.push_back(atof(block_tokens[next_tok_idx+1]));
next_tok_idx+=2;
if (!block_tokens[next_tok_idx]) // After each parameter-value tuple we should always find a token (at least block end)
abort(file_line,"Incorrect parameter block format: block-end character not found (at least in a correct place)");
}else
abort(file_line,"Incorrect parameter block format: apparent parameter name without value"); // abort() sets continueReading to false
}
} else
abort(file_line,"Incorrect start of parameter list");
}
// Set parsed module parameters
if(continueReading) {
continueReading = new_module->setParameters(param_values, param_ids);
if(!continueReading)
abort(file_line,"Error setting specified module parameters (incorrect parameter name or invalid value)");
}
}
//-------------------------------------------------//
void FileReader::parseFile(Retina &retina, DisplayManager &displayMg){
bool verbose = false;
int line = 0;
int action = 0;
while (!fin.eof() && CorrectFile && continueReading){
// read a line into memory
char line_buf[MAX_CHARS_PER_LINE];
// array to store memory addresses of the tokens in line_buf
char *token[MAX_TOKENS_PER_LINE];
line++;
fin.getline(line_buf, MAX_CHARS_PER_LINE); // Endline char not included
if(parseLine(line_buf, token, MAX_TOKENS_PER_LINE))
discardTokens(token, "'(),"); // These tokens are not meaningfull for the script syntax
else
abort(line,"Check tokens and delimiter characters");
if (continueReading && token[0]){
if(strcmp(token[0], "retina") == 0)
{
if(token[1]){
// Read action
if ( strcmp(token[1], "Create") == 0 ){
action = 1;
}
else if( strcmp(token[1], "Connect") == 0 ){
action = 2;
}
else if( strcmp(token[1], "TempStep") == 0 ){
action = 3;
}
else if( strcmp(token[1], "PixelsPerDegree") == 0 ){
action = 4;
}
else if( strcmp(token[1], "DisplayDelay") == 0 ){
action = 6;
}
else if( strcmp(token[1], "DisplayWindows") == 0 ){
action = 7;
}
else if( strcmp(token[1], "Input") == 0 ){
action = 8;
}
else if( strcmp(token[1], "DensityScheme") == 0 ){
action = 9;
}
else if( strcmp(token[1], "SetDensity") == 0 ){
action = 10;
}
else if( strcmp(token[1], "Show") == 0 ){
action = 11;
}
else if( strcmp(token[1], "DisplayZoom") == 0 ){
action = 12;
}
else if( strcmp(token[1], "multimeter") == 0 ){
action = 13;
}
else if( strcmp(token[1], "SimTime") == 0 ){
action = 14;
}
else if( strcmp(token[1], "NumTrials") == 0 ){
action = 15;
}
else if( strcmp(token[1], "Output") == 0 ){
action = 16;
}
else{
abort(line,"Unknown action command");
break;
}
}
}
else if (*token[0] != '#')
{
abort(line,"neither 'retina' nor '#' token found at line beginning");
break;
}
}
// retina configuration
if(continueReading){
if(action==11 || action==13) // If Action is Show or multimeter prepare Display Manager
displayMg.allocateValues(retina.getNumberModules(),retina.getStep()); // allocate values of Display Manager even if no Connect command is used
switch(action){
// Create
case 1:
if (token[2] && token[3]){
// read module type
module* newModule;
if (strcmp(token[2], "LinearFilter") == 0 ){
newModule = new LinearFilter(retina.getSizeX(),retina.getSizeY(),retina.getStep(),0.0);
}
else if (strcmp(token[2], "SingleCompartment") == 0 ){
newModule = new SingleCompartment(retina.getSizeX(),retina.getSizeY(),retina.getStep());
}
else if (strcmp(token[2], "StaticNonLinearity") == 0 ){
newModule = new StaticNonLinearity(retina.getSizeX(),retina.getSizeY(),retina.getStep(),0);
}
else if (strcmp(token[2], "CustomNonLinearity") == 0 ){
newModule = new StaticNonLinearity(retina.getSizeX(),retina.getSizeY(),retina.getStep(),1);
}
else if (strcmp(token[2], "SymmetricSigmoidNonLinearity") == 0 ){
newModule = new StaticNonLinearity(retina.getSizeX(),retina.getSizeY(),retina.getStep(),2);
}
else if (strcmp(token[2], "SigmoidNonLinearity") == 0 ){
newModule = new StaticNonLinearity(retina.getSizeX(),retina.getSizeY(),retina.getStep(),3);
}
else if (strcmp(token[2], "ShortTermPlasticity") == 0 ){
newModule = new ShortTermPlasticity(retina.getSizeX(),retina.getSizeY(),retina.getStep(),0.0,0.0,0.0,0.0,false);
}
else if (strcmp(token[2], "GaussFilter") == 0 ){
newModule = new GaussFilter(retina.getSizeX(),retina.getSizeY(),retina.getPixelsPerDegree());
}
else{
abort(line,"Unknown module type");
break;
}
// read parameters
if (token[4]){
if (strcmp(token[4], "{") == 0 && token[5]){
int i = 5;
vector<double> p;
vector<string> pid;
while(strcmp(token[i], "}") != 0 ){
if (token[i] && token[i+1]){
if (strcmp(token[i], "type") == 0 || strcmp(token[i], "spaceVariantSigma") == 0){
pid.push_back(token[i+1]);
p.push_back(0.0);
// Several values of E
}else if( strcmp(token[i], "E") == 0 && strcmp(token[i+1], "{") == 0){
while(strcmp(token[i+2], "}") != 0 ){
pid.push_back("E");
p.push_back(atof(token[i+2]));
i+=1;
}
}else{
pid.push_back(token[i]);
p.push_back(atof(token[i+1]));
}
i+=2;
}else{
abort(line,"Incorrect parameter format");
break;
}
if (!token[i]){
abort(line,"Incorrect parameter format");
break;
}
}
// Add module to the retina
if(continueReading){
continueReading=newModule->setParameters(p,pid);
if(continueReading){
retina.addModule(newModule,token[3]);
}else{
abort(line,"Error setting specified parameters (incorrect name or value)");
break;
}
}
}else{
abort(line,"Incorrect start of parameter list");
break;
}
}else{
abort(line,"No parameter start found");
break;
}
}
action = 0;
break;
// Connect
case 2:
if (token[2] && token[3] && token[4]){
vector <int> operations;
vector <string> modulesID;
// sequence of inputs
if (strcmp(token[2], "{") == 0 ){
int i = 3;
bool change = true;
while(strcmp(token[i], "}") != 0 ){
if (change){
modulesID.push_back(token[i]);
change=false;
}else{
if(strcmp(token[i],"+")==0){
operations.push_back(0);
}else if(strcmp(token[i],"-")==0){
operations.push_back(1);
}else if(strcmp(token[i],"/")==0){
operations.push_back(2);
}else
{
abort(line,"'+', '-', '/' operator found");
continueReading=false;
break;
}
change=true;
}
i+=1;
if (!token[i]){
abort(line,"Expected token not found in Connect parameter block");
continueReading=false; // Syntax error: do not continue
break;
}
}
// Connect from modulesID to token[i+1]
if(token[i+1] && token[i+2] && continueReading){
continueReading=retina.connect(modulesID,token[i+1],operations,token[i+2]);
if(verbose)cout << "Modules connected to "<< token[i+1] << endl;
if (!continueReading){
abort(line,"Error connecting expecified modules");
break;
}
}else{
abort(line,"Expected target module ID and connection type ('Current'/'Conductante') after list of source module IDs");
break;
}
}
// Only one input
else{
modulesID.push_back(token[2]);
continueReading=retina.connect(modulesID,token[3],operations,token[4]);
if (!continueReading){
abort(line,"Incorrect module IDs for Connect action command");
break;
}
if(verbose)cout << "Module " << token[2] << " connected to " << token[3] << endl;
}
}else{
abort(line,"Not enough parameters for Connect");
break;
}
action = 0;
break;
// Temporal step
case 3:
if (token[2]){
if (atof(token[2])>0)
retina.set_step(atof(token[2]));
else{
abort(line,"Expected positive value (>0)");
break;
}
}else{
abort(line,"Expected temporal step value");
break;
}
if(verbose)cout << "Temporal step = "<< atof(token[2]) << endl;
action = 0;
break;
// Pixels per degree
case 4:
if (token[2] && token[3] && token[4]){
if (strcmp(token[2], "{") == 0 && strcmp(token[4], "}") == 0){
if (atof(token[3])>0.0){
retina.setPixelsPerDegree(atof(token[3]));
if(verbose)cout << "Pixels per degree = " << atof(token[3]) << endl;
}
else{
abort(line,"Expected positive parameter (>0)");
break;
}
}else{
abort(line,"Expected '{' and '}' around parameter");
break;
}
}else{
abort(line,"Expected pixel per degree parameter");
break;
}
action = 0;
break;
// Display delay
case 6:
if (token[2]){
if (atof(token[2])>=0)
displayMg.setDelay(atof(token[2]));
else{
abort(line,"Expected positive or zero value (>=0)");
break;
}
}else{
abort(line,"Expected value of display delay");
break;
}
if(verbose)cout << "Display delay = "<< atof(token[2]) << endl;
action = 0;
break;
// Windows
case 7:
if (token[2]){
if (atof(token[2])>0)
displayMg.setImagesPerRow(atof(token[2]));
else{
abort(line,"Expected a positive value (>0)");
break;
}
}else{
abort(line,"Expected number of windows");
break;
}
if(verbose)cout << "Windows configured." << endl;
action = 0;
break;
// Input
case 8:
if (token[2] && token[3]){
// Input sequence
if(strcmp(token[2], "grating") == 0 ){
if (strcmp(token[3], "{") == 0 && strcmp(token[4],"type")==0 && strcmp(token[6],"step")==0 && strcmp(token[8],"length1")==0 && strcmp(token[10],"length2")==0 && strcmp(token[12],"length3")==0 && strcmp(token[14],"sizeX")==0 && strcmp(token[16],"sizeY")==0 && strcmp(token[18],"freq")==0 && strcmp(token[20],"period")==0 && strcmp(token[22],"Lum")==0 && strcmp(token[24],"Contr")==0 && strcmp(token[26],"phi_s")==0 && strcmp(token[28],"phi_t")==0 && strcmp(token[30],"orientation")==0 && strcmp(token[32],"red_weight")==0 && strcmp(token[34],"green_weight")==0 && strcmp(token[36],"blue_weight")==0 && strcmp(token[38],"red_phase")==0 && strcmp(token[40],"green_phase")==0 && strcmp(token[42],"blue_phase")==0 && strcmp(token[44],"}")==0){
continueReading=retina.generateGrating(atof(token[5]),atof(token[7]),atof(token[9]),atof(token[11]),atof(token[13]),atof(token[15]),atof(token[17]),atof(token[19]),atof(token[21]),atof(token[23]),atof(token[25]),atof(token[27]),atof(token[29]),atof(token[31]),atof(token[33]),atof(token[35]),atof(token[37]),atof(token[39]),atof(token[41]),atof(token[43]));
if(verbose)cout << "Grating generated." << endl;
}else{
abort(line,"Expected parameter list of grating: 'type','step','length1','length2','length3','sizeX','sizeY','freq','period','Lum','Contr','phi_s','phi_t','orientation','red_weight','green_weight','blue_weight','red_phase','green_phase','blue_phase'");
break;
}
}else if(strcmp(token[2], "fixationalMovGrating") == 0 ){
if (strcmp(token[3], "{") == 0 && strcmp(token[4],"sizeX")==0 && strcmp(token[6],"sizeY")==0 && strcmp(token[8],"circle_radius")==0 && strcmp(token[10],"jitter_period")==0 && strcmp(token[12],"spatial_period")==0 && strcmp(token[14],"step_size")==0 && strcmp(token[16],"Lum")==0 && strcmp(token[18],"Contr")==0 && strcmp(token[20],"orientation")==0 && strcmp(token[22],"red_weight")==0 && strcmp(token[24],"green_weight")==0 && strcmp(token[26],"blue_weight")==0 && strcmp(token[28],"type1")==0 && strcmp(token[30],"type2")==0 && strcmp(token[32],"switch")==0 && strcmp(token[34],"}")==0){
continueReading=retina.generateFixationalMovGrating(atof(token[5]),atof(token[7]),atof(token[9]),atof(token[11]),atof(token[13]),atof(token[15]),atof(token[17]),atof(token[19]),atof(token[21]),atof(token[23]),atof(token[25]),atof(token[27]),atof(token[29]),atof(token[31]),atof(token[33]));
if(verbose)cout << "Grating of fixational movements generated." << endl;
}else{
abort(line,"Expected parameter list of fixationalMovGrating: 'sizeX','sizeY','circle_radius','jitter_period','spatial_period','step_size','Lum','Contr','orientation','red_weight','green_weight','blue_weight','type1','type2','switch'");
break;
}
}else if(strcmp(token[2], "whiteNoise") == 0 ){
if (strcmp(token[3], "{") == 0 && strcmp(token[4],"mean")==0 && strcmp(token[6],"contrast1")==0 && strcmp(token[8],"contrast2")==0 && strcmp(token[10],"period")==0 && strcmp(token[12],"switch")==0 && strcmp(token[14],"sizeX")==0 && strcmp(token[16],"sizeY")==0 && strcmp(token[18],"}")==0){
continueReading=retina.generateWhiteNoise(atof(token[5]),atof(token[7]),atof(token[9]),atof(token[11]),atof(token[13]),atof(token[15]),atof(token[17]));
if(verbose)cout << "White noise generated." << endl;
}else{
abort(line,"Expected parameter list of whiteNoise: 'mean','contrast1','contrast2','period','switch','sizeX','sizeY'");
break;
}
}else if(strcmp(token[2], "impulse") == 0 ){
if (strcmp(token[3], "{") == 0 && strcmp(token[4],"start")==0 && strcmp(token[6],"stop")==0 && strcmp(token[8],"amplitude")==0 && strcmp(token[10],"offset")==0 && strcmp(token[12],"sizeX")==0 && strcmp(token[14],"sizeY")==0 && strcmp(token[16],"}")==0){
continueReading=retina.generateImpulse(atof(token[5]),atof(token[7]),atof(token[9]),atof(token[11]),atof(token[13]),atof(token[15]));
if(verbose)cout << "Impulse generated." << endl;
}else{
abort(line,"Expected parameter list of impulse: 'start','stop','amplitude','offset','sizeX','sizeY'");
break;
}
}else if(strcmp(token[2], "sequence") == 0 ){
module *new_input_module;
new_input_module = new SequenceInput(retina.getSizeX(), retina.getSizeY(), retina.getStep(), token[3]);
parseParameterBlock(token+4, new_input_module, line);
// Add module to the retina
if(continueReading) {
retina.addModule(new_input_module, "Input");
retina.setModuleInput();
if(verbose) cout << "Input configured as sequence of frames." << endl;
} else
break;
}else if(strcmp(token[2], "streaming") == 0 ){
module *new_input_module;
new_input_module = new StreamingInput(retina.getSizeX(), retina.getSizeY(), retina.getStep(), token[3]);
parseParameterBlock(token+4, new_input_module, line);
// Add module to the retina
if(continueReading) {
retina.addModule(new_input_module, "Input");
retina.setModuleInput();
if(verbose) cout << "Input configured as streaming video." << endl;
} else
break;
}else{
abort(line,"Unknown input type");
break;
}
}else{
abort(line,"Tokens for input action command not found");
break;
}
action = 0;
break;
// Density scheme
case 9:
if(verbose)cout << "New Density scheme created." << endl;
action = 0;
break;
// Density assignment
case 10:
if(verbose)cout << "Density assigned to modules." << endl;
action = 0;
break;
// Show windows
case 11:
if (token[2] && token[3] && token[4] && token[5]){
bool module_id_found;
// Search for the module ID
module_id_found=false;
continueReading=false;
for(int l=1;l<retina.getNumberModules();l++){ // For all retina modules except 0 (Input) with specified ID set isShown
module *m = retina.getModule(l);
string ID = m->getModuleID();
if(ID.compare(token[2])==0){
continueReading=true;
module_id_found=true;
if(strcmp(token[3],"True")==0){
displayMg.setIsShown(true,l);
if(verbose)cout << "Module "<< token[2] <<" is displayed." << endl;
// also input
//displayMg.setIsShown(true,0);
}
else if(strcmp(token[3],"False")==0){
displayMg.setIsShown(false,l);
if(verbose)cout << "Module "<< token[2] <<" is not displayed." << endl;
}
else{
abort(line,"Expected a 'True' or 'False' value after module ID");
break;
}
if(atof(token[5])>=0){
displayMg.setMargin(atof(token[5]),l);
}
}
}
// Check for input
if(strcmp(token[2],"Input")==0){
continueReading=true;
if(strcmp(token[3],"True")==0){
displayMg.setIsShown(true,0);
if(verbose)cout << "Module "<< token[2] <<" is displayed." << endl;
}
else if(strcmp(token[3],"False")==0){
displayMg.setIsShown(false,0);
if(verbose)cout << "Module "<< token[2] <<" is not displayed." << endl;
}
else{
abort(line,"Expected 'True' or 'False' value for Input");
break;
}
if(atof(token[5])>=0){
displayMg.setMargin(atof(token[5]),0);
}
}
else
if(!module_id_found)
abort(line,"Specified module ID not found");
}else{
abort(line,"Parameters for Show window not found");
break;
}
action = 0;
break;
// Window Zoom
case 12:
if (token[2] && token[3] && token[4]){
if (strcmp(token[2], "{") == 0 && strcmp(token[4], "}") == 0){
if (atof(token[3])>0.0){
displayMg.setZoom(atof(token[3]));
if(verbose)cout << "Display zoom = " << atof(token[3]) << endl;
}
else{
abort(line,"Expected a positive value (>0)");
break;
}
}else{
abort(line,"Expected '{' and '}' around parameter value");
break;
}
}else{
abort(line,"Expected parameters for Windows Zoom not found");
break;
}
action = 0;
break;
// multimeter
case 13:
if (token[2] && token[3] && token[4] && token[5]){
// read multimeter type
if (strcmp(token[2], "spatial") != 0 && strcmp(token[2], "temporal") != 0 && strcmp(token[2], "Linear-Nonlinear") != 0)
{
abort(line,"Expected any of the parameters for multimeter: 'spatial','temporal','Linear-Nonlinear'");
break;
}
// read parameters
if (token[5]){
if (strcmp(token[5], "{") == 0){
// check the module exists
continueReading=false;
if(strcmp("Input",token[4])==0){
continueReading=true;
}else{
for(int s=1;s<retina.getNumberModules();s++){
if(retina.getModule(s)->checkID(token[4]))
continueReading=true;
}
}
// select type
if(continueReading){
if (strcmp(token[2], "spatial") == 0 && token[6] && token[7] && token[8] && token[9] && token[10] && token[11] && token[12] && token[13] && token[14]){
if(strcmp(token[6], "timeStep") == 0 && strcmp(token[8], "rowcol") == 0 && strcmp(token[10], "value") == 0 && strcmp(token[13], "Show") == 0){
if(strcmp(token[9], "True") == 0)
displayMg.addMultimeterTempSpat(token[3],token[4],atof(token[11]),atof(token[7]),false,token[14]);
else if(strcmp(token[9], "False") == 0)
displayMg.addMultimeterTempSpat(token[3],token[4],-atof(token[11]),atof(token[7]),false,token[14]);
else
continueReading=false;
}else{
abort(line,"Expected spatial multimeter parameter list: 'timeStep','rowcol','value','Show'");
break;
}
}else if(strcmp(token[2], "temporal") == 0 && token[6] && token[7] && token[8] && token[9] && token[10] && token[11] && token[12]){
if(strcmp(token[6], "x") == 0 && strcmp(token[8], "y") == 0 && strcmp(token[11], "Show") == 0){
displayMg.addMultimeterTempSpat(token[3],token[4],atof(token[7]),atof(token[9]),true,token[12]);
}else{
abort(line,"Expected temporal multimeter parameter list: 'x','y','Show'");
break;
}
}else if(strcmp(token[2], "Linear-Nonlinear") == 0 && token[6] && token[7] && token[8] && token[9] && token[10] && token[11] && token[12] && token[13] && token[14] && token[15] && token[16] && token[17] && token[18] && token[19] && token[20]){
if(strcmp(token[6], "x") == 0 && strcmp(token[8], "y") == 0 && strcmp(token[10], "segment") == 0 && strcmp(token[12], "interval") == 0 && strcmp(token[14], "start") == 0 && strcmp(token[16], "stop") == 0 && strcmp(token[18], "Show") == 0){
displayMg.addMultimeterLN(token[3],token[4],atof(token[7]),atof(token[9]),atof(token[11]),atof(token[13]),atof(token[15]),atof(token[17]),token[19]);
}else{
abort(line,"Expected Linear-Nonlinear multimeter parameter list: 'x','y','segment','interval','start','stop','Show'");
break;
}
}
else{
abort(line,"Expected any of the multimeter types ('spatial', 'temporal', 'Linear-Nonlinear') and corresponding parameters");
break;
}
}
else{
abort(line,"Parameter syntax error or specified module ID not found");
break;
}
}else{
abort(line,"Expected parameter list start token ('{')");
break;
}
}else{
abort(line,"Expected parameter token");
break;
}
}else{
// Shouldn't we abort here?
}
action = 0;
break;
// Simulation time
case 14:
if (token[2]){
if (atof(token[2])>0)
retina.setTotalSimTime(atof(token[2]));
else{
abort(line,"Expected a positive time value (>0)");
break;
}
}else{
abort(line,"Expected simulation time value");
break;
}
if(verbose)cout << "Simulation time = "<< atof(token[2]) << endl;
action = 0;
break;
// Number of trials
case 15:
if (token[2]){
if (atof(token[2])>0)
retina.setSimTotalTrials(atof(token[2]));
else{
abort(line,"Expected a positive value (>0)");
break;
}
}else{
abort(line,"Expected number of trials value");
break;
}
if(verbose)cout << "Number of trials = "<< atof(token[2]) << endl;
action = 0;
break;
// Output
case 16:
if(token[2] && token[3]){ // Check that at least we can read the output type and its ID
if(strstr(token[3], "Output") == token[3]){ // Check if the specified module ID contains the substring Output at the beggining of the ID
// read module type
int next_tok_idx; // Next token to parse
module *newModule;
vector<double> p;
vector<string> pid; // Parameter list
if (strcmp(token[2], "spikes") == 0 ) {
string output_filename;
if (token[4] && strcmp(token[4], "{") != 0){ // the next token is not {, assume that it is the output filename
output_filename=token[4]; // Replace (default) filename
next_tok_idx=5; // Pass to the next token to continue reading parameters
} else {
output_filename=""; // Use the default filename
next_tok_idx=4; // continue reading parameters from this current token
}
newModule = new SpikingOutput(retina.getSizeX(), retina.getSizeY(), retina.getStep(), output_filename);
}
else if (strcmp(token[2], "sequence") == 0 ) {
string output_filename;
if (token[4] && strcmp(token[4], "{") != 0){ // the next token is not {, assume that it is the output filename
output_filename=token[4]; // Replace (default) filename
next_tok_idx=5; // Pass to the next token to continue reading parameters
} else {
output_filename=""; // Use the default filename
next_tok_idx=4; // continue reading parameters from this current token
}
newModule = new SequenceOutput(retina.getSizeX(), retina.getSizeY(), retina.getStep(), output_filename);
} else {
abort(line,"Unknown retina output type");
break;
}
// Process parameter block if it is found
parseParameterBlock(token+next_tok_idx, newModule, line);
// Add module to the retina
if(continueReading) {
retina.addModule(newModule,token[3]);
if(verbose) cout << "Output module " << token[3] << "added to the retina" << endl;
} else
break;
} else {
abort(line,"The ID of Output module must start with the characters 'Output'");
break;
}
}else{
abort(line,"Expected a retina output type and output module ID");
break;
}
action = 0;
break;
default:
break;
}
}
}//end while
// close file
fin.close();
}
//-------------------------------------------------//
void FileReader::abort(int line, const char *error_msg){
cout << "Incorrect syntax in line " << line << ": " << error_msg << endl;
cout << "Aborting parsing of retina file." << endl;
continueReading = false;
}