Using C# Property to convert ‘C’ #define macro

January 24, 2012

Given these two ‘C’ macros to convert to C#:

#define CFG_FILE(dwChoice) ((dwChoice >> 12) & 0x000F)
#define CFG_ELEMENT(dwChoice) (dwChoice & 0x01FF)

The solution I instituted was to create a class containing the results of the two macros. The macros are placed in set accessor of a property with the result being saved in a private variable (to implement data hiding).

using System;
using System.Collections.Generic;
using System.Text;

namespace TestCfgWord
{
    class clsCfgWord
    {
        private uint uiTableType;
        private uint uiTableElement;
        private uint uiCfgWord;

        public uint TableType
        {
            get
            {
                return uiTableType;
            }

            set
            {
                uiTableType = (value >> 12) & 0x000F;
            }

        }

        public uint TableElement
        {
            get
            {
                return uiTableElement;
            }
            set
            {
                uiTableElement = value & 0x01FF;
            }
        }

        public uint CfgWord
        {
            get
            {
                return uiCfgWord;
            }
            set
            {
                uiCfgWord = value;
                TableType = value;
                TableElement = value;
            }
        }
    }
}

To use the CfgWord class:

clsCfgWord CfgWord = new clsCfgWord();

private void cmdXferToStruct_Click(object sender, EventArgs e)
{
    CfgWord.CfgWord = Convert.ToUInt16(mtxtCfgWord.Text);

    txtTableType.Text = CfgWord.TableType.ToString();
    txtTableElement.Text = CfgWord.TableElement.ToString();
}

As an example given a value of CfgWord value of 16422, the Table Table is 4 while the Table Element is 38.

 


Example of youtube censorship

January 18, 2012

Youtube allows shootings, violence, urination on dead bodies, sucking of toes, live births, breast exams, but – if there is a hint of anything sexually suggestive it is banned.

Stop censorship!


Dynamically create an array of strings in C#

November 14, 2011

To dynamically create a string array, do not use string[].  Rather use List <T> as shown in this example:

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestStringArray
{
    class Program
    {
        static void Main(string[] args)
        {
            List<String> arString = new List<string>();

            for (int i=0; i<10; i++)
            {
                int iProduct = i * i;
                arString.Add("Test " + iProduct.ToString());

            }

            foreach (string str in arString)
            {
                Console.WriteLine("String: " + str);
            }

            Console.ReadLine();
        }
    }
}

IP Address stored as 32-bit integer

November 13, 2011

Each IP address is a numeric representation of a 32 bit number, which is normally how it is retrieved from a PLC or digital drive.

In this example: 16.1.206.254 ==0x1001CEFE because:

16 10
1 01
206 CE
254 FE

There are two methods to extract the IP address from an integer:

Method 1:

UInt32 iIP = 0x1001CEFE;
arDrives[i].lNodeIP = Convert.ToInt32(iIP)
sMsg = string.Format("  IP: {0}.{1}.{2}.{3}",
                      (arDrives[i].lNodeIP >> 24) & 0xFF,
                      (arDrives[i].lNodeIP >> 16) & 0xFF,
                      (arDrives[i].lNodeIP >> 8) & 0xFF,
                       arDrives[i].lNodeIP & 0xFF);
Console.WriteLine(sMsg);

Method 2:

public void GetAddr(Int32 lAddr, ref Int32[] ip) {
       ip[3] = (lAddr / 0x1000000);
       ip[2] = (lAddr / 0x10000) % 0x100;
       ip[1] = (lAddr / 0x100) % 0x100;
       ip[0] = (lAddr % 0x100);
 }

ts.GetAddr(arDrives[i].lNodeIP, ref ip)

sMsg = string.Format("  IP: {0}.{1}.{2}.{3}",
                      ip[3],
                      ip[2],
                      ip[1],
                      ip[0]);
Console.WriteLine(sMsg);


Bind list T to a DataGridView

November 11, 2011

Here is a technique to bind a List (of objects) to a DataGridView so that the public Properties appear as columns.

BindArrayToGrid

In this example, the columns are binded to the individual public property of the object. The column Random Number is binded to the public property RandomNumber while the column Square Root to the public property SqRt.

Create a class that contains the public properties that appear as columns in the dataGridView

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TestBindArrayToGrid
{
    public class RandomNbr : System.Object
    {
        private Double m_RandomNbr = 0.0;
        private Double m_SqRt = 0.0;

        private Random r;

        public RandomNbr(Double RandomNbr)
        {
            m_RandomNbr = RandomNbr;
            m_SqRt = Math.Sqrt(RandomNbr);
        }

        public RandomNbr()
        {
            m_RandomNbr = GenerateRandomNumber();
            m_SqRt = Math.Sqrt(m_RandomNbr);
        }

        public Double RandomNumber
        {
            get { return this.m_RandomNbr; }
            set { m_RandomNbr = value; }
        }

        public Double SqRt
        {
            get { return this.m_SqRt; }
            set { m_SqRt = value; }
        }

        private double GenerateRandomNumber()
        {
            TimeSpan ts = DateTime.Now.Subtract(new DateTime(2011,01,01));
            var Seconds = ts.TotalSeconds;

            r = new Random((int) Seconds);
            return r.NextDouble();
        }

        public Double GetNextRandom()
        {
            return r.NextDouble();
        }

        public void GetNextRandom(ref double _RandonNbr, ref double _SqRt)
        {
            _RandonNbr = m_RandomNbr = r.NextDouble();
            _SqRt = m_SqRt = Math.Sqrt(m_RandomNbr);
        }

    }
}

And here is the technique to bind the List objects to the DataGridView

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace TestBindArrayToGrid
{
    public partial class frmBindArrayToGrid : Form
    {
        List<RandomNbr> lstRandom = new List<RandomNbr>();
        private RandomNbr r = new RandomNbr();      // This seeds the random number generator

        public frmBindArrayToGrid()
        {
            InitializeComponent();
        }

        private void cmdExit_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void frmBindArrayToGrid_FormLoad(object sender, EventArgs e)
        {
            GenerateRandomList();
            BindArrayListToGrid();
        }

        private void BindArrayListToGrid()
        {
            dgRandom.Columns.Clear();

            // Create new column for randon number
            DataGridViewTextBoxColumn csRandom = new DataGridViewTextBoxColumn();
            
            csRandom.DataPropertyName = "RandomNumber";  // Public property name
            csRandom.HeaderText = "Random Number";      // Header name
            csRandom.DefaultCellStyle.Format = "#.#000";    // Format 
            dgRandom.Columns.Add(csRandom);

            // Create a column for the "SqrtValue" property
            // defined in the RandomNumber Class

            DataGridViewTextBoxColumn csSqRt = new DataGridViewTextBoxColumn();

            csSqRt.DataPropertyName = "SqRt";  // Public property name
            csSqRt.HeaderText = "Square Root";      // Header name
            csSqRt.DefaultCellStyle.Format = "#.#000";    // Format 
            dgRandom.Columns.Add(csSqRt);            

            dgRandom.DataSource = lstRandom;        // Binding is to the list of random numbers
            int rowNumber = 1;
            foreach (DataGridViewRow row in dgRandom.Rows)
            {
                row.HeaderCell.Value = "R" + rowNumber;
                rowNumber++;
            }
            dgRandom.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders);

            dgRandom.Show();
        }

        private void GenerateRandomList()
        {
            lstRandom.Add(new RandomNbr(r.GetNextRandom()));
            for (int i = 0; i < 100; i++)
            {
                lstRandom.Add(new RandomNbr(r.GetNextRandom()));
            }
        }
    }
}


Suppressing blanks when converting numbers to characters in Oracle

June 17, 2010

By default, a converted number to character prefixes a space (‘ ‘). To suppress all trailing and leading spaces, use FM. For example:

LotNum := to_char(intLotNbrBase, 'FM0000000') || to_char(intLotNbrExt, 'FM000')

produces

2080764.001


Using ListView’s AddRange method

March 23, 2010

L1_MMF_Reader_Listview.png

A listView control is used display realtime data from a Memory Mapped File that is being updated at a high-rate (5x/sec). This article will only focus on the updating to the listview, not the actual mechanism that performs the update on a timely basis; that will be left for another article.

My first attempt to add rows to the listView was to use the listView’s SubItem.Add method

for (i = 0; i < 1024; i++)
{
    ListViewItem row = new ListViewItem(i.ToString());
    ListViewItem bRow = new ListViewItem(i.ToString());
    ListViewItem fRow = new ListViewItem(i.ToString());

    row.SubItems.Add(arL1Int[i].ToString());
    bRow.SubItems.Add(arL1Bool[i].ToString());
    fRow.SubItems.Add(arL1Real[i].ToString());

    lvI.Items.Add(row);
    lvB.Items.Add(bRow);
    lvR.Items.Add(fRow);
}

And, even though the above code worked, it’s not the most efficient method.  Using the AddRange method is a much more efficient method.

Since each section has a boolean, integer and real data list, I first declare three generic lists:

List listViewItemsIntsList = new List&lt;ListViewItem&gt;();
List listViewItemsBoolsList = new List&lt;ListViewItem&gt;();
List listViewItemsFloatsList = new List&lt;ListViewItem&gt;();

To prevent drawing of the lists, I turn it off with a call BeginUpdate().  I turn it back on with a call to EndUpdate().

Each row in the listView is a listView item.  But, since these lists are being updated continuously, the items in the lists must first be cleared before they are populated.  Otherwise, the new rows are appended to the list.  A call to the Items.Clear() method is made to accomplish this task.

As we scan thru the array that was built from the Memory Mapped File (each array is 1024 elements), a listViewItem is created and added to the generic list.  After which the items are added to each listView via the AddRange method.

lvI.BeginUpdate();
lvB.BeginUpdate();
lvR.BeginUpdate();

lvI.Items.Clear();
lvB.Items.Clear();
lvR.Items.Clear();

for (i = 0; i < 1024; i++)
{
   ListViewItem lvi = new ListViewItem(i.ToString());
   ListViewItem lvb = new ListViewItem(i.ToString());
   ListViewItem lvf = new ListViewItem(i.ToString());

   lvi.SubItems.Add(arL1Int[i].ToString());
   lvb.SubItems.Add(arL1Bool[i].ToString());
   lvf.SubItems.Add(arL1Real[i].ToString());

   listViewItemsIntsList.Add(lvi);
   listViewItemsBoolsList.Add(lvb);
   listViewItemsFloatsList.Add(lvf);
}

lvI.Items.AddRange(listViewItemsIntsList.ToArray());
lvB.Items.AddRange(listViewItemsBoolsList.ToArray());
lvR.Items.AddRange(listViewItemsFloatsList.ToArray());

if (iTopVisIdx < 0) iTopVisIdx = 0;
if (iTopProcVisIdx < 0) iTopProcVisIdx = 0;
if (iTopDelvVisIdx < 0) iTopDelvVisIdx = 0;

lstEntryInts.TopItem = lstEntryInts.Items[iTopVisIdx];
lstEntryBools.TopItem = lstEntryBools.Items[iTopVisIdx];
lstEntryReals.TopItem = lstEntryReals.Items[iTopVisIdx];

lstProcInts.TopItem = lstProcInts.Items[iTopProcVisIdx];
lstProcBools.TopItem = lstProcBools.Items[iTopProcVisIdx];
lstProcReals.TopItem = lstProcReals.Items[iTopProcVisIdx];

lstDelvInts.TopItem = lstDelvInts.Items[iTopDelvVisIdx];
lstDelvBools.TopItem = lstDelvBools.Items[iTopDelvVisIdx];
lstDelvReals.TopItem = lstDelvReals.Items[iTopDelvVisIdx];

lvB.EndUpdate();
lvI.EndUpdate();
lvR.EndUpdate();
Blogged with the Flock Browser

LINQ to SQL DataContext Example

November 17, 2009

Having the need to query some SQL server tables using LINQ, I have to first connect to the database.  But, connecting to a database on a remote server is a little bit different than a local database.

Before we can discuss the things like tables, connection strings, queries, anonymous types, we need to discuss about an object called a DataContext.  The DataConext object is the pipe that connects your .Net application to the target database.  This is very similar to the ADO .Net database connection object.

You can think of the database as the entire entity – tables, stored procedures, columns – all that composes a database.  Well, the DataContext object is LINQ’s equivalent object since it is bound to the target  database. 

For the required binding, a DataContext object can be instantiated three ways:

  1. A string that represents the location of the SQL Server database
  2. A connection string
  3. Another DataContext object

All three can be passed into the DataContext constructor. 

I personally like to encapsulate the database’s DataContext object and its Table objects in its own class which then can be used as one unit:

using System;
using System.Collections.Generic;
using System.Data.Linq;
using System.Linq;
using System.Text;
namespace TestLinqSql
{
    public partial class clsL2db : DataContext
    {
        public Table&lt;Tracking&gt; Trackings;
        public clsL2db(string connection) : base(connection) { }
    }
}

The used of this class is shown below:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace TestLinqSql
{
    public partial class frmLingSql : Form
    {
        clsL2db db;
        public frmLingSql()
        {
            InitializeComponent();
        }
        private void frmLinqSql_Load(object sender, EventArgs e)
        {
            StringBuilder sb = new StringBuilder();
            try
            {
                db = new clsL2db(&quot;Server=BhServer;initial catalog=chtl_l2_db;user=sa;Password=&quot;);
            }
            catch (Exception ex)
            {
                sb.Length = 0;
                sb.Append(&quot;Cannot connect to CHTL DB: &quot;).Append(ex.Message);
                MessageBox.Show(sb.ToString());
            }
            try
            {
                var query =
                    from item in db.Trackings
                    where item.HeadWeldZone &lt; 80
                    select item;
                lstTrack.BeginUpdate();
                lstTrack.Items.Clear();
                foreach (var item in query)
                {
                    ListViewItem row = new ListViewItem(item.ChargeKey.ToString());
                    row.SubItems.Add(item.ChgCoilNbr.ToString());
                    row.SubItems.Add(item.HeadWeldZone.ToString());
                    row.SubItems.Add(item.TailWeldZone.ToString());                    lstTrack.Items.Add(row);<br /><br />
                }
                lstTrack.EndUpdate();
                lstTrack.Refresh();
            }
            catch (Exception ex)
            {
                sb.Length = 0;
                sb.Append(&quot;Cannot query DB: &quot;).Append(ex.Message);
                MessageBox.Show(sb.ToString());
            }
        }
        private void button1_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }
    }
}

Using C# structs between classes

November 12, 2009

I use structures to group data, such as messages or data records. I also use structures to pass groups of data between functions so that I don’t have a long parameter list.

Ususually, structures are used within the same class, but I use them to between classes. To allow more than one class to use the structure, I encapsulate the structure(s) within another class that is used by all the classes that use the structure.

In this example, I pass a structure from a function in one class to another function in another class as a parameter.

First, we define the structure in its own class.

using System;

namespace TestStruct
{
    public class TestStruct
    {
        public struct strTest
       {
           public int iA;
           public int iB;
           public int iC;
           public int iD;
           public bool boA;
           public bool boB;
       }
    }
}

The first class that uses the structure which sets the data values and passes the structure to another class’ function:

using System;
using TestStruct;
using TestClass;

static void UpdateL1TableWorker()
{
     strTest tS = new strTest();
     testClass tC = new testClass();

     int i = 1;
     int j = 2;
     tS.iA = 100;
     tS.iB = 200;
     tS.iC = 300;
     tS.iD = 400;
     tS.boA = (i == 1 ? true : false);
     tS.boB = (j > 3 ? true : false);
     tC.useStruct(ts);
}

This class uses the structure’s values:

using System;
using TestStruct;

public void useStruct(strTest tS)
{
     Console.WriteLine("iA: {0}  iB: {1}  iC: {2}  iD: {3}", tS.iA, tS.iB, tS.iC, tS.iD)
}

Synchronous event threads

October 26, 2009

C# supports what I call waitForEvent threads or formally known as synchronous event threads.  This is a thread that is fired whenever an event in another thread occurs.  I use this type of thread to perform an action when a bit transitions from true to false, a variable transitions above/below a limit.  The reason for doing this is because we do not want to interrupt the timer thread which checks these values on a 1-sec basis with the chore of building & sending messages, updating database tables, etc.

The design of L1 Monitor is to allow the timer thread to strictly check any transitions in bits or integers .    Initially, the threads are created and then wait until its event is set from another thread.

There are two types of synchronous  event thread: ManualResetEvent and AutoResetEvent.  I make use of the AutoResetEvent since the timer thread cannot waitupon a worker thread from completing its task.

Later, you will see how the worker thread is not fired by the timer when it is still running.

The worker thread has two states: signaled & reset.    Initially, the worker thread enters the reset state.  It wait for the event by making a call to WaitOne(). A signal state is set by the calling thread when issuing a call to Set().  When the thread is initiated, it waits for the event .  When the signal state is Set, the call to WaitOne() returns and the worker thread resumes execution.  Since I am using the AutoResetEvent worker thread, it automatically enters a reset state upon event notification.

Since parameters are not passed into  the worker thread (because it waiting for the event), we make use of static volatile variables to pass variables between the calling thread and the worker thread.   Static makes the variable global while volatile indicates that a field might be modified by multiple threads.

Here is an example on using a worker thread (comments explain what is happening…)

First, define the synchronous events using EventWaitHandle.  Initialize the event as non-signaled or reset state.


/* Define the sync event.  Specify the constructor with false to 
    indicate the thread will be created whose state is initialized 
    as reset */

static EventWaitHandle Level1Tbl = new AutoResetEvent(false);

Define the variables that are shared with the worker threads:

static volatile int iActivePOR;
static volatile int iHeadCropFtg;

/* This flag is set when the worker thread is running.  
    The calling thread checks this flag before signaling the 
    event to make sure that the worker event is not signaled 
    when it is already running */

static volatile bool boLevel1TblWorking = false;

In the service’s OnStart event, define and start the worker thread. Since the thread is created whose state is reset, the threads wait until needed.


/* Create worker thread and start it */
new Thread(HeadCropWorker).Start(); 

Create the worker thread as a function in the same class as the calling thread:

static void HeadCropWorker()
{
    StringBuilder sb = new StringBuilder();
    evtCropFtgThrd.WriteEntry("Head crop thread starting...", 
                    EventLogEntryType.Information);
    while (true)
    {
        string sActiveCoilNbr;

        /* Wait here until the event is signaled */
        HeadCropEvt.WaitOne();
        
        /* Set the flag to indicate that the thread is running */
        boHeadCropWorking = true;  

        if (iActivePOR == 1)
             sActiveCoilNbr = sCoilNbrAtPOR1;
         else
             sActiveCoilNbr = sCoilNbrAtPOR2;
         sb.Length = 0;
         sb.Append("Head crop received for coil ").Append(sActiveCoilNbr);
         sb.Append(" Active POR: ").Append(iActivePOR.ToString());
         sb.Append(" head crop ftg: ").Append(iHeadCropFtg.ToString());

         evtCropFtgThrd.WriteEntry(sb.ToString(), EventLogEntryType.Information);

         /* Thread is finished; ready for next event signal */
         boHeadCropWorking = false;
     }
}

The calling thread calls the worker thread:


     iActivePOR = (arByteEntry[clsGlobalDefs.POR1_ACTIVE_ON] == 1 ? 1 : 2);
     iHeadCropFtg = arIntEntry[clsGlobalDefs.ENTRY_HD_CROP_FTG];
     if (!boHeadCropWorking)
     {
         /* Set the event state to fire off the worker thread */
         HeadCropEvt.Set();           
     }
     else
         evt.WriteEntry("Head Crop Ftg worker still running...", EventLogEntryType.Warning);