Solved

How can data resulting from checksum exceptions in VC++ /NET be ignored

Posted on 2004-08-13
41
247 Views
Last Modified: 2010-04-24
Occasionally, when communicating with an external device the incoming data is corrupted and a checksum exception occurs. I'd like to ignore such data. What is the best way to do that?
0
Comment
Question by:judico
  • 23
  • 18
41 Comments
 
LVL 19

Expert Comment

by:drichards
ID: 11795675
When checksum error occurs, set the data value to a well-known value outside the normal range and then ignore all data with that well-known value.
0
 

Author Comment

by:judico
ID: 11795849
drichards,

I tried to do all you advise me to do in:

http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VisualC_PLUS_PLUS_DOT_NET/Q_21092168.html

1) In MultiMeter.cpp I replaced return 0.0; with

return System::Double::MaxValue;

2) in temperature.h I placed if-else selection statement in the OnTimeEvent function:


private:
            void OnTimedEvent(Object* source, System::Timers::ElapsedEventArgs* e)
                  {
         try
            {
                        BYTE *pBuf = NULL;
                    dMeterReading = mmeter->ReadData();
                        
                              if ( dMeterReading == System::Double::MaxValue)
                                    ;
                              else

                        evtCounter += 1;
                        
                        yVALUE[ evtCounter ] = dMeterReading;
                        Invalidate();
                textBox2->Text = System::Convert::ToString(dMeterReading);
                        
                        xVALUE[ evtCounter ] = evtCounter;
                textBox1->Text = System::Convert::ToString(evtCounter,10);
            
                        // Restart timer
                aTimer->Start();
            }
            catch (System::Exception *ex)
            {
                System::Console::WriteLine(ex->Message);
            }  
        }


but these changes still don’t ignore the faulty data from being plotted. Maybe there is something more I should do because I don’t understand very well all points in your instruction:

1) Set dMeterReading to System::Double::MaxValue on error and check this value on return
2)  Set an error flag in multimeter and read it after getting dMeterReading
3) Add a pointer parameter to the read function and pass a pointer to a value that will accept an error code
4) Have the read function return error status and pass dMeterReading to the read function as a pointer.
0
 

Author Comment

by:judico
ID: 11796246
I applied a palliative solution. Just avoing plotting a point that's zero:

 for (int iii = 1; iii <= 500; iii++)
                         {
                              if ( yVALUE[ iii ]  == 0)
                                    
                                            ;
                              
                                       else
                  
               graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
                        }      
0
 
LVL 19

Expert Comment

by:drichards
ID: 11796540
Like this:

private:
          void OnTimedEvent(Object* source, System::Timers::ElapsedEventArgs* e)
               {
         try
            {
                    BYTE *pBuf = NULL;
                  dMeterReading = mmeter->ReadData();
                   
                         if ( dMeterReading == System::Double::MaxValue) {}
                         else
                         {
                             evtCounter += 1;
                             yVALUE[ evtCounter ] = dMeterReading;
                             Invalidate();
                             textBox2->Text = System::Convert::ToString(dMeterReading);
               
                             xVALUE[ evtCounter ] = evtCounter;
                             textBox1->Text = System::Convert::ToString(evtCounter,10);
                          }
                    // Restart timer
                aTimer->Start();
            }
            catch (System::Exception *ex)
            {
                System::Console::WriteLine(ex->Message);
            }  
        }
0
 
LVL 19

Expert Comment

by:drichards
ID: 11796633
Initially when the window paints it will paint before the initial value has even been read.  The value will be 0 at that time.  You should probably initialize evtCounter to -1 in the constructor and don't plot if evtCounter < 0.  That way you won't plot anything until you've read a data point.  Also, as your code sits (will be OK with initial evtCounter value of -1) you increment evtCounter BEFORE loading the values into the arrays, so you are skipping the 0 index of the array.  You never load a value into the 0 index.

    void OnPaint( PaintEventArgs *paintEvent )    
      {
         if ( evtCounter >= 0 )
         {
            // call base OnPaint method
            __super::OnPaint( paintEvent );
         
            // get graphics object
            Graphics *graphicsObject = paintEvent->Graphics;
            SolidBrush *brush = new SolidBrush( Color::Blue );
            Pen *pen = new Pen( Color::Black );

            for ( int ii = 0; ii <= evtCOunter; ii++)
            {
                graphicsObject->DrawEllipse( pen,xVALUE[ii], yValue[ii] * 10, 7, 7 );
            }
         }
    }

Also, in previous post, you should check if evtCounter is 500 (your array size, I assume) and reset it to 0 so you don't do off the array.
0
 

Author Comment

by:judico
ID: 11797321
Still plots the zero point. After your advice I placed evtCounter = -1 in the constructor:

temperature(void)
            {
                  InitializeComponent();
                  evtCounter = -1;
            }


and then placed an if-else selection statement where the plotting occurs


if (evtCounter < 0 ) {}
                              else
                              {
                                                graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
                              }

bit, as I said, this doesn't remove the zero point.
0
 

Author Comment

by:judico
ID: 11797393
See, it works with the palliative solution I mentioned before but I prefer it to work the way you explained it, with the flag.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11797504
If you're still looping from 0 to 499, you're going to get lots of zeros because the data is not yet filled in.

Also, if there are 0 values in positions less than evtCounter, do they come from the data read from the meter?  Check the return value for debug purposes.  Before checking if dMeterReading is MaxValue, check if it's 0.  If you see the dialog box, you know that the meter reading was 0.  If the zeros are coming from somewhere else, it's because you are not manipulating the array correctly.

Test code to see if meter reads 0:

private:
          void OnTimedEvent(Object* source, System::Timers::ElapsedEventArgs* e)
               {
         try
            {
                    BYTE *pBuf = NULL;
                  dMeterReading = mmeter->ReadData();
                   
                         // Code for debugging
                         if ( dMeterreading == 0 ) System::Windows::Forms::MessageBox(S"dMeterReading is 0!");

                         if ( dMeterReading == System::Double::MaxValue) {}
                         else
                         {
                             evtCounter += 1;
                             yVALUE[ evtCounter ] = dMeterReading;
                             Invalidate();
                             textBox2->Text = System::Convert::ToString(dMeterReading);
               
                             xVALUE[ evtCounter ] = evtCounter;
                             textBox1->Text = System::Convert::ToString(evtCounter,10);
                          }
                    // Restart timer
                aTimer->Start();
            }
            catch (System::Exception *ex)
            {
                System::Console::WriteLine(ex->Message);
            }  
        }
0
 

Author Comment

by:judico
ID: 11797571
For some reason

if ( dMeterReading == 0 ) System::Windows::Forms::MessageBox(S"dMeterReading is 0!");

gives the error

temperature.h(154): error C2440: 'type cast' : cannot convert from 'System::String __gc *' to 'System::Windows::Forms::MessageBox'

and I can't do the debuggigng.
0
 

Author Comment

by:judico
ID: 11797589
OK, it should be

if ( dMeterReading == 0 ) System::Windows::Forms::MessageBox::Show(S"dMeterReading is 0!");
0
 

Author Comment

by:judico
ID: 11797622
No, the debugging shows that the zero value isn't coming from the multimeter and is due to what you already suggested -- the first time the form paints it paints with zero values because the program hasn't yet called the multimeter. The flag -1 should be put before that first painting. I tried placing it in temperature.cpp:

System::Threading::Thread::CurrentThread->ApartmentState = System::Threading::ApartmentState::STA;
      evtCounter = -1;

      Application::Run(new temperature());
      return 0;

declaring static int evtCounter; at the head of temperature.h but it didnt help as well.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798049
It's probably because you have this code which resets evtCOnter to 0 after the program starts.:

private: System::Void timer1_Tick(System::Object *  sender, System::EventArgs *  e)
           {
  if ( mmeter == NULL )
                    {
            timer1->Stop();
            mmeter = new MultiMeter;
            mmeter->ConfigureSerialInterface();
            aTimer = new System::Timers::Timer(500);
            aTimer->Elapsed+=new System::Timers::ElapsedEventHandler(this, OnTimedEvent);
            // Only raise the event the first time Interval elapses.
            aTimer->AutoReset = false;
            aTimer->Enabled = true;
            evtCounter = 0;   // <----------------Problem here
                    }
           }


};
0
 

Author Comment

by:judico
ID: 11798095
I changed that line to evtCounter = -1; but the problem persists. Somehow, the first time the OnPaint method is invoked the values of xVALUE and yVALUE are zero because the multimeter hasn't been called yet. Can't this first invoking of the OnPaint method be overridden somehow?
0
 

Author Comment

by:judico
ID: 11798125
Can't the first values of xVALUE and yVALUE be obtained in the constructor before initializing the component?
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798127
If the multimeter read hasn't been called yet, how is evtCOunter changing from -1 to 0 since the only place that is supposed to happen is in the timer method where the read happens?  I'd put a break in the constructor and set a watch on evtCOunter and see when it gets changed.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798148
They could as long as you've initialized the multimeter class so the serial port is open.
0
 

Author Comment

by:judico
ID: 11798183
Yeah, that's logical. I don't know how to set a watch on evtCounter but I did the following -- I set breaks in the constructor:

temperature(void)

and in the line where evtCounter changes:

evtCounter += 1;

and I saw the following:



When F11 is depressed, after certain waiting period, the program goes to temperature.cpp, as expected:

System::Threading::Thread::CurrentThread->ApartmentState = System::Threading::ApartmentState::STA;

then

Application::Run(new temperature());

after which gets into temperature.h into the constructor:

temperature(void)

followed by

InitializeComponent();

and then goes through the whole list of the initialization parameters, untill it reaches the end of the constructor. Then, back to temperature.cpp

Application::Run(new temperature());

And now, the most interesting -- the form appears on the screen momentarily, then disappears, and the program reaches:

evtCounter += 1;

Thus, it appears that evtCounter gets changed only after one painting of the form has already occurred.




0
 

Author Comment

by:judico
ID: 11798185
How can this first painting of the form be gotten rid of?
0
 

Author Comment

by:judico
ID: 11798234
Something else ... Insertion of another breakpoint in the line

 evtCounter = -1;

showed that above assignment of -1 to evtCounter occurs only after the first painting of the form.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798239
You can't get rid of first painting.  When the form is rendered, it needds to paint.  Anytime the form is uncovered, unminimized, or moved (or first shown) it will do OnPaint to render the form surface.

When you say

>> And now, the most interesting -- the form appears on the screen momentarily, then disappears, and the program reaches:

>> evtCounter += 1;

What method is that in?  The only place that line should appear is in the timer callback where you are reading the meter.  That, combined with the "if ( evtCounter >= 0 ) ..." in OnPaint should prevent plotting data until the meter has been read at least once.


0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 19

Expert Comment

by:drichards
ID: 11798246
The form has to be constructed before it is painted, so where is the "evtCounter = -1;" that happens after the first painting?  Perhaps you should post the whole code again so I can see what's going on.  My version works perfectly except that I have a random number generator in place of the meter - or should I just post mine so you can look at it?
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798297
Compare this to what you have...

    public __gc class temperature : public System::Windows::Forms::Form
    {    
    public:
        temperature(void)
        {
            InitializeComponent();
            evtCounter = -1;
            xValues = new int __gc[500];
            yValues = new double __gc[500];
            rnd = new Random();
            mmeter = new MultiMeter;
            mmeter->ConfigureSerialInterface(1);
            aTimer = new System::Timers::Timer(500);
            aTimer->Elapsed+=new System::Timers::ElapsedEventHandler(this, OnTimedEvent);
            aTimer->AutoReset = false;  // Don't automatically restart timer
            aTimer->Enabled = true;
        }
 
    protected:
        void Dispose(Boolean disposing)
        {
            if (disposing && components)
            {
                        components->Dispose();
            }
            __super::Dispose(disposing);
        }

    private: System::Windows::Forms::TextBox *  textBox1;

    private: System::Windows::Forms::TextBox *  textBox2;
    private: System::Windows::Forms::TextBox *  textBox3;
    private: System::ComponentModel::IContainer *  components;

    private:
        System::Timers::Timer *aTimer;
        double yValues __gc[];
        int xValues __gc[];
        int evtCounter;
        System::Random *rnd;
        MultiMeter *mmeter;
     
    private:
            /// <summary>
        /// Required designer variable.
        /// </summary>


        /// <summary>
        /// Required method for Designer support - do not modify
        /// the contents of this method with the code editor.
        /// </summary>
        void InitializeComponent(void)
          {
                    this->textBox1 = new System::Windows::Forms::TextBox();
                    this->textBox2 = new System::Windows::Forms::TextBox();
                    this->textBox3 = new System::Windows::Forms::TextBox();
                    this->SuspendLayout();
                    //
                    // textBox1
                    //
                    this->textBox1->Location = System::Drawing::Point(520, 8);
                    this->textBox1->Name = S"textBox1";
                    this->textBox1->ReadOnly = true;
                    this->textBox1->TabIndex = 3;
                    this->textBox1->Text = S"";
                    this->textBox1->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                    //
                    // textBox2
                    //
                    this->textBox2->Location = System::Drawing::Point(520, 48);
                    this->textBox2->Multiline = true;
                    this->textBox2->Name = S"textBox2";
                    this->textBox2->ReadOnly = true;
                    this->textBox2->Size = System::Drawing::Size(104, 24);
                    this->textBox2->TabIndex = 4;
                    this->textBox2->Text = S"";
                    this->textBox2->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                    //
                    // textBox3
                    //
                    this->textBox3->Location = System::Drawing::Point(520, 136);
                    this->textBox3->Multiline = true;
                    this->textBox3->Name = S"textBox3";
                    this->textBox3->ReadOnly = true;
                    this->textBox3->Size = System::Drawing::Size(104, 24);
                    this->textBox3->TabIndex = 5;
                    this->textBox3->Text = S"";
                    this->textBox3->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                    //
                    // temperature
                    //
                    this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
                    this->ClientSize = System::Drawing::Size(632, 466);
                    this->Controls->Add(this->textBox3);
                    this->Controls->Add(this->textBox2);
                    this->Controls->Add(this->textBox1);
                    this->Name = S"temperature";
                    this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
                    this->Text = S"Form1";
                    this->ResumeLayout(false);

              }    
   
    private:
        void OnTimedEvent(Object* source, System::Timers::ElapsedEventArgs* e)
        {
            try
            {
                evtCounter += 1;
                textBox1->Text = System::Convert::ToString(evtCounter,10);

                BYTE *pBuf = NULL;
                //double dMeterReading = mmeter->ReadData();
                double  dMeterReading = rnd->NextDouble()*200.0 + 100;
                xValues[evtCounter] = evtCounter+20;
                yValues[evtCounter] = dMeterReading;
                textBox2->Text = System::Convert::ToString(dMeterReading);
                // Restart timer
                this->Invalidate();
                aTimer->Start();
            }
            catch (System::Exception *ex)
            {
                System::Console::WriteLine(ex->Message);
            }  
        }

    protected:
        void OnPaint( PaintEventArgs *paintEvent )    
        {
            // call base OnPaint method
            __super::OnPaint( paintEvent );
            if ( evtCounter >= 0 )
            {
                // get graphics object
                Graphics *graphicsObject = paintEvent->Graphics;
                SolidBrush *brush = new SolidBrush( Color::Blue );
                Pen *pen = new Pen( Color::Black );
      
                for ( int ii = 0; ii <= evtCounter; ii++ )
                {
                    graphicsObject->DrawEllipse( pen,xValues[ii], yValues[ii], 7, 7 );
                }
            }
        }
};
0
 

Author Comment

by:judico
ID: 11798313
Let me first mention this, before posting the code. I again inserted evtCounter = -1; (evtCounter being declared globally) in temperature.cpp just above Application::Run(new temperature());, so that I can be sure that evtCounter will be initialized with value -1 before anything else, especially before the form is initialized. Now, having done that I took it for granted that first time drawing of the ellipse would not occur because I had the following:

for (int iii = 1; iii <= 500; iii++)
                         {
                              if (evtCounter == -1 )      
                              {
                              }
                              else
                  graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
                        }

(this 500 is just in this example; I'll take care of it later)

Curiously, the program didn't heed that 'if (evtCounter == -1 )' and performed as if evtCounter had a value different from -1. Thus, something had interfered between the time evtCounter was assigned the value -1 and the moment the program reached for the first time 'if (evtCounter == -1 )'.

I tried placing a breakpoint also in evtCounter += 1; but for some reason depressing F11 never stopped me at that point.       
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798351
I think you've got too many evtCounter's running around.  Do not put it as a global.  Put it in the temperature class and initialize it to  -1 in the constructor.  See the code I just posted.  This is the correct way to handle it.  

The code I posted should be functionally identical to yours except that instead of reading the meter I generate a random number between 100.0 and 300.0.  If you copy it and switch the "double dMeterReading = rnd->NextDouble()..." line with the commented-out lne right above it, it should work.  You will probably need to change the scaling on the plot as well.
0
 

Author Comment

by:judico
ID: 11798400
OK, I was able to compile your above code. However, it still works in a similarly curious way as the code I have. In your code continuous plotting occurs at the very top of the form. In addition to that you have an immobile point at position x = 1 and y somewhere in the tens of form scale units. This second point changes its position along the y-axis as the values coming from the multimeter change, its x-axis position remaining unchanged.

Also, in your code you have placed the timer in the constructor. Let me post what I have. It at least correctly has the point moving in the plane of the form (one thing I'm noticing is the less selection statements there are the fewer instances of faulty data there are). Here is the code I have


#pragma once

#include "MultiMeter.h"

//static int evtCounter;
//static double dMeterReading;

using namespace System;
using namespace System::IO;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;

static int evtCounter = -1;

namespace Q307398
{
      /// <summary>
      /// Summary for Form1
      ///
      /// WARNING: If you change the name of this class, you will need to change the
      ///          'Resource File Name' property for the managed resource compiler tool
      ///          associated with all .resx files this class depends on.  Otherwise,
      ///          the designers will not be able to interact properly with localized
      ///          resources associated with this form.
      /// </summary>
      public __gc class temperature : public System::Windows::Forms::Form
      {      
      public:
            temperature(void)
            {            
                  InitializeComponent();
            }
 
static double xVALUE __gc[] = new double __gc[ 1000 ];
static double yVALUE __gc[] = new double __gc[ 1000 ];

      


      protected:
            void Dispose(Boolean disposing)
            {
                  if (disposing && components)
                  {
                        components->Dispose();
                  }
                  __super::Dispose(disposing);
            }

    private: System::Windows::Forms::TextBox *  textBox1;
    private: System::Timers::Timer* aTimer;
                int evtCounter;
                double dMeterReading;
                MultiMeter *mmeter;
      private: System::Windows::Forms::Timer *  timer1;
      private: System::Windows::Forms::TextBox *  textBox2;
      private: System::Windows::Forms::TextBox *  textBox3;
      private: System::Windows::Forms::TextBox *  textBox4;
      private: System::ComponentModel::IContainer *  components;
      private: System::Windows::Forms::Label *  label1;

      private:
            /// <summary>
            /// Required designer variable.
            /// </summary>


            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            void InitializeComponent(void)
            {
                  this->components = new System::ComponentModel::Container();
                  this->textBox1 = new System::Windows::Forms::TextBox();
                  this->timer1 = new System::Windows::Forms::Timer(this->components);
                  this->textBox2 = new System::Windows::Forms::TextBox();
                  this->textBox3 = new System::Windows::Forms::TextBox();
                  this->textBox4 = new System::Windows::Forms::TextBox();
                  this->label1 = new System::Windows::Forms::Label();
                  this->SuspendLayout();
                  //
                  // textBox1
                  //
                  this->textBox1->Location = System::Drawing::Point(40, 8);
                  this->textBox1->Name = S"textBox1";
                  this->textBox1->ReadOnly = true;
                  this->textBox1->Size = System::Drawing::Size(104, 20);
                  this->textBox1->TabIndex = 3;
                  this->textBox1->Text = S"";
                  this->textBox1->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                  //
                  // timer1
                  //
                  this->timer1->Enabled = true;
                  this->timer1->Interval = 500;
                  this->timer1->Tick += new System::EventHandler(this, timer1_Tick);
                  //
                  // textBox2
                  //
                  this->textBox2->Location = System::Drawing::Point(40, 32);
                  this->textBox2->Multiline = true;
                  this->textBox2->Name = S"textBox2";
                  this->textBox2->ReadOnly = true;
                  this->textBox2->Size = System::Drawing::Size(104, 24);
                  this->textBox2->TabIndex = 4;
                  this->textBox2->Text = S"";
                  this->textBox2->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                  //
                  // textBox3
                  //
                  this->textBox3->Location = System::Drawing::Point(296, 32);
                  this->textBox3->Multiline = true;
                  this->textBox3->Name = S"textBox3";
                  this->textBox3->ReadOnly = true;
                  this->textBox3->Size = System::Drawing::Size(104, 24);
                  this->textBox3->TabIndex = 5;
                  this->textBox3->Text = S"";
                  this->textBox3->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                  //
                  // textBox4
                  //
                  this->textBox4->Location = System::Drawing::Point(296, 64);
                  this->textBox4->Multiline = true;
                  this->textBox4->Name = S"textBox4";
                  this->textBox4->ReadOnly = true;
                  this->textBox4->Size = System::Drawing::Size(104, 24);
                  this->textBox4->TabIndex = 6;
                  this->textBox4->Text = S"";
                  this->textBox4->TextAlign = System::Windows::Forms::HorizontalAlignment::Center;
                  //
                  // label1
                  //
                  this->label1->Location = System::Drawing::Point(280, 8);
                  this->label1->Name = S"label1";
                  this->label1->Size = System::Drawing::Size(136, 24);
                  this->label1->TabIndex = 7;
                  this->label1->Text = S"Values passed to OnPaint";
                  //
                  // temperature
                  //
                  this->AutoScaleBaseSize = System::Drawing::Size(5, 13);
                  this->ClientSize = System::Drawing::Size(632, 466);
                  this->Controls->Add(this->label1);
                  this->Controls->Add(this->textBox4);
                  this->Controls->Add(this->textBox3);
                  this->Controls->Add(this->textBox2);
                  this->Controls->Add(this->textBox1);
                  this->Name = S"temperature";
                  this->StartPosition = System::Windows::Forms::FormStartPosition::CenterScreen;
                  this->Text = S"Form1";
                  this->ResumeLayout(false);

            }      


private:
            void OnTimedEvent(Object* source, System::Timers::ElapsedEventArgs* e)
                  {
         try
            {
                        BYTE *pBuf = NULL;
                    dMeterReading = mmeter->ReadData();
                         
                        // Code for debugging
                        if ( dMeterReading == 0 ) System::Windows::Forms::MessageBox::Show(S"dMeterReading is 0!");

   
       if ( dMeterReading == System::Double::MaxValue)
                                 {
                                             }                  
                                     else
                                     {
                                                
                                    evtCounter += 1;
                        
                        yVALUE[ evtCounter ] = dMeterReading;
                        Invalidate();
                textBox2->Text = System::Convert::ToString(dMeterReading);
                        
                        xVALUE[ evtCounter ] = evtCounter;
                textBox1->Text = System::Convert::ToString(evtCounter,10);
                                    }
                        // Restart timer
                aTimer->Start();
            }
            catch (System::Exception *ex)
            {
                System::Console::WriteLine(ex->Message);
            }  
        }




protected:
      void OnPaint( PaintEventArgs *paintEvent )      
      {
            
              // call base OnPaint method
              __super::OnPaint( paintEvent );
         
             // get graphics object
         Graphics *graphicsObject = paintEvent->Graphics;
         SolidBrush *brush = new SolidBrush( Color::Blue );
         Pen *pen = new Pen( Color::Black );
 
             textBox3->Text = System::Convert::ToString(dMeterReading);
             textBox4->Text = System::Convert::ToString(evtCounter);
             
             for (int iii = 1; iii <= 500; iii++)
                         {
                              if (evtCounter == -1 )      
                              {
                              }
                              else
                  graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
                        }
      }
      



private: System::Void timer1_Tick(System::Object *  sender, System::EventArgs *  e)
             {
  if ( mmeter == NULL )
                        {
          timer1->Stop();
            mmeter = new MultiMeter;
            mmeter->ConfigureSerialInterface();
            aTimer = new System::Timers::Timer(500);
            aTimer->Elapsed+=new System::Timers::ElapsedEventHandler(this, OnTimedEvent);
            //// Only raise the event the first time Interval elapses.
            aTimer->AutoReset = false;
            aTimer->Enabled = true;
            evtCounter = -1;
                        }
             }


};
}
:

0
 
LVL 19

Expert Comment

by:drichards
ID: 11798462
Interestingly, that is not at all the behavior my code exhibits on my system here.  I get a nice plot going across the middle of my form (that's why I offset all the y coords by 100).  Like I said, if you switch to use the multimeter readings instead of the random number generator, you'll nned to change the plot scaling.  Did you try it with the random number?

Anyway, the reason you keep getting the evtCounter not -1 in OnPaint is because you did not put the evtCounter=-1 in the constructor as I keep mentioning.  You have it in timer1_tick method which doesn't get called until long (in CPU time) after the form has been painted.  All that code you have in the timer1_tick method beliongs in the constructor right after the call to IntializeComponents.  That's what constructors are for.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798503
I ran your version of the code and made one change - you need to set the xVALUE array BEFORE calling invalidate.  Other than that, except that it's plotting hundreds of points at 0,0 and plots one time before you've even read in any data (see previous post), it seems to work.  Again, I replaced

                  dMeterReading = mmeter->ReadData();
 
with

                  dMeterReading = rnd->NextDouble()*100+50;

What exactly is not right?
0
 

Author Comment

by:judico
ID: 11798504
See, the code above is only one variant of the many ways I tried to place evtCounter = -1;. I placed it in the temperature.cpp, in the constructor, you name it. I just tried again placing it in the constructor -- didn't do any good. The reason, I think, why the code doesn't work is because I don't fully understand the method OnPaint. Somehow, I feel uncomfortable that I have to create sequential events through selection statements. This is one recurrent problem I have  which shows itself here as well.

As for your code, I didn't use any special scaling. I'm using the natural scale of the form and I just replaced the random numbers with the data coming from the multimeter. Let me take a look again.
0
 

Author Comment

by:judico
ID: 11798533
Indeed, the program otherwise works just fine. It is that first point you mention that bothers me. I can't understand how is it that something which is declared to be evtCounter = -1 at the onset later cannot be used as a condition and is ignored.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798537
We seem to be homing in on something here.  Now that I've run your code and it works exactly as I would expect based on what I see, what is your issue?  I've kind of lost that in the shuffle here, but I can probably tell you how to solve it now.
0
 

Author Comment

by:judico
ID: 11798551
See, suppose there is an array of 10 non-zero experimental points to be plotted on the screen. lt will be incorrect if the first of these non-zero points is plotted on the screen (and is saved in a text file) as if it is of zero value.

The way the program works now gives an impression that the first point is always zero. That has to be corrected.
0
 

Author Comment

by:judico
ID: 11798560
Mind you, it may happaen that one of the experimental points is indeed zero, therefore, what I did, writing

 for (int iii = 1; iii <= 500; iii++)
                     {
                         if ( yVALUE[ iii ]  == 0)
                             
                                            ;
                         
                                       else
               
               graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
                    }    

is incorrect in the general case because it will ignore legitimate points of zero value.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798602
>> lt will be incorrect if the first of these non-zero points is plotted on the screen (and is saved in a text file) as if it is of zero value.

True enough, but plotting can be easily fixed by initializing evtCounter properly before OnPaint is called.  Another approach might be to add another variable in the form:

    bool haveData;

initialized to false in the constructor.  Then in OnPaint check "if (haveData)..." instead of "if (evtCounter >= 0)...".  It's basically the same thing but perhaps less confusing.  Then in OnTimedEvent, do "haveData = true;" after reading valid data from the meter.  This is the signal to start plotting.

Also, C++ arrays start at 0.  You should be iterating from 0 to 500, not 1.  If you declare an array ...[n], the valid index values are 0 to n-1.  Also a reminder, your code is plotting 400+ points at 0,0 since you iterate to 500 every time.  You should really stop at evtCounter since that's how many points you have at any moment.
0
 

Author Comment

by:judico
ID: 11798662
I just tried initializing bool haveData as false in the constructor, then having it become true after reading valid data and checking it in the OnPaint with if (haveData ...). Still gives the first point at 0,0 position ... How can this be?

Also,  I don't understand what you mean by saying "your code is plotting 400+ points at 0,0 since you iterate to 500 every time". The code seems to be plotting only one, the first one, point at 0,0 and all other points are plotted at non-zero x and y's.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798754
No, it's not the first one - it's actually evtCounter+1 to 500 that are being plotted right on top of each other at 0,0.  Run the code for a couple of seconds and the set a break in OnPaint.  Step through and you'll see that after the first few ponts which have valid values, all the rest have x and y values of 0.  I think that's what's confusing you.
0
 

Author Comment

by:judico
ID: 11798795
Now, this sounds confusing, indeed. I think it's very important to be clarified and corrected, if that's the case. Otherwise the program will be useless.
0
 
LVL 19

Expert Comment

by:drichards
ID: 11798857
Here's a test you can run to see if things are going as expected (assumes you've changed iteration in OnPaint):

1) Put a breakpoint in OnTimedEvent
2) Put a breakpoint at the start of the "for (iii = 0;..." loop in OnPaint which should be inside the "if (haveData)..." block.
3) Run the program
4) You should hit the OnTimedEvent breakpoint first.  Validate that haveData is set to true.  Step through a few lines if you have to.
5) Continue execution
6) You should hit the OnPaint breakpoint next.
7) Expand xVALUE and yVALUE arrays and validata that yVALUE[0] is non-zero.  xValue[0] will be 0 unless you add an offset like I did in my code.  I wanted to start plotting a little into the form, so I used evtCounter+20 as my xVALUE - my lowest xVALUE was 20.

If you can do that test successfully, then the code is correct.  I think you will find this to be the case.  What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in the array when in fact it is all the unused points at teh end of the array.
0
 

Author Comment

by:judico
ID: 11800692
I tried the test point by point as you asked me to do in your previous post. Unfortunately, I had problems applying it. I set up the breakpoints, as you explained, and then started the program. I don't know, however, what you mean by "Expand xVALUE and yVALUE arrays and validata that yVALUE[0] is non-zero." I don't know how to expand it. Thus, I didn't get too far with that test.

To explore the issue I approached it this way. I added some code which writes the values of xVALUE[ iii ] and yVALUE[ iii ] in a text file named TestFile.txt. The code goes as follows:



if (haveData  ==  false)
                     ;
               else
               {
             for (int iii = 0; iii <= 9; iii++)
                     {
                graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 20, 7, 7 );
                               }                              
               }
      
StreamWriter* pwriter = new StreamWriter( S"c:/AAAAAAVisual C++/TestFile.txt" );
      for ( int jjj = 0; jjj <= 9; jjj++ )
                        {      
                  String *xxx = xVALUE [ jjj ].ToString();
                  String *yyy = yVALUE [ jjj ].ToString();
      
                  String *xxxyyy = String::Concat(xxx, "     ", yyy);
      
                  pwriter->WriteLine( xxxyyy );
                        }
                  pwriter->Close();
        

and this is what I obtain in the text file when I run the program until the counter is increased from 0 to 9::

0     10.71
1     10.71
2     10.72
3     10.73
4     10.73
5     10.73
6     9.84
7     9.65
8     9.17
9     8.46

These are the actual values of xVALUE[ iii ] and yVALUE[ iii ] coming in from the multimeter. They are being plotted on the screen and can be observed (in addition to the misterious point at 0,0 which we seen not to be able to get rid of). As you can see there are no 0,0 couples in these data. That's why I was telling you that I don't understand when you're saying:

"What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in the array when in fact it is all the unused points at teh end of the array."

(I don't know what the term 'teh' means, could you explain, please).

Thus, it seems to me that the whole problem stems from the application of the OnPaint method. It boggles the mind how come one can have have evtCounter assigned to -1 at the onset of the program and yet when the selection statement in the OnPaint method is to obey it, it in fact disregards it. I think that's what is unclear in this problem.
0
 
LVL 19

Accepted Solution

by:
drichards earned 125 total points
ID: 11800925
>> (I don't know what the term 'teh' means, could you explain, please).
It's my fast-typing misspelling of 'the'.

>> That's why I was telling you that I don't understand when you're saying:
>>"What is confusing you is that you are seeing points plotted at 0,0 and you assume that this is the first point in
>>  the array when in fact it is all the unused points at teh end of the array."

Look at the code you posted to me above (repeated here):

           for (int iii = 1; iii <= 500; iii++)
                     {
                         if (evtCounter == -1 )    
                         {
                         }
                         else
               graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 10, 7, 7 );
                    }

You are looping and plotting from 1 to 500 every time despite the fact that the number of data points is only evtCounter.  So on the first pass, for example, you don't even plot the real data which is is yVALUE[0] and you plot 500 zero values.  On second pass you plot one point of real data and 499 zeros, etc.

But moving on...

OK, you plot only the first 10 points and if you sit there and watch it there is still a point plotted at 0?

Since I do not get this mysterious point in my output, I cannot really help you much beyond here.  I ran your code exactly as you posted it and the only anomaly I got was a point at 0 for about half a second because of your incorrect initialization of evtCounter.  As soon as data was "read" from the multimeter, this point went away.  It is up to you to do some debugging to figure out where your odd point comes from.  All I can do is offer a few last debugging tips.

1) To "expand" xVALUE and yVALUE -  go in the Autos windows and find "this".  It will have a + sign.  Click on the + to expand.  Now find 'xVALUE' and 'yVALUE' and click on their + signs to expand.  You can now see all the values.

2) In the plotting loop, put:
    if (yVALUE[iii] == 0) ::DebugBreak();

If you get a dialog with a message like:

    "Unhandled exception at 0x77f75a58 in WinMon.exe: User breakpoint."

hit the Break button on the dialog and look at your arrays and whatever other values are relevant.

If you have additional specific questions, go ahead and ask, but my version of the code works perfectly and I don't know what you're doing differently at this point.
0
 

Author Comment

by:judico
ID: 11801232
OK, here’s the solution of that “mystery”. Believe it or not it consists in changing just one little thing. In the for loop one should have evtCounter instead of 500, namely

for (int iii = 0; iii <= evtCounter; iii++)
                     {
                graphicsObject->DrawEllipse( pen, xVALUE[ iii ], yVALUE[ iii] * 20, 7, 7 );
                               }                              
               }

And it stands to reason. As you explained, the loop containing 500 as a parameter will inevitably loop 500 times every time the OnPaint method is called. This will lead to multiple 0,0 points in the initial stages of the acquisition of the points (in fact, until 500 actual points are acquired). Thus, a “mysterious” 0,0 point will always be seen plotted on the screen as many times as there are zeros (due to still not acquired data) coming from the 500-turn for-loop.

Now, with the above code that 0,0 point is gone because the for-loop turns only as many times as the multimeter has actually been called (accounted for by the value of the evtCounted). Undoubtedly, evtCounter has to be initialized as –1 so that even initially no bogus 0,0 point is seen on the graph.

Now, due to the discussion with you this problem is taken care of. What remains is the checksum problem. Obviously, if one needs to retain the actual number of points taken one mustn’t write code which skips unpleasant points. Probably, correction of the point values should occur somehow manually, after all data has been acquired.

I will open later a special question to discuss that. Now I’m closing this question and would like to thank you so much for the great help.



P.S. Please note, I’m increasing your points to 250. Please let me know if you have problems in getting the increased points.
0
 

Author Comment

by:judico
ID: 11801522
Small correction. To avoid the momentary appearance of the 0,0 point at the beginning the above loop should start from iii = 1:

for (int iii = 1; iii <= evtCounter; iii++)
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
In Easy String Encryption Using CryptoAPI in C++ (http://www.experts-exchange.com/viewArticle.jsp?aid=1193) I described how to encrypt text and recommended that the encrypted text be stored as a series of hexadecimal digits -- because cyphertext may…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now