Announcement

Collapse
No announcement yet.

Best approach for migrating an app to became a plugin

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • 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
    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

    Originally posted by guino
    This basically uses the SendMessage Windows API call with the WM_COPYDATA inteface to exchange messages between applications
    Last edited by Enforcer; 05-16-2011, 08:52 AM.

    Comment


    • #3
      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 Files
      Last edited by novorado; 05-17-2011, 04:56 AM.
      Will contract for C++/Win-Linux/PIC jobs

      Comment


      • #5
        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

        Comment


        • #6
          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

          Comment

          Working...
          X