RTD UpdateTopic issues

Add-in Express™ Support Service
That's what is more important than anything else

RTD UpdateTopic issues
 
Nir Wein




Posts: 577
Joined: 2011-03-28
Hello, I have been working on an RTD server for a while (pre-Add-in Express, i.e. with IRTDServer implementation) where every time a cell is being updated it sends two request for update so I can get 2 values associated with each cell.
this method worked and still working in the IRTDServer implementation.
I've been doing a lot of reading, mainly on these two threads (http://www.add-in-express.com/forum/read.php?PAGEN_1=1&FID=5&TID=8050#nav_start and http://www.add-in-express.com/forum/read.php?PAGEN_1=1&FID=5&TID=8413#nav_start)
and I was able to come up with an RTDServerModule solution with
Interval =0
that works from my Connect event as a separate thread/task (code snippet from my Connect method:
Task.Factory.StartNew(() => UpdateTopic(topic))
)
However, since I'm calling my connect twice for each new cell/topic the Refresh method doesn't get called twice (mainly because of thread/task not finishing).
If I put wait for task to finish, nothing really happens (i.e.
Task.WaitAll(Task.Factory.StartNew(() => UpdateTopic(topic)))
)

this is the method I've been using in my IRTDServer implementation. I also had to change my code to accommodate for the fact that Add-in express Connect method doesn't return a value as opposed to IRTServer's connect; this allowed me to get the initial value without any problem.
Any suggestions as to how I can get it to work?
this is (hopefully) the final thing standing between me having an Add-in Express solution to a regular COM RTD solution.
Thanks!
Posted 28 Mar, 2011 11:41:36 Top
Eugene Astafiev


Guest


Hi Nir,

What version and build number of Add-in Express do you use? Excel version?
Posted 28 Mar, 2011 11:47:51 Top
Nir Wein




Posts: 577
Joined: 2011-03-28
Sorry, forgot to include those :oops:
Add-in Express 2010 6.3.3052 Standard
Targeting Excel 2003 and 2010 (32 bit)
Posted 28 Mar, 2011 11:51:08 Top
Sergey Grischenko


Add-in Express team


Posts: 7233
Joined: 2004-07-05
Hi Nir,

I also had to change my code to accommodate for the fact that Add-in express Connect method doesn't return a value as opposed to IRTServer's connect;

To get the actual rtd topic in the Connect event handler of the ADXRTDTopic component you can use the code below.
private void adxrtdTopic1_Connect(object sender, EventArgs e)
{
ADXRTDTopic caller = sender as ADXRTDTopic;
}

The same way you can obtain rtd topics in the RefreshData event.
I don't quite understand your algorithm. Could you please send a little example? I will test it.
Posted 30 Mar, 2011 06:20:45 Top
Nir Wein




Posts: 577
Joined: 2011-03-28
Thanks Sergey, I'm already getting the topic in the connect, it's the fact that Connect doesn't return a value that I was comlpaining.
If you look at the Connect signature for IRTDserver you'd see that it returns an object (dynamic ConnectData(int TopicID, ref System.Array Strings, ref bool GetNewValues))
Add-In Express's topic connect doesn't. But that is not the main problem, my main problem is that I can't synchronize the refresh data with my connect event, hopefully my code example will make it clearer:

private void ConnectData(object sender, EventArgs e)
{
	var topic = sender as ADXRTDTopic;
	if (topic == null) return;
	if (string.IsNullOrEmpty(topic.String01)) throw new Exception("Error: Subject not speicifed");
	string subject = topic.String01.ToUpper();
        bool isTimestamp = subject.EndsWith(TIMESTAMP);
	object value = istimestamp ? Cache.GetTimestamp(subject) : Cache.GetValue(subject);	
	AddNewDataItem(topic, value);
	RefreshData(topic);
	Task.Factory.StartNew(() => UpdateTopic(topic));
}


The AddNewDataItem is a private method to maintain my own dictionary of items.
When calling the RefreshData the topic value actually changes, however it will not be reflected until I call the UpdateTopic from another thread (calling it from the same thread doesn't invoke it and Excel will not refresh the value).
However that task/thread keeps running indefinitely (I can see it b the Tasks's status which remains running constantly) and this is the core of the problem.

In our solution we're trying to associate two values for each cell, one visible and one "behind the scenes" which is used for other functionalities.
When I'm calling my RTD from my created UDF twice from the same cell (for new values. i.e. connect, each time slightly different to get a different type of value, yet still only a single topic) I'm not getting the effect of two values per cell. Only the last value is being "caught" in the RefreshData method.

My code for calling the RTD twice is as follows:

public static object LightningPrices(string param1, string param2)
{
	if (Module.IsInFunctionWizard)
		return "this UDF call an RTD server";
	string topic = string.Format("{0}.{1}", param1, param2).ToUpper();
	
	// Call once to get the timestamp
	var rtdValue = Module.CallWorksheetFunction(ADXExcelWorksheetFunction.Rtd, "RTD_ProgId", string.Empty, topic + ".TIMESTAMP");
	if (rtdValue is double)
	{
		// Do somethign with the first value getting back
	}

	// Call twice to get the actual value
	rtdValue = Module.CallWorksheetFunction(ADXExcelWorksheetFunction.Rtd, "RTD_ProgId", string.Empty, topic);
	return rtdValue;
}


Also I'm including my RefreshData implementation (just in case):

private object RefreshData(object sender)
{
	if (sender is ADXRTDTopic)
	{
		_topic = sender as ADXRTDTopic;
		var updatedItems = GetUpdatedDataItems();
		return updatedItems.ContainsKey(_topic.String01) ? (object) updatedItems[_topic.String01] : _topic.DefaultValue;
	}
	return null; // something went wrong
}


GetUpdatedDataItems() returns a dictionary of all the items I care about that were updated recenetly.

As mentioned before - this solution works well with IRTDServer implementation.
Please let me know if you still need any other clarifications.
Thanks!
Posted 30 Mar, 2011 10:54:45 Top
Sergey Grischenko


Add-in Express team


Posts: 7233
Joined: 2004-07-05
Hi Nir,

If you look at the Connect signature for IRTDserver you'd see that it returns an object (dynamic ConnectData(int TopicID, ref System.Array Strings, ref bool GetNewValues))
Add-In Express's topic connect doesn't.

Add-in Express returns this object too but internally. To return the default value you need to set the DefaultValue property of the ADXRTDTopic component.

calling it from the same thread doesn't invoke it and Excel will not refresh the value

I think that you just need to use a timer (Interval = 200 or so) and disable it in the Tick event handler. In this case the UpdateTopic method will be called once for each connected rtd topics. Please test it. Let me know if the issue still exists.
Posted 31 Mar, 2011 10:09:59 Top
Nir Wein




Posts: 577
Joined: 2011-03-28

I think that you just need to use a timer (Interval = 200 or so) and disable it in the Tick event handler. In this case the UpdateTopic method will be called once for each connected rtd topics

OK, I've tested this and here's the workflow and the results of how it's working (this is for a new topic):

1. Excel's UDF calls the RTD with topic1.string0 x
2. The Connect method updates the default value for topic1.string01 x
3. The Connect method calls Refresh to topic1.string0 x
4. The Connect method calls a threaded timer that calls in turn UpdateTopic (topic1.string x) and blocks until the callback has finished (200ms)
5. The UDF retrieves a value from the RTD call but this value is wrong! (it's the initial topic1 default value, not the newly assigned, or anything)
6. The UDF goes on to call the RTD with topic1.string0 y
7. repeat steps 2 - 5 but with topic1.string0 y

Note, if I'm debugging and breaking my timer callback, after both calls to the RTD by my UDF the RefreshData is being called (by who? I don't call it anymore, the only place I'm calling it is from my Connect) with the last topic, i.e. topic1.string0 y and I get the value associated with it.

As you can see, this is still not working, I'd also like to not "hack" my solution by putting hard coded "waits" to wait for the tread to finish their job, but I'd like to get everything else working beforehand
Posted 31 Mar, 2011 12:29:12 Top
Sergey Grischenko


Add-in Express team


Posts: 7233
Joined: 2004-07-05
Note, if I'm debugging and breaking my timer callback, after both calls to the RTD by my UDF the RefreshData is being called (by who? I don't call it anymore, the only place I'm calling it is from my Connect) with the last topic, i.e. topic1.string0 y and I get the value associated with it.

What exactly timer do you use? Is it System.Windows.Forms.Timer or System.Threading.Timer?
Do you disable the timer before you call UpdateTopic method?
Posted 01 Apr, 2011 10:11:02 Top
Nir Wein




Posts: 577
Joined: 2011-03-28
Thanks for attempts Sergey, however I don't think that Addin Express's ADXRTDServerModule by itself can solve my issues. I've really exhausted my attempts with it.

I did however got my solution to work using Addin Express own IRTDServer (i.e. AddinExpress.RTd.IRtdServer) and not Excel's IRtdServer (even though they are almost the same) along with ADXRTDServerModule.
What I ended up doing was to leave my previous implementation (which was working properly) and extend my class to both ADXRTDServerModule and AddinExpress.RTd.IRtdServer, implementing the component designer portions and the Register/Unregister methods.
this seems to have solved my problems, and now my RTD server can be registered and distributed with Addin Express functionality, which is what I was looking to achieve from the first place.
Posted 01 Apr, 2011 10:21:52 Top
Sergey Grischenko


Add-in Express team


Posts: 7233
Joined: 2004-07-05
Nir, if you send me a simple example of your own implementation, I will try to implement the same code but using the RTD server module. If I don't find any solution, I will fix the issue in the next build of the product.
Posted 01 Apr, 2011 10:27:31 Top