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);
}