Working with VC4 - coding styles / appraoch

Hello all,

since I’m about to start a new projectI’d like to use this opportunity to find a better way to work with VC4 as I’m rather unhappy with how I used to access VC4 before.

In my past projects, all visu elements were organized in one huge global structure, something like:

gVC4.pageMainMenu.layerMessage.but_abort <TYPE_CTRL_BUTTON>
gVC4.pageMainMenu.layerMessage.str_enterSerial <TYPE_CTRL_STRINPUT> 
.
.
.
gVC4.pageMaintenance.layerOperatingTimes.numRuntimeMotr <TYPE_CTRL_NUMERIC1> 

With TYPE_CTRL_BUTTON, TYPE_CTRL_BUTTON, … being other structues defined like:

TYPE_CTRL_NUMERIC1 : STRUCT
	status : UDINT; 
	completion : UDINT; 
	minVal : REAL; 
	maxVal : REAL; 
	value : REAL; 
	isLocked : BOOL;
	bitmapIndex : USINT;
	colorIndex : USINT;
END_STRUCT;

While putting all elements into one structure may have its own quirks,
what really bugs me is, how handling of VC4 elements clutters the statemaschines.
For example:

CASE someSM OF
	...
	STATE_INIT_PROCESS:
		//lock all buttons:
		gVC4.pageMainMenu.but_startProcess.isLocked 	:= 1;	// disable button
		gVC4.pageMainMenu.but_startProcess.bitmapIndex 	:= 3; 	// grey out button icon
		gVC4.pageMainMenu.but_startProcess.colorIndex 	:= 2;  	// grey out button text
		... (8 elements like this)
		
		// send axis to initial position
		axisctrl.cmd := MOVE_HOME;
		
		// next step
		someSM := STATE_INIT_PROCESS_WAIT
		
	STATE_INIT_PROCESS_WAIT:
		IF axisCtrl.stat = MOVE_DONE THEN
			//unlock all buttons:
			gVC4.pageMainMenu.but_startProcess.isLocked 	:= 0;
			gVC4.pageMainMenu.but_startProcess.bitmapIndex 	:= 1; // enable button
			gVC4.pageMainMenu.but_startProcess.colorIndex 	:= 1;  // black color
			... (8 elements like this)
		
		ELSIF axisCtrl.stat = MOVE_ERROR THEN
			// many lines of code opening a layer, setting its elements
			someSM := STATE_PROCESS_ERROR
		END_IF
		
	STATE_PROCESS_IDLE:
		// wait for user input
		IF gVC4.pageMainMenu.but_startProcess.completion = 1 THEN
			gVC4.pageMainMenu.but_startProcess.completion = 0:
			//(lots of more rows locking buttons, changing status texts indices, ...
			someSM := STATE_PROCESS_START_AUTO;
			
		ELSIF gVC4.pageMainMenu.but_startManualMode.completion = 1 THEN
			gVC4.pageMainMenu.but_startManualMode.completion = 0:
			//(lots of more rows locking buttons, changing status texts indices, ...
			someSM := STATE_PROCESS_START_MANUAL;
			
		ELSIF gVC4.pageMainMenu.but_startMaintenanceMode.completion = 1 THEN
			gVC4.pageMainMenu.but_startMaintenanceMode.completion = 0:
			//(lots of more rows locking buttons, changing status texts indices, ...
			someSM := STATE_PROCESS_START_MAINTENANCE;
		
		...
		END_IF

END_CASE

You get the idea. Using styleclasses may help spare some lines, but I was wondering if creating a dedicated VC4 controller, that can send/receive commands/stats/parameters, and takes care of all elements would help to de-clutter the SM.

For the states in statemachines in general I’d like to see what actually happens concerning the process and the transitions to other states since this is the most important code that makes the machine work.

All the VC4 code makes it rather unreadable and hard to maintain. I, as the developer may cope with it, but if my colleaque would have to take a look and fix a bug under time pressue this becomes a problem.

So … I’m looking for a more elegant solution to work with VC4 and would be grateful if someone could share their approach.

Many thanks!

Hi Torsten,

what I always did in these cases is:
Create a dedicated "Visu"Task, with a local Variable (much like your global one)
and then handle all VC4-Specific Datapoints through there.
In your case this would mean that you would have the same “someSM” Variable in the VC4-Task (either via PVmapping, global Variable or with the address of the variable with PV_xgetadr()…)

and essentially “mirror” your statemachine in the Visu-Task.

So the “original” Statemachine would like your example, without all the “gVC4” parts
Your “Visu” Statemachine would only have the “gVC4” parts, without the controls and the “next-Step” Parts

3 Likes

Hello Stefan,
thanks for the reply, these are the ideas I’m looking for ^^
I’m not sure if I fully understood your approach though. Mirroring the statemachine and putting the VC4 related code into another task would mean, that I have state transitions in 2 different tasks? For example “user clicks button to start process” would have to be initiated in the visu-task then?

Hi,
no, thats not what I meant, sorry.
You just “mirror” the value of the statemachine-variable.
If you make a pv-mapping of the variable from your “main”-Task (where the statemachine runs) to your “visu”-Task you have the value (the current state) and can do stuff depending on the current state, without having to care about the transitiotns in your visu-task

Hello Stefan and thanks for the reply,
I think I partly understood your approach. Its like a “read-only”-SM in the visu-task that just reacts on the state-changes that happens in the main-task.
The problem I see is: the visu can become an active player that initiates a state change, for example when a user hits a button to start a process.

Exactly, the statemachine is “read-Only” in the visu task.
If you want to react to a user-input in your statemachine you make a read-only variable of your boolean-Value from your “Visu”-Task in your “main”-task.
For Example: You have the 2 tasks “MainControl” and “VisuCtrl”.
Your Statemachine Variable “StateMachine” Runs in the Task “MainControl” and you want only to react to the current state in the VisuCtrl Task.
So you make a Pv-Mapping from Task “StateMachine” to “VisuCtrl”

and also you want to react to the Variable “Start” From the Task “VisuCtrl” in you Statemachine.

So you make a PV-Mapping From Task “VisuCtrl” to “MainControl” using the Variables “Start” and “UserInput_Start”

that way, you can only write the statemachine in your Task “MainControl” and your variable “Start” only in the Task “VisuCtrl”

But you can react to the state of those two Variables in the corresponding Task.

The PV-Mapping (*.vvm-File in Configuration View) for this example would look like this:

VAR_CONFIG
	::MainContro:StateMachine AT %Q.::VisuCtrl:StateMachine; (*Insert your comment here...*)
	::VisuCtrl:Start AT %Q.::MainContro:UserInput_Start; (*Insert your comment here...*)
END_VAR

You would need to “mapp” every Button or input-Value you want to use outside of your Visutask this way, but that is one way to separate your visualisation from your “backend” Code. If I understood you correctly that is what you want to do.

I hope this makes things a little more understandable

Hi @c418917 ,

It looks like you got some good suggestions from other community members, and it has been a couple of weeks since the last activity on this post. Can you please mark the reply that helped you the most as the solution? Or if you still have open questions on this topic, can you please provide an update?

Jaroslav