Results 1 to 6 of 6

Thread: Best approach for migrating an app to became a plugin

  1. #1
    Low Bitrate
    Join Date
    Oct 2006
    Location
    Moscow ZAO, Russia
    Posts
    104

    Best approach for migrating an app to became a plugin

    Dear All,

    I have a C++ App, which is done in multiplatform way using platform-independent GUI graphic
    library and some low-level C code. Application is multi-threaded, and there is a high speed application thread that monitors attached USB device, consuming very little processor cycles.

    I need to port it to RR plugin or embed it as external application, i.e. make it convinient for RR users to install and use the app in RR environment.



    When there is an event, recieved from device, corresponded RR plugin must
    activate, pop-up, pause video and/or music stream (if user selected than in the options), visualize parking radars measurements. When parking radar is deactivated or obstacle is out of range, after some periodic delay, the plugin must resume whatever media play was in progress and hide.

    Easiest way to be embedding an application, but is there any way to communicate with RR, making it suspend music, etc. - like network socket or library API?

    I tried installing relevant RRCam and PDC plugins, no luck with installation yet, hard to understand all the requirements from scratch.

    Thanks for all your input in advance.
    -- Novorado
    Will contract for C++/Win-Linux/PIC jobs

  2. #2
    Confusion Master
    Auto Apps:loading...
    Enforcer's Avatar
    Join Date
    Sep 2003
    Location
    If you go down to the woods today, You're sure of
    Posts
    14,633
    Looking at the image of your app it seems to be similar to RRPDC, so that's probably the one to look at.

    Robby has posted the source so that should help.

    Not why you haven't been able to get either of the two plugins you mentioned to work though.



    Also this FAQ should help


    http://www.mp3car.com/rr-faq/86680-h...n-with-rr.html


    If you look at the list of ways you will see you can use the windows API

    Quote Originally Posted by guino
    This basically uses the SendMessage Windows API call with the WM_COPYDATA inteface to exchange messages between applications

  3. #3
    Low Bitrate
    Join Date
    Oct 2006
    Location
    Moscow ZAO, Russia
    Posts
    104
    Thanks, @Enforcer. Base on quick reading, looks like recommended integration recipie recommended by @Guino is probably most straigtforward way. I could not install PDC, it's VB6 based, and my PC is all over to .NET. Probably some DLLs incompatibility. Will see how it goes though.
    Attached Images Attached Images  
    Last edited by novorado; 05-17-2011 at 05:56 AM.
    Will contract for C++/Win-Linux/PIC jobs

  4. #4
    Confusion Master
    Auto Apps:loading...
    Enforcer's Avatar
    Join Date
    Sep 2003
    Location
    If you go down to the woods today, You're sure of
    Posts
    14,633





    Probably an OCX or DLL, or some other VB6 runtime that we VB6 programmers always assume is on the system.

  5. #5
    Low Bitrate
    Join Date
    Oct 2006
    Location
    Moscow ZAO, Russia
    Posts
    104
    Quote Originally Posted by Enforcer View Post

    Probably an OCX or DLL, or some other VB6 runtime that we VB6 programmers always assume is on the system.
    Thanks @Enforcer, so far so good.

    I have low-level device library, using all the device driver mess, multithreaded cyles, it's. It is a mix of ancient technologies written with highly optimized GCC C++/C/ASM platform legacy code. Due to compiler architecture and differences in mangling and code convensions, it can not be easily called from C#/VB* DLL's.

    Here is glue DLL interface code that simplifies calling by providing a glue code. Works for Centrafuse like charm.
    Code:
    #include	<iostream>
    #include	<fstream>
    #include	<novopark.h>
    #include	<ParkingProtocol.h>
    #include	<QStringList>
    #include	<QSettings>
    #include	<map>
    #include	<set>
    #include	<sstream>
    
    std::ofstream log("c:/temp/log.txt");
    
    // Define callback
    class Feedback : public Novorado::ParktronicUpdateCallback
    {
    	public:
    	
    		std::string devVersion;
    		int hasDevVersion;
    		
    		Feedback(){ hasDevVersion=false; }
    
    		void load_heads();
    		void init();
    
    		PtrHolder<Novorado::Parktronic> m_park;
    		
    		void poll(){ 
    			log << "poll()" << std::endl;
    			m_park->quant(); 
    			}
    		
    		std::map<Novorado::LineId, std::map<Novorado::HeadId,Novorado::HeadLogicNumber> > m_ha;
    		std::map<Novorado::LineId, std::set<Novorado::HeadId> > m_unassigned_heads;
    		std::map<Novorado::LineId, Novorado::ParkingProtocol::PROTOCOLS> line_assignment;
    		
    		struct Sensor{
    			bool visible: 1;
    			int distance;
    			Sensor(){ visible=false;distance=255; }
    			};
    
    		Sensor m_sensors[8];
    	
    		void onNewDevice(Novorado::LineId l)
    		{
    			log << "onNewDevice(" << l <<")" << std::endl;
    		}
    		void onNewHead(Novorado::LineId l, Novorado::HeadId h)
    		{
    			log << "onNewHead(" << l << "," << h <<")" << std::endl;
    		}
    		void onDistanceChange(Novorado::LineId l, const Novorado::Pair& p)
    		{
    			log << "onDistanceChange(" << (int)(l) << ":"  << p.headId << " " << p.distanceCM << "cm)" << std::endl;
    
    			std::map<Novorado::LineId, std::map<Novorado::HeadId,Novorado::HeadLogicNumber> >::iterator i=m_ha.find(l);
    			if(i==m_ha.end()) return;
    			std::map<Novorado::HeadId,Novorado::HeadLogicNumber>::iterator j=i->second.find(p.headId);
    			if(j==i->second.end()) return;
    			
    			Novorado::HeadLogicNumber h=m_ha[l][p.headId];
    			if(h<1||h>8) throw std::logic_error("Number out of bound in 'onDistanceChange(Novorado::LineId l, const Novorado::Pair& p)'");
    			
    			log << "Writing to head " << (int)(h) << std::endl;
    			m_sensors[h-1].distance=p.distanceCM;
    		}
    		void onStatusChange(Novorado::STATUS st, std::string s)
    		{
    			log << "STATUS CODE #" << (int)(st) << " " << std::flush;
    			switch(st){
    				case Novorado::NRDP_DATA_FEED_STARTED:
    					log << "Data feed started" << std::endl;
    					break;
    
    				case Novorado::NRDP_DATA_FEED_STOPPED:
    					log << "Data feed stopped" << std::endl;
    					break;
    
    				case Novorado::NRDP_RECEIVING_DATA:
    					log << "Connected, incoming data packet" << std::endl;
    					break;
    
    				case Novorado::NRDP_GOT_PING:
    					log << "Gotaping" << std::endl;
    					break;
    
    				case Novorado::NRDP_FIRMWARE_UPDATE_MODE:
    					log << "Firmware update mode" << std::endl;
    					break;
    
    				case Novorado::NRDP_CONNECTING:
    					log << "Connecting to the device: " << s << std::endl;
    					break;
    
    				case Novorado::NRDP_NO_PARKTRONIC_SIGNAL:
    					log << "No signal: " << s << std::endl;
    					break;
    
    				case Novorado::NRDP_USB_CRITICAL_ERROR:
    					log << "Critical error: " << s << std::endl;
    					break;
    
    				case Novorado::NRDP_FIRMWARE_UPDATED_OK:
    					log << "Finished firmware update: " << s << std::endl;
    					break;
    
    				case Novorado::NRDP_FIRMWARE_UPDATE_FAILED:
    					log << "Unable to update the firmware: " << s << std::endl;
    					break;
    
    				case Novorado::NRDP_DEVICE_EMULATION:
    					log << "Emulation mode: " << s << std::endl;
    					break;
    
    				case Novorado::NRDP_GOT_DEVICE_VERSION:
    					log << "Received device version: " << s << std::endl;
    					devVersion=s;
    					hasDevVersion=true;
    					break;
    
    				case Novorado::NRDP_UNKNOWN_PROTOCOL:
    					log << "Protocol unrecognized: " << s << std::endl;
    					break;
    
    				default:
    					log << "STATUS " << st << ", unkown" << s << std::endl;
    					break;		
    				}
    		}
    		const char** onFirmwareMode()
    		{
    			return NULL;
    		}
    };
    
    static PtrHolder<Feedback> m_feedback;
    
    void Feedback::load_heads()
    {
    	QSettings m_settings("Novorado","ParkingAssistant");
    	m_ha.clear();
    	QStringList groups=m_settings.childGroups();
    	
    	log << "Loading settings, " << groups.size() << " groups" << std::endl;
    
    	for(int g=0;g<groups.size();g++){
    
    		QString grp=groups[g];
    		if(grp.left(6)=="Device"){
    
    			m_settings.beginGroup(grp);
    
    			// Get the device id
    			grp=grp.right(grp.size()-6);
    			Novorado::LineId deviceId=grp.toInt();
    
    			// Look for all the logic head connected to that device
    			QStringList keys=m_settings.allKeys();
    			for(int k=0;k<keys.size();k++) {
    				QString key=keys[k];
    
    				// spot Novorado::HeadId<x>=disabled
    				QString l=key.left(6);
    
    				if(l=="Novorado::HeadId"){
    
    					QString v=m_settings.value(key).toString();
    
    					l=key.right(key.size()-6);
    					Novorado::HeadId headId=l.toInt();
    
    					// Check if value is "disabled"
    					if(v=="disabled"){
    						m_unassigned_heads[deviceId].insert(headId);
    						log
    							<< "Disabled head - DeviceId=" << deviceId
    							<< ", Novorado::HeadId=" << headId << std::endl;
    						}
    
    					continue;
    					}
    
    				// it's probably an assignment than
    				l = key.left(9);
    				if(l!="LogicHead") continue;
    
    				l=key.right(key.size()-9);
    
    				Novorado::HeadLogicNumber num = l.toInt();
    
    				if(num<=0 || num>8){
    					std::stringstream ss;
    					ss << "Load heads assignment: value " << num
    						<< " is out of range";
    					throw std::logic_error(ss.str());
    					}
    
    				Novorado::HeadId hid = m_settings.value(key).toInt();
    
    				m_ha[deviceId][hid]=num;
    				m_sensors[num-1].visible=true;
    				log << "HEAD " << (int)(num) << " *** " << deviceId << ":" << hid << std::endl;
    				}
    
    			m_settings.endGroup();
    			}
    		}
    
    //	f_LogicNumbersLoaded=true;
    }
    
    void Feedback::init()
    {
    	hasDevVersion=false;
    	load_heads();
    
    	// Tweak. Prevent from going into OSCO mode. We know the lines, it's fixed board for now
    	if(!line_assignment.size()) {
    		line_assignment[4]=Novorado::ParkingProtocol::CHALLENGER_26;
    		line_assignment[5]=Novorado::ParkingProtocol::CHALLENGER_26;
    		}
    
    	// Pthread 1: Launch USB ThreadProc loop
    	m_park=new Novorado::Parktronic(this,&line_assignment);	
    }
    
    // Initialize parking assistant
    extern "C" int pa_head_visible(int i /* 0-7 */)
    {
    	if(i<0||i>7) throw std::logic_error("Index out of bound in 'pa_head_visible'");
    	return m_feedback->m_sensors[i].visible;
    }
    
    #define	USB_POLLS_MSEC 50
    extern "C" int pa_poll_interval()
    {
    	return USB_POLLS_MSEC;
    }
    
    extern "C" int pa_retry_delay()
    {
    	return 5000;
    };
    
    extern "C" int pa_hide_delay()
    {
    	QSettings m_settings("Novorado","ParkingAssistant");
    	m_settings.beginGroup("gui");
    
    	//m_showDelay=m_settings.value("ShowDelay","1").toInt();
    	int m_hideDelay=m_settings.value("AutoHideDelay","3").toInt();
    
    	m_settings.endGroup();	
    	return m_hideDelay*1000;
    };
    
    extern "C" int pa_init()
    {
    	try {
    		m_feedback = new Feedback;
    		m_feedback->init();
    	} 
    catch( const std::logic_error& e)
    	{
    		log << "Init: Caught " << e.what () << std::endl;
    	}
    catch( ... )
    	{
    		log << "Init: unkown exception" << std::endl;
    	}
    	
    	return 1;
    }
    
    extern "C" int pa_head_distance(int i)
    {
    	if(i<0||i>7) throw std::logic_error("Index out of bound in 'pa_head_distance'");
    	
    	return m_feedback->m_sensors[i].distance;
    }
    
    extern "C" void pa_poll()
    {
    	// Ignore poll rquests until has device version
    	if(m_feedback->hasDevVersion) m_feedback->poll();
    }
    
    extern "C" int pa_ping()
    {
    	return 1;
    }
    Now, following guidelines provided by @mitjcs, looks like best & RoadRunner native integration scenario would be adding a Park Asisst interface class and inheriting RRExtension from it

    Code:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.IO;
    using System.Reflection;
    using System.Runtime.InteropServices;
    // Debug
    using System.Diagnostics;
    
    /*
     * Remember every new plug in must have new GUIDS, there are 3:
     * The Interface class (IRRExtension.cs), the RRExtension class (RRExtsion.cs)
     * and in the properties for the ASSEMBLY (AssemblyInfo.cs)
    */
    
    namespace ParkingAssistant
    {
        [Guid("4E7297A3-25D0-4e96-9A30-E7F0C3DD1DD2")]
        [ClassInterface(ClassInterfaceType.None)]
    
        public class USBDevice
        {
            #region NOVOPARK
            [DllImport("novopdc.dll", EntryPoint = "pa_init")]
            public static extern int pa_init();
            [DllImport("novopdc.dll", EntryPoint = "pa_poll_interval")]
            public static extern int pa_poll_interval();
            [DllImport("novopdc.dll", EntryPoint = "pa_ping")]
            public static extern int pa_ping();
            [DllImport("novopdc.dll", EntryPoint = "pa_head_visible")]
            public static extern int pa_head_visible(int id);
            [DllImport("novopdc.dll", EntryPoint = "pa_head_distance")]
            public static extern int pa_head_distance(int i);
            [DllImport("novopdc.dll", EntryPoint = "pa_poll")]
            public static extern void pa_poll();
            [DllImport("novopdc.dll", EntryPoint = "pa_retry_delay")]
            public static extern int pa_retry_delay();
            [DllImport("novopdc.dll", EntryPoint = "pa_hide_delay")]
            public static extern int pa_hide_delay();
            #endregion NOVOPARK
        };
    
    	public class RRExtension : ParkingAssistant.USBDevice, ParkingAssistant.IRRExtension
    	{
    		#region Private Fields
    		
    		#endregion
    
    		#region Constructor
    
    		public RRExtension()
    		{
    			if (SDK.Created == false)
    				SDK.SetSDK();
    		}
    
    		#endregion
    
    		#region Public RRExtension API Methods (new ones)
    
    		// this is called ONLY once, right after plug-in is loaded
    		// use this to set up anything you need, including data storage
    		public void Initialize(string pluginDataPath)
    		{
    
    			/*
    				pluginDataPath will contain a USER Profile (my documents) folder path
    				suitable for storing WRITEABLE settings to
    				this would make your plugin OS compliant (VISTA and onward)
    				not to mention, its proper programming, user data should NOT be stored in "Program Files"
        		
    			 * example (typical vista): "C:\Users\Username\Documents\RideRunner\Plugins\MyPlugin\"
        
    				App.path will be the path of the ACTUALL LOADED .dll (not recomend for any writes)
    			
    				uncomment code below if u need the directory
    			*/
    
    			// use to create data storage folder
    			if (Directory.Exists(pluginDataPath) == false)
    				Directory.CreateDirectory(pluginDataPath);
    		}
    
    		public void Enabled(bool state)
    		{
    			SDK.Enabled = state;
    		}
    
    		public string Properties(string item)
    		{
    			string properties = "";
    
    			switch (item)
    			{
    				case "version":
    					properties = Assembly.GetExecutingAssembly().GetName().Version.ToString();
    					break;
            case "category":
    					properties = "Driver Assistance";
    					break;
            case "description":
    					properties = "Parking Assistant";
    					break;
            case "supporturl":
    					properties = "http://www.novorado.com/";
    					break;
    			}
    
    			return properties;
    		}
    
    		#endregion
    
    		#region Public RRExtension API Methods
    
    		public int ProcessCommand(string CMD, object frm)
    		{
    			int result = 0;
    	
    			switch (CMD.ToLower())
    			{
    				case "boo":
    					SDK.Execute("PlaySound;scary.wav");
    					break;
    
    				case "yeah":
    					SDK.ErrScrn("title", "subject", "error details");
    					break;
    
    				case "onsuspend":
    					//
    					break;
    
    				case "onresume":
    					//
    					break;
    			}
    
    			return result;
    		}
    
    		public string ReturnLabel(string LBL, string FMT)
    		{
    			string s = "";
    
    			switch (LBL.ToLower())
    			{
    				case "boo":
    					s = "I'm Scared";
    					break;
    			}
    
    			return s;
    		}
    
    		public string ReturnIndicator(string Ind)
    		{
    			return "";
    		}
    
    		public string ReturnIndicatorEx(string Ind)
    		{
    			return "";
    		}
    
    		public long ReturnSlider(string SLD)
    		{
    			return -1;
    		}
    
    		#endregion
    
    		#region Logging
    
    		[ComVisible(false)]
    		static private void log(string message)
    		{
    			if (isAssemblyDebugBuild() == true)
    			{
    				SDK.DoLog(message);
    			}
    		}
    
    		[ComVisible(false)]
    		static private bool isAssemblyDebugBuild()
    		{
    			System.Reflection.Assembly assemb = System.Reflection.Assembly.GetExecutingAssembly();
    
    			foreach (object att in assemb.GetCustomAttributes(false))
    			{
    				if (att.GetType() == System.Type.GetType("System.Diagnostics.DebuggableAttribute"))
    				{
    					return ((System.Diagnostics.DebuggableAttribute)att).IsJITTrackingEnabled;
    				}
    			}
    
    			return false;
    		}
    
    		#endregion
    
    		#region Private Methods
    
    		#endregion
    	}
    	
    	#region RR SDK
    
    	[ComVisible(false)]
    	static public class SDK
    	{
    		static bool _Created;
    		static object RRSDK;
    		static Type objAddType;
    		static bool _Enabled = true;
    
    		static public void SetSDK()
    		{
    			try
    			{
    				objAddType = Type.GetTypeFromProgID("RideRunner.SDK");
    				RRSDK = Activator.CreateInstance(objAddType);
    				if (RRSDK != null)
    				{
    					_Created = true;
    
    					_Enabled = true;
    				}
    			}
    			catch 
    			{
    				// "Failed to create RideRunner SDK Com Interface"
    			}
    		}
    
    		static public bool Created
    		{
    			get { return _Created; }
    		}
    
    		static public bool Enabled
    		{
    			 set { _Enabled = value; }
    		}
    
    		static public void DoLog(string message)
    		{
    			if (RRSDK == null)
    				return;
    
    			if (_Enabled == false)
    				return;
    
    			objAddType.InvokeMember("RRLog", BindingFlags.InvokeMethod, null, RRSDK, new object[] { message });
    		}
    
    		static public void Execute(string CMD)
    		{
    			if (RRSDK == null)
    				return;
    
    			if (_Enabled == false)
    				return;
    
    			objAddType.InvokeMember("Execute", BindingFlags.InvokeMethod, null, RRSDK, new object[] { CMD, false });
    		}
    
    		static public void Execute(string CMD, bool Wait)
    		{
    			if (RRSDK == null)
    				return;
    
    			if (_Enabled == false)
    				return;
    
    			objAddType.InvokeMember("Execute", BindingFlags.InvokeMethod, null, RRSDK, new object[] { CMD, Wait });
    		}
    
    		static public string GetInfo(string inf)
    		{
    			if (RRSDK == null)
    				return null;
    
    			return (string)objAddType.InvokeMember("GetInfo", BindingFlags.InvokeMethod, null, RRSDK, new object[] { inf, "" });
    		}
    
    		static public string GetInfo(string inf, string FMT)
    		{
    			if (RRSDK == null)
    				return null;
    
    			if (_Enabled == false)
    				return null;
    
    			return (string)objAddType.InvokeMember("GetInfo", BindingFlags.InvokeMethod, null, RRSDK, new object[] { inf, FMT });
    		}
    
    		static public string GetInd(string ind)
    		{
    			if (RRSDK == null)
    				return null;
    
    			if (_Enabled == false)
    				return null;
    
    			return (string)objAddType.InvokeMember("GetInd", BindingFlags.InvokeMethod, null, RRSDK, new object[] { ind, "" });
    		}
    
    		static public string GetInd(string ind, string SCR)
    		{
    			if (RRSDK == null)
    				return null;
    
    			if (_Enabled == false)
    				return null;
    
    			return (string)objAddType.InvokeMember("GetInd", BindingFlags.InvokeMethod, null, RRSDK, new object[] { ind, SCR });
    		}
    
    		static public void ErrScrn(string Title, string Subject, string Message, int Timeout)
    		{
    			if (RRSDK == null)
    				return;
    
    			if (_Enabled == false)
    				return;
    
    			objAddType.InvokeMember("ErrScrn", BindingFlags.InvokeMethod, null, RRSDK, new object[] { Title, Subject, Message, Timeout });
    		}
    
    		static public void ErrScrn(string Title, string Subject, string Message)
    		{
    			SDK.ErrScrn(Title, Subject, Message, (int)-1);
    		}
    	}
    	#endregion
    }
    As you can see, that approach is recommended by @guino in his documents.

    Question 1

    What is not clear however, where is the example skin for the plugin and how to install it?
    I understand what this part of code does, but how to hook it up to a skin?
    Code:
    public int ProcessCommand(string CMD, object frm)
    		{
    			int result = 0;
    	
    			switch (CMD.ToLower())
    			{
    				case "boo":
    					SDK.Execute("PlaySound;scary.wav");
    					break;
    
    				case "yeah":
    					SDK.ErrScrn("title", "subject", "error details");
    					break;

    Question 2

    Is there any plugin example of actually drawing (painting) into the Plugin area on paintevent ?

    Question 3

    What commands can be used to Suspend multimedia playback and bring the plugin up by device event and than resume and hide Parking Asistance plugin?

    I suspect that I wont be able to accomplish all those tasks without help from RR authors, so thanks for your help guys.
    Will contract for C++/Win-Linux/PIC jobs

  6. #6
    MySQL Error
    Auto Apps:loading...

    Join Date
    Oct 2004
    Posts
    5,266
    fyi i see ur a CF guy, RR is not like CF

    RRExtension : ParkingAssistant.USBDevice, ParkingAssistant.IRRExtension

    might not work

    leave as
    RRExtension : ParkingAssistant.IRRExtension

    and USBDevice class should be static
    and just use it from the rrextension class

    USBDevice.pa_init()
    -Thanks
    Mitch
    www.rush2112.net

    "Did you test it in carwings??"

    Sun, Come shine my way
    May healing waters bury all my pain
    Wind, Carry me home
    The fabric of reality is tearing apart
    The piece of me that died
    Will return To live again

Similar Threads

  1. Migrating from Audi Concert to CarPC, which harness?
    By Kent_AudiA4 in forum Car Audio
    Replies: 2
    Last Post: 05-14-2011, 10:03 AM
  2. poi approach - before buying it
    By upspace in forum Centrafuse
    Replies: 1
    Last Post: 07-23-2008, 06:48 AM
  3. Has anybody tried this approach for cooling...
    By AcidPunch in forum General MP3Car Discussion
    Replies: 7
    Last Post: 07-14-2008, 07:00 PM
  4. Migrating EPIA boards
    By tmar89 in forum General Hardware Discussion
    Replies: 4
    Last Post: 09-22-2006, 09:19 AM
  5. Let's see what you guy's think of this novel approach...
    By Genesisfactor in forum General MP3Car Discussion
    Replies: 2
    Last Post: 02-10-2006, 05:43 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •