CALL US
819-345-3497

How to parse C/C++ declarations

This was somewhere lying around in one my old HDD backups, and I always wanted to put it somewhere convenient for me to be able to reference it on demand.

It’s a post from comp.lang.c++ from when I was doing a lot of C++ development (most of which I’ve forgotten now that I use C# and .NET for EPLAN API development), but I think it’s just too good to let go to waste.

For those who might be interested in such things, enjoy:

Re: int (*t(int))(int *); // what does this mean?

Author: jim.hyslop
Email: jim.hyslop@leitch.com
Date: 1998/09/17
Forums: comp.lang.c++.moderated, comp.lang.c++
————————————————————————

In article <6tok7l$3ook$1@newssvr04-int.news.prodigy.com>,
“JER” wrote:
> Please give me the meaning of the declaration:
> int ( * t (int) )( int * );

The rules for parsing are:
Start at the identifier. Process to the right until you hit the end of the declaration or a closing parenthesis. Process to the left until you
hit an opening parenthesis or the beginning of the declaration. Repeat until the declaration is fully parsed.

So, the declaration is read as:
int ( * t (int) )( int * ) ;
10 6 5 1 2 3 4 7 8 9 11

1 – t
2 – is a function
3 – which accepts an int parameter
4 – [closing parenthesis – parse backwards now]
5 – and returns a pointer
6 – [opening parenthesis – parse forwards now]
7 – to a function
8 – which accepts an int *
9 – [closing parenthesis – parse backwards now]
10- and returns an int [beginning of dec – parse forwards now]
11- end of declaration – you’re done.

So: “t is a function which accepts an int parameter and returns a
pointer to a
function which accepts an int * and returns an integer”. The following
code
will work with your declaration:

#include 
using std::cout;
using std::endl;

int x(int *val)
{
  cout << "In x, passed value of " << *val << endl;
  return *val;
}

int y(int *val)
{
  cout << "In y, passed value of " << *val << endl;
  return *val;
}

int z(int *val)
{
  cout << "In z, passed value of " << *val << endl;
  return *val;
}

int ( * t (int v) )( int *) // Your original declaration
{
   // Exercise to the reader - how do you parse arr:
   // Hint: "=" is the end-of-declaration
   static int (*arr[])(int *) = {x, y, z};

   if (v < 0 || v >= sizeof(arr) / sizeof(arr[0])) {
      return NULL;
   }
   return arr[v];
}

int main(void)
{
  // and how do you parse:
  int(*p) (int *);

  int count=0;
  p=t(count);
  while(p) {
     cout << "p(&count) returned " << p(&count) << endl;
     p=t(++count);
  }
}

Creating pull lists reports

The problem

When dealing with large automation systems, it is often required to provide the installation electricians with pull lists, also known as conduit schedules.

Thanks to EPLAN P8’s reporting facility, and its filtering capabilities, the task of creating those documents can be automated, with all the benefits that this brings: reduction in the time to generate and reduction in the number of errors. Basically, we’re automating a task that would have to be done manually when using a regular drafting software.

In the case of plant documentation, the number of wires and cables that have to be pulled between the different control enclosures can literally explode and become unmanageable. By providing installation electricians with accurate pull lists, we create a downward pressure on the overall cost of installation. Not only because of saved time, but also because the tendency to add a lot of spare wires to cover up for possible mistakes can force the electricians to beef up the conduit sizes, thus increasing the cost of material. Too many spare wires in a conduit is literally money “sleeping” there, as the cost of copper is non-negligeable for longer runs.

The solution

EPLAN P8 allows us to create what are know a “report templates”. They define all the properties required to generate a specific report, such as the report type, the form to be used, and also a filtering scheme to narrow down the list of results.

In order for this to work with minimal manual entry of properties, the project must at the very least define the Mounting location as structuring element. How to enable this is outside the scope for this article and will be covered in a future one. The idea is that each cabinet/junction box is assigned an identifier shortcode, and this is what we’ll be using as the basis for our filtering of the pull lists.

In this post, I will not concentrate on all the report template settings, but rather only on the filtering aspect. If you need help with setting up your custom report templates, we at STLM can provide you with the necessary consulting.

Creating the report template

Report templates are created from the Utilities > Reports > Generate menu. In the dialog that opens up, make sure to select the Templates tab. Then click on the New button, and select Connection list from the offered report types:

You can set the typical properties on your report template, such as the form to be used, the destination page where the report should be generated and so on.

The one setting that imports us for now is the Filter setting. Clicking in the value cell, you get the small button with the three dots, which means there is a sub-dialog accessible.

The Filter dialog allows you to create a named filter, and assign criterias to only get the objects that you want, in this case connections between a Panel +P1, and a Panel +P2:

My example today is to create a pull list between panels +P1 and +P2, so here’s how the filter MUST be like (click on image for larger view):

How it works

The above filter definition is quite interesting to analyse.

The first line says “Give me all connections whose Source OR Target are NOT within P1 or P2”, and then negates that criteria. What this basically does is bring you all the connections between +P1 and +P2, but at the same time any internal connections to +P1 and +P2, which we don’t want as part of the final result.

This is why we have to add the (…) condition, which is basically a “grouping” of conditions.

Within this grouping, we say that we want connections whose source AND target are within P1, OR connections whose source and target are within P2. But then, we negate the whole group, so in effect, we remove any connection whose source and target are completely within P1, or completely within P2.

This is for sure some wicked boolean logic hocus pocus, but it works, and this is what matters. Taking time to analyze how these boolean conditions work together is a nice exercise left to the reader.

Final words

The above example shows how to create a single pull list between two cabinets. If multiple pull lists are needed, it is possible to create multiple report templates, each with its own filter, in order to generate them individually.

For sure this may require some manual work, especially in the case of large projects. My goal is to come up with a script that will automate the creation of those report templates, complete with the filter settings. The user would simply call the script, select the Source and Target mounting locations from dropdown lists, and the corresponding report template and filter would automatically be created and imported in EPLAN.

I don’t have a clear time frame for the development of that script, so stay tuned,

Fun with wire numbering

Automated wire numbering in EPLAN Electric P8 is certainly a great time saver. I’ve worked with 500+ page projects, and I wouldn’t want to go back to use AutoCAD.

While EPLAN is certainly flexible when it comes to wire numbering, sometimes a specific customer requirement leaves me pensive, and sometimes it becomes a challenge I have to accept.

In this example, the customer wanted all connections to motors to be numbered like this:

where the format is <Page number><Non-digit part of motor connection point designation><Counter per motor per page>

The picture above shows a proof of concept with two motors on page 2, and their corresponding desired wire numbers. The more motor on a page, the higher the last digit(s) of the connection designation. I’ve tested my solution with 12 motors on a page with the correct result.

Connection numbering scheme

The idea is to create a connection numbering scheme that defines a format group based on specific devices, in our case the motors, or devices with “MTR” as their DT identifier (note that in some cases the DT identifier for motors might be only “M”, so this would have to be tweaked):

I placed that group at the top of the list so that those connections in that group are considered first when numbering. Once a connection is handled by a format group, it is not handled by groups further down the list, so you have to go from specific to general (top to bottom in the list of format groups).

This is how the group is defined:

The selected format elements are:

  • The Page name of the target component.
  • A block property defined on the connection currently being numbered (described in details below).
  • Then finally a subcounter defined over the signal/state of the connection (in our example, the same number on each side of terminals).

Here are screenshots of their specific settings:

Block property format for connections

Block property formats can be defined at the individual connections, but it’s better to define them globally in the project.

Under Project > Properties…, you can select the Formats from the Category drop-down in the Properties tab. This will limit the number of properties displayed in the grid.

Add those two properties to the grid:

Block property: Replacement text [1]:

○│??_??@^.*MTR[0-9]{1,2}:U[0-9]{0,1}$;│??_??@U;║○│??_??@^.*MTR[0-9]{1,2}:V[0-9]{0,1}$;│??_??@V;║○│??_??@^.*MTR[0-9]{1,2}:W[0-9]{0,1}$;│??_??@W;

Block property: Format (connection) [10]:

[20025,1,1&lt;20048,1,0,0,0,0,0,0,0,en_US,0,0,0,0,0,1&gt;]

The replacement text table is defined like this:

It’s important to note the Operator is set to Regular expression on all 3 rows. Then the Source text is the actual Regular expression to evaluate, and the Output text is what we want to replace the match from the RexEx with.

The RegEx is used to detect which pin of the motor we are connected to, and then use “U”, “V” or “W” accordingly.

The block property format is defined as follows:

Last function via connection point and target number (PLC), Connection point 1, Target 1: Name of target connection point (Full),

and then the Replacement text is set on the block property format:

Explanation

By defining a block property format for connections at the project level, we implicitly assign it to all connections of the project.

The block property format “pulls” the Name of target connection point (full), meaning that it will return something such as:

MTR21:U

And then using the replacement table and its regular expression, we convert that to simply “U”.

In the connection numbering scheme we have defined the Page, the Block Property, and a subcounter.

All together, those pieces of data form the connection designation as wanted by the customer.

Conclusion

I try to stay as active as I can on the official EPLAN forum in english at:

http://forum.eplan.info/en/

Registration is required, but free. If you have questions about this, or any related topics (or unrelated), don’t hesitate to ask there.

Cheers

 

Problem when using UNC notation for master data directories

On a recent project I had to work with a remote team of designer.

The company provided me with the VPN client configuration and read/write access to a shared folder on one of their servers.

Everything went fine until I started assigning the master data directories within Eplan P8. I kept getting error messages saying that I didn’t have access to those folders. We checked with the IT team, and they assured me the rights were properly set.

It turns out that for some reason, if you use UNC notation, ie \\server\path\to\folder, then Eplan seems to want to have access rights to each folder within the path, which was not the case here. I only had access rights to the deepest directory.

The problem can be easily solved by using a mapped letter drive in Windows that is mapped to the deepest directory, and then use that drive letter in Eplan.

Enjoy.

Stopping PLC Tracking at terminal

Eplan has a functionality called “PLC Tracking” that allows to track a signal to/from a PLC input or output.

This is used, for example, when numbering devices based on PLC data. One might use the PLC address as the Device Tag for a relay.

This functionality can be used for other purposes once we understand how it works.

On LinkedIn, one of the EPlan group members asked how to get data from the last terminal connected to another terminal without taking in-between terminals into account. A simplified version of this would be:

Image 1

Image 1

Here we have a black box on the left, three terminals in between, and a final black box on the right. For the sake of this example, we assume that U1111 & X4 are within the same enclosure, that X5 is located in a field mounted junction box, and that X6 & U2222 are in a remote enclosure.

Using the PLC tracking, we can display properties from the last connected target under X4 and X6. For this we would use a Block Property Format on both X4:1 and X6:1 like so:

X4:1, Block Property Format 1: [20025,1,1<20201<20048,1,0,0,0,0,0,0,0,en_US,0,0,0,0,0,0>>]

X6: 1, Block Property Format 1: [20025,2,1<20201<20048,1,0,0,0,0,0,0,0,en_US,0,0,0,0,0,0>>]

These block properties can be described as “Start from Terminal, then take the Last function via connection point and target number (PLC), Connection point 1, Target 1, and finally take the Device tag

Image 2

Image 2

Since the default display properties on terminals will display Block Property 1, then we should automatically see the result as shown in Image 1.

All good, but our LinkedIn user would like to get properties from the last terminal, not the last device. This is where we can “cheat” Eplan into doing what we need.

When looking at X4:1 properties, under “Symbol / function data”, we have the “Logic…” button:

Image 3

Image 3

This button brings up the following dialog:

Image 4

Image 4

We see here the “Target tracking (PLC) to” property for each connection point of the terminal. We are interested in stopping the tracking between pins 1 & 2 (pins 3&4 are used for jumpers so they are not of interest for now). To do so, simply delete the values in columns 1 & 2 as so:

Image 5

Image 5

We also do the same for terminal X6:1, and we refresh the connections by clicking this toolbar button in Eplan’s main toolbar:

We should now see this:

Image 6

Notice that the tracking is now stopped at the outer most terminals and that the desired information is displayed. We could now display that Block Property on a terminal diagram report.

Enjoy

Defeating the “Design Mode” annoyance

In Eplan P8 we have what is called the “Design Mode”. It is useful to copy or move objects relative to a specific point of origin. In order to understand why this mode can be useful, let’s examine what “Normal Mode” is.

When Design Mode is not enabled, any copy or move command will be made relative to the insertion point of the selected component. In some cases this might not be what we want. For example, a Black Box will be copied relative to its insertion point, which is normally in the upper left corner. But what if we want to copy a black box and align it with the center of another Black Box like this:

DesignMode

In this case the Design Mode, along with the Object Snap option will come in handy.

The annoying part about Design Mode is that if you forget to turn it off, and then try to do a Normal Mode copy and paste operation, you will paste the last component selected in Design Mode instead of the one you just selected, and that’s simply because Eplan is still waiting for you the define the “handle” of the copy operation when you are in fact trying to paste. In other words, it didn’t get a chance to complete the copy operation, so it still has the before last object in the clipboard. You will notice this text in the STatus Bar at the bottom of the Graphical Editor:

DefineHandle

In any case, even seasoned Eplan user get bitten by this once in a while, so I decided to write this little script that defines two actions. One is the Normal Mode copy, and the other is the Design Mode copy. Both will work in the desired mode regardless of the current Design Mode state.

Here’s the script:

/*
Copyright (c) 2013 STLM Inc.
 
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
 
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
 
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
 
public class STLMCopy
{
    //Add the two actions as menu points under Utilities
    [DeclareMenu()]
    public void CopyNormalMenu()
    {
	Eplan.EplApi.Gui.Menu oMenu = new Eplan.EplApi.Gui.Menu();
        oMenu.AddMenuItem("Copy (Normal Mode)", "NormalCopyAction");
        oMenu.AddMenuItem("Copy (Design Mode)", "DesignCopyAction");
    }
 
    //Declare the action to force copy in normal mode
    [DeclareAction("NormalCopyAction")]
    public void NormalCopyAction()
    {
	bool toggled = false;
 
        if (DesignModeState)
        {
            ToggleDesignMode();
            toggled = true;
        }
 
        Copy();
 
        if (toggled)
            ToggleDesignMode();
    }
 
    //Declare the action to force copy in design mode
    [DeclareAction("DesignCopyAction")]
    public void DesignCopyAction()
    {
        bool toggled = false;
 
        if (!DesignModeState)
        {
            ToggleDesignMode();
            toggled = true;
        }
 
        Copy();
 
        if (toggled)
            ToggleDesignMode();
    }
 
    //Helper functions and properties
 
    private bool DesignModeState
    {
	get
	{
		return new Eplan.EplApi.Base.Settings().GetBoolSetting("USER.GedViewer.ConstructionMode", 0);
	}
    }
 
    private void ToggleDesignMode()
    {
        Eplan.EplApi.ApplicationFramework.ActionManager mgr = new Eplan.EplApi.ApplicationFramework.ActionManager();
 
        Eplan.EplApi.ApplicationFramework.Action act = mgr.FindAction("XGedActionToggleConstructionMode");
        if (act != null)
        {
            Eplan.EplApi.ApplicationFramework.ActionCallingContext ictx = new Eplan.EplApi.ApplicationFramework.ActionCallingContext();
            act.Execute(ictx);
        }
    }
 
    private void Copy()
    {
        Eplan.EplApi.ApplicationFramework.ActionManager mgr = new Eplan.EplApi.ApplicationFramework.ActionManager();
 
        Eplan.EplApi.ApplicationFramework.Action act = mgr.FindAction("XGedStartInteractionAction");
        if(act != null)
        {
	        Eplan.EplApi.ApplicationFramework.ActionCallingContext CopyCtx = new Eplan.EplApi.ApplicationFramework.ActionCallingContext();
	        CopyCtx.AddParameter("Name", "XMIaClipboardCopy");
	        act.Execute(CopyCtx);
    	}
    }
 
}

Once loaded this script will create two new entries under the Utilities menu. Optionally you could assign shortcut keys to the new Actions, or even assign them to custom toolbar buttons.

To use it, make sure you select the objects you want to copy first (this is because of a weird issue in Eplan), and select the desired Action, either Normal Mode Copy or Design Mode Copy.

The script will always revert the Design Mode to the state it was prior to calling the script.

Enjoy !

Refreshing the GED after changing project setting

In some cases, changing a project setting from API will seem to have no effect at all. For example, if you change the default plot frame setting for a project, you will not see the change reflected in the graphical editor (GED).

There is a very simple fix for that. All you have to do is raise the PageManagement.ProjectSettings.Changed event from your API.

Here’s a snippet show how to do this:

//Refresh the GED
EventParameterString oEventParamString = new EventParameterString();
oEventParamString.String = "";
int result = new EventManager()
      .Send("PageManagement.ProjectSettings.Changed", oEventParamString);

Please note: this is an undocumented event, and as such could change in the future.

Enjoy

From AutoCAD to Eplan P8

I was recently involved in a fair sized project conversion (200+ pages) from AutoCAD to EPlan P8. I was helping this customer on their very first Eplan project which would eventually become their “template” for future machines.

What struck me, once again, is that most people coming from AutoCAD tend to concentrate on the graphical aspects of their documents, while giving less consideration to the logical aspects of it. Having worked with AutoCAD for many years myself, I definitely understand why it is so. AutoCAD is a very good drafting software, but when it comes to expressing electrical schematics, it falls flat for anything but the most trivial project. The lack of specialized tools in AutoCAD makes it so that drafters will leave out details that would guide the panel builders in their job, only to shift that responsibility on those same panel builders. One good example of this is leaving out the terminals from the schematics because “our guys on the shop floor know where to put them as needed”.

Not only does this shift responsibility to the wrong place, but it raises the labor cost when errors are discovered and panel builders/shop workers lack the knowledge to correct them. We then assist to a merry-go-round between shop floor, drafters and engineers, and a simple one hour thing ends up eating up a man-day of labor.

This is definitely a mistake when working with EPlan, which is more of a design tool than a drafting tool. In EPlan, as you create your electrical schematics, you’re not only laying out graphical elements on the page, you’re actually building a “model” of you machine’s controls. The analogy I always give at my trainings is that of using AutoCAD vs. 3D modeling software for mechanical design. In the old days of 2D drafting, modifications to one drawing often involved many manual updates on several other drawings to reflect all the views of the object. Countless errors came from forgotten updates, and many manufactured parts had to be scrapped because of this.

With the advent of 3D modeling software such as Inventor or SolidWorks, you concentrate on modeling the actual part, and you generate views as needed. Any needed changes are done on the model itself, and views are regenerated, making sure that nothing is forgotten. This brings consistency and quality to the design. Shop workers are free to do their jobs instead of wasting time trying to understand discrepancies between drawings.

When applied to the electrical engineering field, modeling your controls is a definite advantage over “dumb” graphical entities. Once the model is completed, you can project “views” in the form of reports that give you all the needed documents for you production team. For example, you can extract a bill of material, a list of wires, terminal diagrams and so on. You know that these generated documents will be consistent and error free as long as you maintain your model error free.

One typical source of errors in electrical schematics is the manual handling of cross-references. For example, a relay coil will typically be represented on one page, and its contacts on different pages. Trying to maintain this information manually is tedious and error prone. The same goes for interruption points that transmit your power rails between pages. This automated cross-referencing in EPlan alone is well worth the cost of the software !

Another benefit of modeling your controls is that it forces the designer to actually think about what he’s doing as opposed to a drafter who’s content with executing the red-lining given to him by the engineers. This is most apparent in the routing of your circuits within your electrical enclosures.

Let’s give an example of this. Here’s a typical AutoCAD way of representing schematics:

This is an IEC style schematic where we see some relays, a door mounted pilot light, and a field mounted pilot light. The problem with this representation is that it gives absolutely no clue to the panel builder about the routing of the wires. If we were to follow the circuit naively, we would go from relay K2 to relay K3, to the door, then to the field, and finally back to the enclosure to relay K4. This would of course be a very inefficient way of wiring this circuit because we’d have to bring two wires to the pilot light in the door, and two wires to the one in the field.

This is where the knowledge of how to build the machine is shifted from the engineering department to the production floor. We rely on the experience of a few individuals within the company who have informal knowledge of how to wire your machines. If they should ever retire or leave the company, or even if you were to outsource your production, you’d be hard pressed to come up with this knowledge.

On the other hand, here’s the same schematics reworked in EPlan:

First we notice that components have been reordered to better express the real routing of the wires. Obviously, we want to daisy chain the neutral on those relays before going out to the door and field. Also, we show the actual terminals to connect external components. Finally, we notice the use of T-Nodes instead of points to better express the routing.

From such a model of the circuit, we could easily generate a list of wires with their respective source and destination, and the panel builder team would simply have to blindly follow it.

So in the end, when converting AutoCAD schematics to EPlan, it’s not only a matter of making sure that the graphical aspect of the wiring is done, but there is also a lot of thought that must be given to the logical aspects. This will of course involve spending more time in the design phase, but what I’ve seen is that this time consistently pays for itself down the line.

If you need someone to convert your AutoCAD schematics to EPlan, don’t hesitate to contact us for expert consulting on how to best achieve this.

API to set arrow at graphical line’s end

In Eplan P8, in order to add an arrowhead at the end of a graphical line, you have to first bring up the property dialog, set a checkbox, then click the OK button. I find this annoying and time consuming.

I have tried to find a way to set the “Arrow at line end” property from a toolbar button, but so far I haven’t found how.

As always when I can’t find an out-of-the-box solution, I resort to API Add-In programming.

This one is quite simple and the code should be self-explanatory. the code can be found on my public GitHub reporsitory.

Some issue with accessory parts in EPlan P8

Today I was on site at my customer’s place, and I was having problems when trying to place a certain part on a 2D panel layout page. No matter what settings I was using before placing the part, Eplan would always ask me for the parts dimensions. I double checked all the parts data in Parts Management, and everything was there: dimensions and also the graphical macro to use for 2D layouts. Funny as hell.

After some investigating, I found that the source of the problem was that the part in question had been assigned as an accessory part (an auxiliary contact block) to my main part (a contactor). In itself this should not be causing a problem, but then I noticed that in the parts management dialog, when looking at the accessory list for the contactor part, the “Variant” field was empty beside the auxiliary part number.

After filling in the missing field, things started to work as expected again. Maybe someone deleted the variant field, or maybe the data was messed up some other way we don’t know.

Have a look at this video for a demo of the issue.

NEWS

How to parse C/C++ declarations


This was somewhere lying around in one my old HDD backups, and I always wanted [...]

FOLLOW US

CERTIFED EXPERT