diff --git a/2do.md b/2do.md index ed7b9b6..a6f8512 100644 --- a/2do.md +++ b/2do.md @@ -1,10 +1,26 @@ # 2do -now: first is to make sure it runs again - checkout -raw interface sits fixed on serial1 + +[ ] multiple parameter passing to bonsai make it possible to pass com port to bonsai sketch -implement Pathlib widely - use this chance also to make use of the tmp folder functionality? +## decisions: +tmp folder or not? +pro: cleaner +contra: temporary arduino_vars file also needed + +distribute interface generator or not? +pro: makes codebase for tasks cleaner +contra: removes flexibility as interface needs to be freezed +solution: interface generator could have diff versions, could be specified in task config. Could actually be something in task config that defines if raw, where serial etc. + +huge pro is though that it will greatly remove clutter + +remember that there was a problem, the settable return type (two diff parsers) + +## known hardcodes +raw interface sits fixed on serial1 +history of serial monitor is limited @@ -20,7 +36,6 @@ write in header day of training, version of TaskControl, date of generation etc ## interface generator + template and generator is to be distributed with task control actually - make function with settable return type! ## general diff --git a/interface_generator.py b/interface_generator.py index 2fed3a4..d5ec9e1 100644 --- a/interface_generator.py +++ b/interface_generator.py @@ -1,4 +1,5 @@ # python me to generate an interface.cpp based on the variables in `init_variables.h` +# MAJOR FIXME this file contains unix specific stuff ... import pandas as pd import scipy as sp @@ -109,31 +110,37 @@ def run(variables_path): """ bool_setter_template = """ - if (dtype == "bool") { - if (strcmp(varname,"VARNAME")==0){ - if (strcmp(varvalue,"false")==0) { - VARNAME = false; - } - else { - VARNAME = true; - } + if (strcmp(varname,"VARNAME")==0){ + if (strcmp(varvalue,"false")==0) { + VARNAME = false; + } + else { + VARNAME = true; } } """ int_setter_template = """ - if (dtype == "int") { - if (strcmp(varname,"VARNAME")==0){ - VARNAME = atoi(varvalue); - } + if (strcmp(varname,"VARNAME")==0){ + VARNAME = atoi(varvalue); + } + """ + + long_setter_template = """ + if (strcmp(varname,"VARNAME")==0){ + VARNAME = atol(varvalue); + } + """ + + unsigned_long_setter_template = """ + if (strcmp(varname,"VARNAME")==0){ + VARNAME = strtoul(varvalue,NULL,10); } """ float_setter_template = """ - if (dtype == "float") { - if (strcmp(varname,"VARNAME")==0){ - VARNAME = atof(varvalue); - } + if (strcmp(varname,"VARNAME")==0){ + VARNAME = atof(varvalue); } """ @@ -163,6 +170,20 @@ def run(variables_path): # no ints found pass + try: + for i, row in init_vars.groupby('dtype').get_group('long').iterrows(): + all_setters.append(long_setter_template.replace("VARNAME",row['name'])) + except KeyError: + # no longs found + pass + + try: + for i, row in init_vars.groupby('dtype').get_group('unsigned long').iterrows(): + all_setters.append(unsigned_long_setter_template.replace("VARNAME",row['name'])) + except KeyError: + # no unsigned longs found + pass + try: for i, row in init_vars.groupby('dtype').get_group('float').iterrows(): all_setters.append(float_setter_template.replace("VARNAME",row['name'])) diff --git a/interface_template.cpp b/interface_template.cpp index 0dbcd17..e56a8eb 100644 --- a/interface_template.cpp +++ b/interface_template.cpp @@ -13,6 +13,8 @@ boolean newData = false; bool verbose = true; bool run = false; +int current_state = 1; + void getSerialData() { // check if command data is available and if yes read it // all commands are flanked by <> @@ -103,26 +105,9 @@ void processSerialData() { char varvalue[len-split+1]; strlcpy(varvalue, line+split+1, len-split+1); - // parse dtype - String dtype = "unset"; - - // test for bool - if ((dtype == "true") || (dtype == "false")) { - dtype = "bool"; - } - - // test for float (has decimal point) - unsigned int num_len = sizeof(varvalue)/sizeof(char); - for (unsigned int i = 0; i < num_len; i++) { - if (varvalue[i] == '.') { - // isFloat = true; - dtype = "float"; - } - } - - // else must be int - if (dtype == "unset"){ - dtype = "int"; + // for the state machine "force state" buttons + if (strcmp(varname,"current_state")==0){ + current_state = atoi(varvalue); } // INSERT_SETTERS @@ -148,11 +133,6 @@ void processSerialData() { } } - // RAW - if (strcmp(mode,"RAW")==0){ - // manually implement functions here - } - newData = false; } } diff --git a/old/interface_generator.py b/old/interface_generator.py new file mode 100644 index 0000000..2fed3a4 --- /dev/null +++ b/old/interface_generator.py @@ -0,0 +1,205 @@ +# python me to generate an interface.cpp based on the variables in `init_variables.h` + +import pandas as pd +import scipy as sp +import sys,os + +dtype_map = { + 'int':'i4', + 'unsigned int':'u4', + 'long':'i8', + 'unsigned long':'u8', + 'bool':'?', + 'float':'f4', + 'double':'f8', + } + +# def parse_arduino_vars(path): +# """ a hacky parser """ # FIXME this needs a new name as well +# with open(path, 'r') as fH: +# lines = fH.readlines() +# lines = [line.strip() for line in lines] + +# # hacky parser: +# dfs = [] +# for line in lines: +# line = line.strip() +# # to skip +# if line == '': +# continue +# if '*' in line: # in block comment +# continue +# if line[:2] == '//': # full line comment +# continue +# if '//' in line: # remove everything after comment +# line = line.split('//')[0] +# print(line) + +# line = line.strip() +# try: +# elements, value = line.split('=') +# value = value[:-1].strip() +# elements = elements.strip().split(' ') +# elements = [elem.strip() for elem in elements] +# name = elements[-1] +# if elements[0] == 'const': +# const = True +# dtype = ' '.join(elements[1:-1]) +# else: +# const = False +# dtype = ' '.join(elements[:-1]) +# value = sp.array(value, dtype=dtype_map[dtype]) +# dfs.append(pd.DataFrame([[name, value, dtype, const]],columns=['name', 'value', 'dtype', 'const'])) +# except: +# print('unreadable line: ',line) +# pass +# arduino_vars = pd.concat(dfs, axis=0) +# arduino_vars = arduino_vars.reset_index(drop=True) + +# return arduino_vars + +def parse_arduino_vars(path): + """ a kind of hacky parser for init_variables.h """ + with open(path, 'r') as fH: + lines = fH.readlines() + lines = [line.strip() for line in lines] + + # hacky parser: + dfs = [] + for line in lines: + line = line.strip() + # to skip + if line == '': + continue + if '*' in line: # in block comment + continue + if line[:2] == '//': # full line comment + continue + if '//' in line: # remove everything after comment + line = line.split('//')[0] + print(line) + + line = line.strip() + try: + elements, value = line.split('=') + value = value[:-1].strip() + elements = elements.strip().split(' ') + elements = [elem.strip() for elem in elements] + name = elements[-1] + dtype = ' '.join(elements[:-1]) + value = sp.array(value, dtype=dtype_map[dtype]) + # FIXME hardcoded dtype instead of dtypemap[dtype] (as in utils), in essence, same func, different behavior. will confuse ppl + dfs.append(pd.DataFrame([[name, value, dtype]],columns=['name', 'value', 'dtype'])) + except: + print('unreadable line: ',line) + pass + arduino_vars = pd.concat(dfs, axis=0) + arduino_vars = arduino_vars.reset_index(drop=True) + + return arduino_vars + + +def run(variables_path): + init_vars = parse_arduino_vars(variables_path) + + getter_template = """ + if (strcmp(varname,"VARNAME")==0){ + Serial.println(String(varname)+String("=")+String(VARNAME)); + } + """ + + bool_setter_template = """ + if (dtype == "bool") { + if (strcmp(varname,"VARNAME")==0){ + if (strcmp(varvalue,"false")==0) { + VARNAME = false; + } + else { + VARNAME = true; + } + } + } + """ + + int_setter_template = """ + if (dtype == "int") { + if (strcmp(varname,"VARNAME")==0){ + VARNAME = atoi(varvalue); + } + } + """ + + float_setter_template = """ + if (dtype == "float") { + if (strcmp(varname,"VARNAME")==0){ + VARNAME = atof(varvalue); + } + } + """ + + + # make getters + all_getters = [] + all_varnames = [] + for i,row in init_vars.iterrows(): + all_varnames.append(row['name']) + + for i in range(len(all_varnames)): + all_getters.append(getter_template.replace("VARNAME",all_varnames[i])) + + # make setters + all_setters = [] + try: + for i, row in init_vars.groupby('dtype').get_group('bool').iterrows(): + all_setters.append(bool_setter_template.replace("VARNAME",row['name'])) + except KeyError: + # no bools found + pass + + try: + for i, row in init_vars.groupby('dtype').get_group('int').iterrows(): + all_setters.append(int_setter_template.replace("VARNAME",row['name'])) + except KeyError: + # no ints found + pass + + try: + for i, row in init_vars.groupby('dtype').get_group('float').iterrows(): + all_setters.append(float_setter_template.replace("VARNAME",row['name'])) + except KeyError: + # no floats ... + pass + + with open("interface_template.cpp",'r') as fH: + lines = fH.readlines() + + # replace in include line + for i, line in enumerate(lines): + if line == "#include \"interface_variables.h\"\n": + insertion_ind = i + lines[insertion_ind] = "#include \""+variables_path+"\"\n" + + # insert getters + for i,line in enumerate(lines): + if line == ' // INSERT_GETTERS\n': + getter_insertion_ind = i + lines.insert(getter_insertion_ind+1,''.join(all_getters)) + + # insert setters + for i,line in enumerate(lines): + if line == ' // INSERT_SETTERS\n': + setter_insertion_ind = i + lines.insert(setter_insertion_ind+1,''.join(all_setters)) + + # write all + with open('interface.cpp','w') as fH: + fH.writelines(''.join(lines)) + +if __name__== "__main__": + if len(sys.argv)==1: + # for using defaults from the cmd + run("interface_variables.h") + + if len(sys.argv) == 2: + variables_path = sys.argv[1] + run(variables_path) \ No newline at end of file diff --git a/old/interface_template.cpp b/old/interface_template.cpp new file mode 100644 index 0000000..0dbcd17 --- /dev/null +++ b/old/interface_template.cpp @@ -0,0 +1,158 @@ +// basic outline of the reader taken from +// http://forum.arduino.cc/index.php?topic=396450.0 + +#include +#include + +#include "interface_variables.h" + +// this line limits total command length to 200 chars - adjust if necessary (very long var names) +const byte numChars = 200; +char receivedChars[numChars]; +boolean newData = false; +bool verbose = true; +bool run = false; + +void getSerialData() { + // check if command data is available and if yes read it + // all commands are flanked by <> + + static boolean recvInProgress = false; + static byte ndx = 0; + char startMarker = '<'; + char endMarker = '>'; + char rc; + + // loop that reads the entire command + while (Serial.available() > 0 && newData == false) { + rc = Serial.read(); + + // read until end marker + if (recvInProgress == true) { + if (rc != endMarker) { + receivedChars[ndx] = rc; + ndx++; + if (ndx >= numChars) { + ndx = numChars - 1; + } + } + else { + receivedChars[ndx] = '\0'; // terminate the string + recvInProgress = false; + ndx = 0; + newData = true; + } + } + + // enter reading if startmarker received + else if (rc == startMarker) { + recvInProgress = true; + } + } +} + +void processSerialData() { + if (newData == true) { + // echo back command if verbose + if (verbose==true) { + Serial.print("Arduino received: "); + Serial.println(receivedChars); + } + + // get total length of message + unsigned int len = 0; + for (unsigned int i = 0; i < numChars; i++){ + if (receivedChars[i] == '\0'){ + len = i; + break; + } + } + + // GET SET CMD + char mode[4]; + strlcpy(mode, receivedChars, 4); + + // GET + if (strcmp(mode,"GET")==0){ + char varname[len-4+1]; + strlcpy(varname, receivedChars+4, len-4+1); + + // INSERT_GETTERS + + } + + // SET + if (strcmp(mode,"SET")==0){ + char line[len-4+1]; + strlcpy(line, receivedChars+4, len-4+1); + + // get index of space + len = sizeof(line)/sizeof(char); + unsigned int split = 0; + for (unsigned int i = 0; i < numChars; i++){ + if (line[i] == ' '){ + split = i; + break; + } + } + + // split by space + char varname[split+1]; + strlcpy(varname, line, split+1); + + char varvalue[len-split+1]; + strlcpy(varvalue, line+split+1, len-split+1); + + // parse dtype + String dtype = "unset"; + + // test for bool + if ((dtype == "true") || (dtype == "false")) { + dtype = "bool"; + } + + // test for float (has decimal point) + unsigned int num_len = sizeof(varvalue)/sizeof(char); + for (unsigned int i = 0; i < num_len; i++) { + if (varvalue[i] == '.') { + // isFloat = true; + dtype = "float"; + } + } + + // else must be int + if (dtype == "unset"){ + dtype = "int"; + } + + // INSERT_SETTERS + + } + + // CMD + if (strcmp(mode,"CMD")==0){ + char CMD[len-4+1]; + strlcpy(CMD, receivedChars+4, len-4+1); + + // manually implement functions here + + // Stop and Go functionality + if (strcmp(CMD,"RUN")==0){ + run = true; + Serial.println("Arduino is running"); + } + + if (strcmp(CMD,"HALT")==0){ + run = false; + Serial.println("Arduino is halted"); + } + } + + // RAW + if (strcmp(mode,"RAW")==0){ + // manually implement functions here + } + + newData = false; + } +}