Thread: Continuous refresh

  1. #1
    Registered User
    Join Date
    Jul 2005
    Posts
    64

    Continuous refresh

    Hello.

    I am working on a robot which is somehow controlled by the mouse. I was forced to turn to Windows programming, which now I am really beginning to take a liking to. Anyway, I have written a program. I will include everything, only for completeness.

    Code:
    #include <windows.h>
    #include <string.h>
    #include <stdio.h>
    #include "Clock3.h"
    
    #define SamplingTime  20    //in milliseconds; ideally, it should be 20 ms
    
    #define KP   1
    #define KI   1
    #define KD   1
    
    #define DATAPORT 0x378
    #define CONTROLPORT 0x37a
    
    
    LRESULT CALLBACK WindowFunc(HWND, UINT, WPARAM, LPARAM);  //Callback function prototype
    
    //Main program:
    int WINAPI WinMain(HINSTANCE hThisInst, HINSTANCE hPrevInst, 
                       LPSTR lpszArgs, int nWinMode)
    {
      char szWinName[] = "MyWin"; /* name of window class */
      HWND hwnd;
      MSG msg;
      WNDCLASSEX wcl;
      
      /* Define a window class. */
      wcl.cbSize = sizeof(WNDCLASSEX); 
    
      wcl.hInstance = hThisInst; /* handle to this instance */
      wcl.lpszClassName = szWinName; /* window class name */
      wcl.lpfnWndProc = WindowFunc; /* window function */
      wcl.style = 0; /* default style */
    
      wcl.hIcon = LoadIcon(NULL, IDI_APPLICATION); /* standard icon */
      wcl.hIconSm = LoadIcon(NULL, IDI_WINLOGO); /* small icon */
      wcl.hCursor = LoadCursor(NULL, IDC_ARROW); /* cursor style */
    
      wcl.lpszMenuName = NULL; /* no main menu */
      wcl.cbClsExtra = 0; /* no extra */
      wcl.cbWndExtra = 0; /* information needed */
    
      /* Make the window white. */
      wcl.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH); 
    
      /* Register the window class. */
      if(!RegisterClassEx(&wcl)) return 0;
    
      /* Now that a window class has been registered, a window
         can be created. */
      hwnd = CreateWindow(
        szWinName, /* name of window class */
        "Processing Mouse Messages", /* title */
        WS_OVERLAPPEDWINDOW, /* window style - normal */
        CW_USEDEFAULT, /* X coordinate - let Windows decide */
        CW_USEDEFAULT, /* Y coordinate - let Windows decide */
        CW_USEDEFAULT, /* width - let Windows decide */
        CW_USEDEFAULT, /* height - let Windows decide */
        HWND_DESKTOP, /* no parent window */
        NULL, /* no menu */
        hThisInst, /* handle of this instance of the program */
        NULL /* no additional arguments */
      );
    
      /* Display the window. */
      ShowWindow(hwnd, nWinMode);
      UpdateWindow(hwnd);
    
      /* Create the message loop. */
      while(GetMessage(&msg, NULL, 0, 0))
      {
        TranslateMessage(&msg); /* translate keyboard messages */
        DispatchMessage(&msg); /* return control to Windows 98 */
      }
      return msg.wParam;
    }
    
    /* This function is called by Windows 98 and is passed 
       messages from the message queue.
    */
    LRESULT CALLBACK WindowFunc(HWND hwnd, UINT message,
                                WPARAM wParam, LPARAM lParam)
    {
      HDC hdc;
      static char str[255] = "", key; /* holds output string */
      static char *clr = "                                                                                  ";
      static BOOL greenlight = 0;	//static variables are initialized only once
      static BOOL delta_t;
      static LONG xref, i=1;
      static LONG x[3];
      static short move[4]={5,6,10,9};	// %0101 -> %0110 -> %1010 -> %1001, just like the website
    
      static Clock timer, clock;
        typedef UINT (CALLBACK* LPFNDLLFUNC1)(INT,INT);
        typedef UINT (CALLBACK* LPFNDLLFUNC2)(INT); 
            HINSTANCE hDLL; // Handle to DLL 
            LPFNDLLFUNC1 Output; // Function pointer 
            LPFNDLLFUNC2 Input; // Function pointer 
            INT Addr; 
            INT AddrIn; 
            INT Value; 
            hDLL = LoadLibrary("Inpout32"); 
            if (hDLL != NULL)
            { 
              Output = (LPFNDLLFUNC1)GetProcAddress(hDLL,"Out32"); 
              Input = (LPFNDLLFUNC2)GetProcAddress(hDLL,"Inp32"); 
              if (!Output || !Input) 
              { 
                // handle the error FreeLibrary(hDLL); 
              } 
            } 
            Addr = 0x378; 
            AddrIn = 0x379; 
            Value = 0; 
            Output(Addr, Value); 
            INT somenum = Input(Addr);
           /* end of motor stuff */
    
      switch(message) {
    
      case WM_CHAR:
    	  hdc = GetDC(hwnd);
    	  switch(wParam)
    	  {
    	    case 'r': case 'R':			//Pressing 'r' or 'R' sets reference point, resets timer
    			greenlight = 1;
    			timer.reset();
    			xref=x[2];
    			x[1]=0;
    			TextOut(hdc, 10, 400, clr, strlen(clr));
    			sprintf(str, "xref = %d", xref);
    			TextOut(hdc, 10, 400, str, strlen(str));
    			Output(CONTROLPORT,0); //set the mode of LPT1 to write mode
    			break;
    		case 's': case 'S':			//Pressing 's' or 'S' halts all operations
    			greenlight = 0;
    			Output(DATAPORT,0);
    			break;
    		case 'q': case 'Q':
    			PostQuitMessage(0);
    			ReleaseDC(hwnd, hdc);
    		default:
    			greenlight = greenlight;
    	  }
    	  ReleaseDC(hwnd, hdc);
    	  break;
    
    
        case WM_RBUTTONDOWN: // Clicking right mouse button clears some data
          hdc = GetDC(hwnd);
    	  TextOut(hdc, 10, 100, clr, strlen(clr));
    	  TextOut(hdc, 10, 200, clr, strlen(clr));
    	  TextOut(hdc, 10, 230, clr, strlen(clr));
    	  TextOut(hdc, 100, 400, clr, strlen(clr));
          ReleaseDC(hwnd, hdc);
          break;
    
        
    	case WM_LBUTTONDOWN: // Clicking left mouse button closes the window (terminates operations)
          hdc = GetDC(hwnd);
    	  PostQuitMessage(0);
          ReleaseDC(hwnd, hdc);
          break;
    
    	
    	case WM_MOUSEMOVE:  // Processing pointer motion
    	  hdc = GetDC(hwnd);
    	  if (greenlight == 1)
    	  {
    		  /* Just Displaying */
    		  TextOut(hdc, 10, 50, clr, strlen(clr));
    		  sprintf(str, "Time passed is %f seconds", (float)timer.time()/1000);
    		  TextOut(hdc, 10, 50, str, strlen(str));
    		  
    		  /* Sampling begins here */
    		  if (timer.sample(SamplingTime))
    		  {
    			BOOL delta_t=(long)timer+SamplingTime;
    			x[0]=x[1];
    			x[1]=LOWORD(lParam)-xref;
    			//theta
    
    			TextOut(hdc, 10, 200, clr, strlen(clr));
    			sprintf(str, "x[0] = %d", x[0]);
    			TextOut(hdc, 100, 200, str, strlen(str));
    			TextOut(hdc, 10, 230, clr, strlen(clr));
    			sprintf(str, "x[1] = %d", x[1]);
    			TextOut(hdc, 100, 230, str, strlen(str));
    
    			TextOut(hdc, 100, 400, clr, strlen(clr));
    			sprintf(str, "%d", delta_t);
    			TextOut(hdc, 100, 400, str, strlen(str));
    			TextOut(hdc, 10, 100, clr, strlen(clr));
    			sprintf(str, "The angular velocity is %f pixels/sec", (float)(x[1]-x[0])/delta_t*1000);
    			TextOut(hdc, 10, 100, str, strlen(str));
    			//theta_dot
    
    			/* won't work here because it will only enter here if you move the mouse */
    			clock.reset();
    			if (LOWORD(lParam)-xref > 0)
    			{ /* move motor clockwise */	}
    
    			if (LOWORD(lParam)-xref < 0)
    			{/* move motor counter-clockwise */}
    		  }
    	  }
    	  x[2]=LOWORD(lParam);		//Set x-coordinate of reference point
    	  TextOut(hdc, 10, 10, clr, strlen(clr));
    	  sprintf(str, "Mouse coordinates are at (%d, %d)", LOWORD(lParam), HIWORD(lParam));
    	  TextOut(hdc, 10, 10, str, strlen(str));
    
    	  /* Calculating the desired force (PID) */
    		//float F_desired = KP*(0-theta) + KD*theta_dot + KI*
    
    	  /* Motor commands corresponding to F_desired go here */
    
    	  ReleaseDC(hwnd,hdc);
    	  break;
    
    
        case WM_DESTROY: // Terminate the program
    	  PostQuitMessage(0);
          break;
    
    
        default:
    	   /* Let Windows 98 process any messages not specified in
             the preceding switch statement. */
          return DefWindowProc(hwnd, message, wParam, lParam);
      }
      return 0;
    }
    Here is the code for Clock.h:

    Code:
    MMRESULT begin = timeBeginPeriod(1);
    MMRESULT end = timeEndPeriod(2);
    
    #define ERR 10 /* Be careful!! You don't want this to be too fast OR TOO SLOW!! */
    
    class Clock
    {
    	private:
    		long timestarted, center;		//time started (in seconds)
    		bool obtainedOneSample;
    	public:
    		Clock();
    		bool sample(const short&);
    		VOID reset();
    		VOID wait(const long&);		//wait a certain number of seconds
    		long time();					//return the time in seconds since last reset
    		operator long();
    };
    
    Clock::Clock()
    {
    	(*this).reset();
    	obtainedOneSample = 0;
    }
    
    VOID Clock::reset()
    {
    	timestarted = timeGetTime();
    	obtainedOneSample = 0;
    	return;
    }
    
    long Clock::time()
    {
    	return timeGetTime()-timestarted;  //return time elapsed in seconds
    }
    
    VOID Clock::wait(const long &tsec)
    {
    	UINT beginning = timeGetTime();
    	while ((beginning + tsec) > timeGetTime())
    	{ /* wait */}
    	return;
    }
    
    bool Clock::sample(const short &msec)
    {
    	long a=time()%msec;		//center = remainder
    
    	if ((a >= 0 && a <= ERR) && obtainedOneSample==false)
    	{
    		obtainedOneSample=true;
    		center=a;
    		return true;
    	}
    
    	if (a > ERR)
    		obtainedOneSample=false;
    
    	return false;
    }
    
    Clock::operator long()
    {
    	return center;
    }
    My question is the following: is there no way to make the motor turn continuously as long as the displacement of the mouse position on the cursor is non-zero? What I have here does not work because the motor moves only when the mouse cursor changes (and I understand why). I am not concerned with the commands here; I have everything. I am just wondering WHERE to put them so that I get what I want. I doubt it is possible, but if you can find a way around it, please let me know. Thanks a million.

    --Bill

  2. #2
    Registered User
    Join Date
    Jul 2005
    Posts
    64
    Sorry I forgot to mention that the "move motor" comments move the motor only in steps; they need to be placed in a loop for the motor to turn continuously.

    Also, I tried to place them in several areas with no success: I tried to put them in the "default" case and after the GetMessage in WinMain. I know that does not suit my purpose because the motor then only moves when a message is received, which is not what I want. (Perhaps I need to add a case for a message which is always being sent to Windows?)

    Thanks again.

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Why do you need a clock, when you only get mouse-move events when the mouse is moving?

    Or perhaps a better question, what do you want the robot to do when the user isn't doing anything?

  4. #4
    Registered User
    Join Date
    Jul 2005
    Posts
    64
    Thanks for your reply. The clock is just a mechanism used to control the speed of the motor through a delay.

    When the user is not doing anything, what the robot does depends on the position of the mouse on the screen. Pressing 'r' sets the reference point at the current pointer location. Anything to the right of that point is positive, implying the motor turning in a certain direction. Anything to the left of that point should cause the motor to turn in the opposite direction. The robot (or motor) should stop moving when the user replaces the pointer at the reference location (only the x-coordinates are taken into account).

    Thanks again.

    --Bill

  5. #5
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Code:
    hDLL = LoadLibrary("Inpout32"); 
            if (hDLL != NULL)
            { 
              Output = (LPFNDLLFUNC1)GetProcAddress(hDLL,"Out32"); 
              Input = (LPFNDLLFUNC2)GetProcAddress(hDLL,"Inp32"); 
              if (!Output || !Input) 
              { 
                // handle the error FreeLibrary(hDLL); 
              } 
            }
    This is code that only needs to be called once. You are calling it hundreds of times every second.

    If you want your code to execute all the time (not just when the mouse moves), then use a timer. Call SetTimer(), and set the delay to something like 200ms. This should be enough to give you pretty continuous motion with the moter. Another option would be to use PeekMessage() in the message pump, and execute your code whenever there isn't a message to process. I suggest against this though because it would consume too much processor time.

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Perhaps use a WM_TIMER message to get windows to send you a new tick periodically.

  7. #7
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Perhaps use a WM_TIMER message to get windows to send you a new tick periodically.
    Which is generated by a call to SetTimer.

  8. #8
    Registered User
    Join Date
    Jul 2005
    Posts
    64
    So I would do something like

    case WM_TIMER:
    /* move motor */
    break;

    ?

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Yes, something like that.
    Every WM_TIMER, examine the current motor position and the desired motor position, and if there's enough of a difference, then move it a bit in the right direction.

  10. #10
    Registered User
    Join Date
    Jul 2005
    Posts
    64
    Excellent. I'll try it now. But where exactly do I put the SetTimer() function? Is it before WinMain()?

  11. #11
    Registered User
    Join Date
    Sep 2004
    Location
    California
    Posts
    3,268
    Call SetTimer() after you've done all your initialization code. Here is a simple example on how to use the function:

    Code:
    #include <windows.h>
    #include <stdio.h>
    
    VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent,DWORD dwTime)
    {
    	printf("timer expired\n");
    }
    
    int main(void)
    {
    	MSG Msg;
    
    	/* Set up the timer to go off every second */
    	SetTimer(NULL,0,1000,TimerProc);
    
    	/* Process all messages */
    	while(GetMessage(&Msg, NULL, 0, 0) > 0)
    	{
    		TranslateMessage(&Msg);
    		DispatchMessage(&Msg);
    	}
    	return 0;
    }
    This code doesn't use the WM_TIMER message at all, instead it uses a callback function. If you want to use the WM_TIMER message instead of a callback, then do:
    Code:
    SetTimer(hwnd,0,1000,NULL);

  12. #12
    Registered User
    Join Date
    Jul 2005
    Posts
    64
    IT WORKED!!!! I thank you guys infinitely.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Force Desktop Refresh?
    By Cat in forum C# Programming
    Replies: 3
    Last Post: 09-06-2008, 10:51 AM
  2. Refresh exporer based displays
    By Yarin in forum Windows Programming
    Replies: 5
    Last Post: 08-19-2008, 08:34 PM
  3. ListView Refresh, Update
    By de4th in forum C++ Programming
    Replies: 1
    Last Post: 12-23-2006, 09:13 AM
  4. Monitor Refresh Rates
    By SlyMaelstrom in forum Tech Board
    Replies: 4
    Last Post: 05-24-2006, 01:08 PM
  5. curses problem
    By rajesh23 in forum Linux Programming
    Replies: 2
    Last Post: 10-07-2003, 07:27 AM