Archive for November 21st, 2011

EMC2 HAL Configuration by Eagle Schematics: The Code

As part of that renaming adventure with the Logitech Gamepad configuration, I realized I hadn’t put my version of Martin Shoeneck’s Eagle-to-HAL conversion script anywhere useful.

Herewith, the script that you’ll apply to schematics built with parts from the hal-config-2.4.lbr.odt library (which you must rename to get ride of the ODT extension):

/******************************************************************************
 * HAL-Configurator
 *
 * Author: Martin Schoeneck 2008
 * Additional gates and tweaks: Ed Nisley KE4ZNU 2010
 *****************************************************************************/
#usage "<h1>HAL-Configurator</h1>Start from a Schematic where symbols from hal-config.lbr are used!";

string output_path =    "./";
string dev_loadrt =     "LOADRT";
string dev_loadusr =    "LOADUSR";
string dev_thread =     "THREAD";
string dev_parameter =  "PARAMETER";

string dev_names[] = {
"CONSTANT",								// must be first entry to make set_constants() work
"ABS",				// 2.4
"AND2",
"BLEND",			// 2.4
"CHARGE-PUMP",		// 2.4
"COMP",
"CONV_S32_FLOAT",	// 2.4
"DDT",				// 2.4
"DEADZONE",			// 2.4
"DEBOUNCE",			// 2.4
"EDGE",
"ENCODER",			// 2.4
"ENCODER-RATIO",	// 2.4
"ESTOP-LATCH",
"FLIPFLOP",
"FREQGEN",			// 2.4
"LOWPASS",
"MULT2",			// 2.4
"MUX2",
"MUX4",				// 2.4
"MUX8",				// 2.4
"NEAR",				// 2.4
"NOT",
"ONESHOT",
"OR2",
"SAMPLER",			// 2.4
"SCALE",			// 2.4
"SELECT8",			// 2.4
"SUM2",
"TIMEDELAY",		// 2.4
"TOGGLE",			// 2.4
"WCOMP",			// 2.4
"XOR2",				// 2.4
""					// end flag
};

/*******************************************************************************
 * Global Stuff
 ******************************************************************************/

string FileName;
string ProjectPath;
string ProjectName;

void Info(string Message) {
	dlgMessageBox(";<b>Info</b><p>\n" + Message);
}

void Warn(string Message) {
	dlgMessageBox("!<b>Warning</b><p>\n" + Message + "<p>see usage");
}

void Error(string Message) {
	dlgMessageBox(":<hr><b>Error</b><p>\n" + Message + "<p>see usage");
	exit(1);
}

string replace(string str, char a, char b) {
	// in string str replace a with b
	int pos = -1;
	do {
		// find that character
		pos = strchr(str, a);
		// replace if found
		if(pos >= 0) {
			str[pos] = b;
		}
	} while(pos >= 0);

	return str;
}

// the part name contains an index and is written in capital letters
string get_module_name(UL_PART P) {
	// check module name, syntax: INDEX:NAME
	string mod_name = strlwr(P.name);
	// split string at the : if exists
	string a[];
	int c = strsplit(a, mod_name, ':');
	mod_name = a[c-1];
	// if name starts with '[' we need uppercase letters
	if(mod_name[0] == '[') {
		mod_name = strupr(mod_name);
	}

	return mod_name;
}

string comment(string mess) {
	string str = "\n\n####################################################\n";
	if(mess != "") {
		str += "# " + mess + "\n";
	}

	return str;
}

// if this is a device for loading a module, load it (usr/rt)
string load_module(UL_PART P) {
	string str = "";

	// it's a module if the device's name starts with LOADRT/LOADUSR
	if((strstr(P.device.name, dev_loadrt) == 0) ||
	   (strstr(P.device.name, dev_loadusr) == 0)) {

		// now add the string to our script
		str += P.value + "\n";
	}

	return str;
}

// count used digital gates (and, or, etc) and load module if neccessary
string load_blocks() {
	string str = "";

	int index;

	int dev_counters[];
	string dname[];

	// count the gates that are used
	schematic(S) { S.parts(P) {
		strsplit(dname,P.device.name,'.');		// extract first part of name
		if ("" != lookup(dev_names,dname[0],0)) {
			for (index = 0;  (dname[0] != dev_names[index]) ; index++) {
				continue;
			}
			dev_counters[index]++;
		}
	} }

// force lowercase module names...

	for (index = 0; ("" != dev_names[index]) ; index++) {
		if (dev_counters[index]) {
			sprintf(str,"%sloadrt %s\t\tcount=%d\n",str,strlwr(dev_names[index]),dev_counters[index]);
		}
	}

	return str;
}

string hook_function(UL_NET N) {
	string str = "";

	// is this net connected to a thread (work as functions here)?
	int    noclkpins       = 0;
	string thread_name     = "";  // this net should be connected to a thread
	string thread_position = "";
	N.pinrefs(PR) {
		// this net is connected to a clk-pin
		if(PR.pin.function == PIN_FUNCTION_FLAG_CLK) {
			// check the part: is it a thread-device?
			if(strstr(PR.part.device.name, dev_thread) == 0) {
				// we need the name of the thread
				thread_name = strlwr(PR.part.name);
				// and we need the position (position _ is ignored)
				thread_position = strlwr(PR.pin.name);
				thread_position = replace(thread_position, '_', ' ');
			}
		} else {
			// no clk-pin, this is no function-net
			noclkpins++;
			break;
		}
	}

	// found a thread?
	if(noclkpins == 0 && thread_name != "") {
		// all the other pins are interesting now
		N.pinrefs(PR) {
			// this pin does not belong to the thread
			if(strstr(PR.part.device.name, dev_thread) != 0) {
				// name of the pin is name of the function
				//string function_name = strlwr(PR.pin.name);
				string function_name = strlwr(PR.instance.gate.name);
				// if functionname starts with a '.', it will be appended to the modulename
				if(function_name[0] == '.') {
					// if the name is only a point, it will be ignored
					if(strlen(function_name) == 1) {
						function_name = "";
					}
					function_name = get_module_name(PR.part) + function_name;
				}
				str += "addf " + function_name + "\t\t" + thread_name + "\t" + thread_position + "\n";
			}
		}
	}

	return str;
}

string set_parameter(UL_NET N) {
	string str = "";

	// is this net connected to a parameter-device?
	int    nodotpins       = 0;
	string parameter_value = "";
	N.pinrefs(PR) {
		// this net is connected to a dot-pin
		if(PR.pin.function == PIN_FUNCTION_FLAG_DOT) {
			// check the part: is it a parameter-device?
//			str += "** dev name [" + PR.part.device.name + "] [" + dev_parameter + "]\n";
			if(strstr(PR.part.device.name, dev_parameter) == 0) {
				// we need the value of that parameter
				parameter_value = PR.part.value;
//				str += "**  value [" + PR.part.value +"]\n";
			}
		} else {
			// no clk-pin, this is no function-net
			nodotpins++;
			break;
		}
	}

	// found a parameter?
	if(nodotpins == 0 && parameter_value != "") {
		// all the other pins are interesting now
		N.pinrefs(PR) {
//			str += "** dev name [" + PR.part.device.name + "] [" + dev_parameter + "]\n";
			// this pin does not belong to the parameter-device
			if(strstr(PR.part.device.name, dev_parameter) != 0) {
				// name of the pin is name of the function
				//string parameter_name = strlwr(PR.pin.name);
				string parameter_name = strlwr(PR.instance.gate.name);
				// if functionname starts with a '.', it will be appended to the modulename
//				str += "** param (gate) name [" + parameter_name + "]\n";
				if(parameter_name[0] == '.') {
					// if the name is only a point, it will be ignored
					if(strlen(parameter_name) == 1) {
						parameter_name = "";
					}
					parameter_name = get_module_name(PR.part) + parameter_name;
//					str += "** param (part) name [" + parameter_name + "]\n";
				}
				str += "setp " + parameter_name + "\t" + parameter_value + "\n";
			}
		}
	}

	return str;
}

// if this is a 'constant'-device, set its value
// NOTE: this is hardcoded to use the first entry in the dev_names[] array!
string set_constants(UL_PART P) {
	string str = "";

	// 'constant'-device?
	if(strstr(P.device.name, dev_names[0]) == 0) {
		str += "setp " + get_module_name(P) + ".value\t" + P.value + "\n";
	}

	return str;
}

string connect_net(UL_NET N) {
	string str = "";

	// find all neccessary net-members
	string pins = "";
	N.pinrefs(P) {
		// only non-functional pins are connected
		if(P.pin.function == PIN_FUNCTION_FLAG_NONE) {
			string pin_name =  strlwr(P.pin.name);
			string part_name = strlwr(P.part.name);
			pin_name =  replace(pin_name,  '$', '_');
			part_name = replace(part_name, '$', '_');
			pins += part_name + "." + pin_name + " ";
		}
	}

	if(pins != "") {
		string net_name = strlwr(N.name);
		net_name = replace(net_name, '$', '_');
		str += "net " + net_name + " " + pins + "\n";
	}

	return str;
}

/*******************************************************************************
 * Main program.
 ******************************************************************************/
// is the schematic editor running?
if (!schematic) {
	Error("No Schematic!<br>This program will only work in the schematic editor.");
}

schematic(S) {
	ProjectPath = filedir(S.name);
	ProjectName = filesetext(filename(S.name), "");
}

// build configuration

string cs = "# HAL config file automatically generated by Eagle-CAD ULP:\n";
cs += "# [" + argv[0] + "]\n";
cs += "# (C) Martin Schoeneck.de 2008\n";
cs += "# Mods Ed Nisley 2010\n";

FileName = ProjectPath + ProjectName + ".hal";

cs += "# Path        [" + ProjectPath + "]\n";
cs += "# ProjectName [" + ProjectName + "]\n";

//cs += "# File name: [" + FileName + "]\n\n";

// ask for a filename: where should we write the configuration?

FileName = dlgFileSave("Save Configuration", FileName, "*.hal");

if(!FileName) {
	exit(0);
}

cs += "# File name   [" + FileName + "]\n";
cs += "# Created     [" + t2string(time(),"hh:mm:ss dd-MMM-yyyy") + "]\n\n";

schematic(S) {
	// load modules
	cs += comment("Load realtime and userspace modules");
	S.parts(P) {
		cs += load_module(P);
	}

	// load blocks
	cs += load_blocks();

	// add functions
	cs += comment("Hook functions into threads");
	S.nets(N) {
		cs += hook_function(N);
	}

	// set parameters
	cs += comment("Set parameters");
	S.nets(N) {
		cs += set_parameter(N);
	}

	// set constant values
	cs += comment("Set constants");
	S.parts(P) {
		cs += set_constants(P);
	}

	// build nets and connect them
	cs += comment("Connect Modules with nets");
	S.nets(N) {
		cs += connect_net(N);
	}
}

// open/overwrite the target file to save the configuration
output(FileName, "wt") {
	printf(cs);
}
About these ads

,

Leave a comment