Variable bindings provide marshalling and change notification services for statically linked target variables. These can be any variable compiled in the C application which is not a stack variable, or a variable allocated from the heap at runtime. The term “global variable” could be used, however the term “statically linked” is used due to the generally negative connotation associated with the use of global variables as a design practice, as well as the fact that these instantiated variables don’t need to be referenced from other C files. Simply put, the variable must be statically located in memory at link time by the linker.
Configurations for variable bindings are shown under the Variables tab in the Target Model Builder, as shown.
To create a variable binding, the variable must be compiled in the target first. This means that you will need to build the project after adding the C code to declare the variable. Once the target is successfully compiled, open the Target Model Builder for that project and click the yellow ‘New’ icon in the lower-left corner, or right-click in the tab area and select ‘New’. The “Create New Variable” window will pop up. By default, the “Advanced” settings will be minimized, as shown.
The settings, including the advanced settings shown below, are described as follows.
1. Target Variable – This is the variable you would like to create a binding for in the target. Start typing the name of the variable and select the variable from the auto-filter results. The framework is automatically aware of every statically linked variable in your target, you just need to specify which one you want to create a binding for.
2. Host Variable Name – This specifies how you want to name the variable as it is exposed on the target model C# class. The host variable name is the same as the target variable name by default, and usually there’s no reason to change it, but you can rename it something different if you want to.
3. I/O Direction – This determines the binding direction, or the direction that data is intended to flow.
INPUT [C# -> C]: Use this when you want to control a value from the host. By writing to the property on the target model, you will be writing directly to the variable in the target.
OUTPUT [C -> C#]: Use this when you want to control a value on the target model from the target. By reading the value of the property on the target model in the host, you will be directly reading the variable in the target.
BIDIRECTIONAL [C# <–> C]: Use this when you want a variable to be simultaneously accessible from either the host or the target by reading or writing. The variable as instantiated in the target memory serves as the backing store for a dual-access variable, or as a dual-port memory.
4. Binding Type – When the variable binding is created, it is exposed on the Target Model as a property. The Binding Type allows the type of the property on the target model class to be specified. The framework will perform casting automatically for you if your binding type is different from the target variable type. For example, your target variable could be an unsigned char output, but you might want to expose it as a ‘bool’. The framework will convert non-zero values to true and zero to false automatically. A yellow warning icon will be shown if there is a potential loss of data in the binding type, or if the binding types are incompatible.
5. Variable Access Mode – This setting specifies how you want the target variable to be exposed on the target model. There are two types: ‘Model Property Interface’ and ‘Target Model Property’.
Assume you have an integer in the target you want to expose to the target model for the target ‘MyTarget’:
int MyInteger;
MyTarget will be a normal class, for example a C# class for a C# host. If “Target Model Property” is selected as the variable access mode, then MyInteger will be accessed as a standard integer property, like this:
public class MyTargetModel : LocalVisualStudioCTargetBackgroundController
{
public Int32 MyInt
{
get { return TargetController.GetInt32Property("MyInt"); }
set { TargetController.SetInt32Property("MyInt", value); }
}
}
The above example assumes that the property is specified as bidirectional. An instruction in C# to set the MyInt property to 100 will call internal code to go straight to the target memory and set the variable in the target to 100.
MyTargetModel.MyInt = 100;
Conversely, read accesses of the property will internally result in the GetInt32Property base class function being called, which will read the variable directly from target memory and return the result.
int TargetVariable = MyTargetModel.MyInt;
Target model properties support change notification. If you come from an embedded programming background and are new to C#, this means that a separate C# object can register to be notified when properties on the target model class change. To see how this is implemented, open your target model class, located in the “VirtuosoCore” folder of your host project. You will see in the declaration of your class that the target model class implements the INotifyPropertyChanged interface. If you then right click on that interface declaration and click “Go To Definition”, you can see that all objects that implement the INotifyPropertyChanged interface must implement a PropertyChanged event. This event based change notification is the primary binding mechanism for data sources. A data target can bind to the target model class by registering an event handler for the PropertyChanged event. When the event handler fires, it can check to see if “MyInt” was the property that changed, and respond accordingly.
This is a great and effortless way to expose target variables on the target model. There are two potential disadvantages to this, however. The first disadvantage is performance related. The target model class could have two output variables, one unsigned char output that could change tens of thousands of times a second, and one 10000-byte buffer which changes once a second. Both of these variable bindings would be properties of the same class, the target model class. If either variable change then the INotifyPropertyChanged PropertyChanged event will be generated. The event handler for the large byte array change notification will be forced to respond to tens of thousands of change notifications generated for the single byte variable, checking to see if the property name matches “MyBigBuffer”, and ignoring it if it doesn’t. With dozens of variable bindings on a target model class, each of which could be frequently generating change notifications, the concern regarding host runtime performance should be clear.
The other potential disadvantage is architectural in nature. When a variable binding is created by exposing it as a standard property of the target model class, it is essentially referenced by name, i.e. MyTarget.MyBigBuffer. A class could be written to encapsulate reusable functionality and use properties of the MyTarget class, however references to MyBigBuffer would have to be hard-coded. Prior knowledge of how to get the big buffer would be required, and the best practice of designing class objects that depend on interfaces instead of implementations would be broken.
The solution to both problems is to expose the target variable as a property interface. That is, to create a property on the target model class which exposes an interface object that allows the target variable to be accessed. Instead of a standard property being rendered on the target model class like this:
public Int32 MyInt
{
get { return TargetController.GetInt32Property("MyInt"); }
set { TargetController.SetInt32Property("MyInt", value); }
}
A property interface object is exposed as a property, like this:
private IInt32Property _MyInt = new Int32Property(0);
public IInt32Property MyInt
{
get { return _MyInt; }
}
MyInt is now an IInt32Property interface, which I can view again by using GoToDefinition:
public interface IInt32Property
{
int Value { get; set; }
event IInt32PropertyValueChangedEventHandler ValueChanged;
void SetValueWithoutChangeNotification(int value);
}
Here, MyInt serves as a getter for the property interface, and to access the target variable on the target model class object from C#, I would write this:
int TargetVariable = MyTargetModel.MyInt.Value;
This code accesses the property interface first, then accesses the Value property of the property interface. Internally, the value of the target variable is then returned.
You will note that the property interface has a ValueChanged event. The object that implements this interface is an independent object dedicated for this target variable, and will only fire the change event when this target variable changes, decoupling change notification processing between target variables now that the data source is a separate object. And since the property interface itself is a separate object, I can now write a class which depends on a big buffer property as an interface instead of an implementation, i.e.:
BigBufferProcessingClass WellArchitectedProcessor = new BigBufferProcessingClass(MyTargetModel.MyBigBuffer);
With these advantages of the property interface over the standard target model property, you might ask why you would want to expose a target variable as a normal property. The reason is as follows. When you use Virtuoso to create a host application, the host’s main view has a data context which is automatically set to a HostViewModel class. This HostViewModel class inherits from the BaseHostViewModel class emitted based on your schematic design. When you add targets to the host, the target view models, which inherit from their respective target model base class, are automatically added as normal properties of the BaseHostViewModel class.
The above paragraph may be difficult to follow if you are just starting out learning the Model-View-ViewModel design pattern. But what it means is this. Let’s say you want to create a host, then add three targets, TargetA, TargetB, and TargetC, and then display the value of a byte variable from TargetB in a textbox on the view at runtime so you can watch it as it changes. To do this, you would simply need to expose the byte variable on TargetB, let’s say it’s named ‘MyByte’, as a target model property. Then, the view XAML code to display this variable looks like this:
<TextBlock Foreground=”White” Text=”{Binding MyTarget_ViewModel.MyByte}”/>
If you were to attempt to expose the byte as a property interface and bind to it, you would use the following expression:
<TextBlock Foreground=”White” Text=”{Binding MyTarget_ViewModel.MyByte.Value}”/>
In this case, the Text property of the TextBox object would read the value of the Value property the first time the TextBlock is initialized, however runtime changes to the MyByte value won’t get updated to the TextBox, because the TextBox’s Text data binding is looking for change notifications coming from the source object (the target view model, MyTarget_ViewModel), not the property interface (MyTarget_ViewModel.MyByte). Thus, for simple variables being exposed for direct binding to a standard control like a Slider control binding to an integer, exposing the variable as a standard property may be quicker and easier.
The video below shows the difference in property interface and target model property bindings from the view.
6. Property Changed Thread – This setting specifies which thread the property change notification will be invoked on for Output and Bidirectional variables that have been updated in the target. Normally, when the framework detects that the target variable has changed and needs to notify the host, the callback is called directly from the background thread which is monitoring for changes. Thus, when an event handler is added in the host, the event handler will be executing on the background thread when it is called. The Property Changed Thread setting allows the change notification to be dispatched to the display thread instead of the default background thread. This is because WPF display controls are not thread safe, and so changes to display controls must occur on the thread that they were created, i.e. the display thread.
To see where this might be used, consider the following scenario. You have a three-byte array in your target which you wish to expose to control the 3-byte RGB color of a control on the view.
unsigned char Color[3];
After adding the byte array on the Target Model Builder, you manually add a SolidColorBrush property to your target view model to bind to from the view, initialized to Red:
private Brush _MyBrush = new SolidColorBrush(System.Windows.Media.Colors.Red);
public Brush MyBrush
{
get
{
return _MyBrush;
}
set
{
if (_MyBrush != value)
{
_MyBrush = value;
OnPropertyChanged("MyBrush");
}
}
}
Then when the byte array changes in the target, you update the Brush to the new color, first by adding a PropertyChanged event handler to the target view model and then adding the code to create and update the brush:
private void InitializeComponents()
{
// Add component(s) here....
// ...
PropertyChanged += TargetViewModel_PropertyChanged;
}
private void TargetViewModel_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == "Color")
{
byte[] _NewColor = this.Color;
System.Windows.Media.Color NewColor = System.Windows.Media.Color.FromArgb(255, _NewColor[0], _NewColor[1], _NewColor[2]);
MyBrush = new SolidColorBrush(NewColor);
}
}
You then add a standard Windows ellipse shape to the view and bind its Fill property to MyBrush, as shown.
<Ellipse Fill=”{Binding Target_ViewModel.MyBrush}” Width=”50″ Height=”50″/>
In this case, an exception will be generated the first time you update the byte array in the target, because by default the PropertyChanged callback will be executing on a background Virtuoso framework thread. To confirm this, set a breakpoint in the TargetViewModel_PropertyChanged function after the check for e.PropertyName matches Color:
Then open the Threads window by clicking Debug->Windows->Threads, and you will see that the current thread is an unnamed background worker thread.
The NewColor and new brush will thus be created on the background thread and returned when the getter for MyBrush is called. This will result in an exception being generated.
An unhandled exception of type ‘System.ArgumentException’ occurred in WindowsBase.dll
Additional information: Must create DependencySource on same Thread as the DependencyObject.
Here, the DependencyObject is Ellipse, and the DependencySource is MyBrush. In order for the standard WPF data binding to work, they both need to be created on the same thread. By dispatching the creation of the brush to the display thread and setting the property on the display thread as shown below, the color binding works as expected.
The binding requires both objects to be created on the same thread because otherwise the control would access its data source in a non-thread-safe way, which can put the control in an inconsistent state:
https://msdn.microsoft.com/en-us/library/ms171728(v=vs.110).aspx
By setting the Property Changed Thread to DISPLAY THREAD, the callback will be dispatched to the display thread automatically for you, saving you from having to manually dispatch the callback handler to the display thread. However, generating the change notification from the background thread involves less work and is quicker. Thus, using the background thread can result in faster performance and is recommended when a display object doesn’t need to be created in the PropertyChanged event handler.
7. Persistent – This setting specifies whether the target variable should be persistent or non-persistent. The values of persistent variables are serialized to disk when the host closes. When the host is run again, the values are de-serialized and loaded back into memory. This occurs inside the InitializeVirtuoso() function which is recommended to be called immediately after entering main().
Persistent variables are an extremely easy way to virtualize non-volatile memory such as EEPROM and flash memory. You can simply declare a byte array of the correct size, and add it to the Target Model Builder with the “Persistent” checkbox checked, and the array will be stored and reloaded for you between executions of the host. Variable bindings are non-persistent by default.
8. Callback ISR – The callback ISR setting allows any void function(void) in the target to be called whenever a property is changed by the host. This allows changes to input variables to be immediately processed in the target before subsequent host code is executed.
9. Change Notification – The Change Notification setting specifies how changes to Output or Bidirectional variables are detected and reported to the host. For automatic change notification, you simply need to write to the variable in the target, and the change will be picked up by a background thread in the framework and reported to the host. In some cases, manual change notification is preferred, where a second variable is selected to act as a change notification flag. When the flag is manually set to ‘true’ or a positive value, the change notification will be generated. This allows a degree of thread synchronization between the target thread and the host, ensuring that the host doesn’t process a change notification while the target is in the middle of updating a large display buffer, for example. Once the display buffer or variable is finished being updated, then the flag can be set to generate a change notification. The framework will clear the flag after it has acknowledged the change.
Manual change notification is also useful in synchronizing the target thread with the processing of an output. Since neither the execution start time or execution duration of a change notification handler in the host can be known by the target, manual change notification can be used to ensure that the host is in a state where the new value has been received. The host could use a separate flag (added to the Target Model Builder separately) as an acknowledgement flag, and the target thread could block until the acknowledgement flag is set to perform synchronization, for example.
The synchronization thread is responsible for monitoring all variables for changes at runtime, which have specified change notification as AUTO. For large buffers that change frequently, such as LCD display buffers, the synchronization thread has to continuously scan the buffer for changes. This can affect the scan speed and change notification latency of other variables. By specifying the change notification as MANUAL and manually setting a flag when changes are complete, the synchronization thread is required to do less work and can detect other variables more efficiently and quickly.
10. Manual Change Notification Flag – When the above Change Notification setting is set to Manual, a corresponding variable must be specified to use as the change notification flag. A flag value of zero indicates to the framework that the variable has not changed. A flag value greater than zero indicates that the variable has changed. The framework will automatically clear the change notification flag when the change notification has been processed.
11. Invert Logic – This setting is valid only for Boolean variables. By checking the “Invert Logic” checkbox, this allows the value interfaced between the target and the host to be inverted.