Articles IntelliPort - An Alternative Windows Version to the Famous HyperTerminal by Stefan-Mihai MOGA

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
IntelliPort - An Alternative Windows Version to the Famous HyperTerminal
Stefan-Mihai MOGA - 12/Jun/2020
[SHOWTOGROUPS=4,20]
You can use IntelliPort to transfer large files from a computer onto your portable computer using a serial port rather than going through the process of setting up your portable computer on a network.
The main purpose of this MFC application is to get logs via serial port or UDP socket from embedded systems, such as EFTPOS devices, and it is based on PJ Naughter's CSerialPort and CWSocket classes.

1591984839813.png

Introduction
As you already know, Microsoft has dropped the development of HyperTerminal starting with Windows 7. IntelliPort is a program that you can use to connect to other computers, using either your null modem cable or Ethernet connection. IntelliPort records the messages passed to and from the computer on the other end of your connection. Therefore, it can serve as a valuable troubleshooting tool when setting up and using your modem. To make sure that your modem is connected properly or to view your modem's settings, you can send commands through IntelliPort and check the results. IntelliPort has scroll functionality that allows you to look at received text that has scrolled off the screen. You can use IntelliPort to transfer large files from a computer onto your portable computer using a serial port rather than going through the process of setting up your portable computer on a network. IntelliPort is designed to be an easy-to-use tool and is not meant to replace other full-feature tools available on the market. You can use IntelliPort to perform the specific tasks described above, but do not attempt to use IntelliPort for more complex communication needs.

Background
The main purpose of this MFC application is to get logs via serial port or UDP socket from embedded systems, such as EFTPOS devices, and it is based on PJ Naughter's CSerialPort and CWSocket classes. For those who do not know, EFTPOS is the method for paying for goods or services without needing to carry cash. On making a purchase, the EFTPOS customer gives an EFTPOS card to the cashier who inserts it into an on-site EFTPOS machine. When the EFTPOS customer confirms the purchase, either by signature or security PIN, the EFTPOS equipment contacts the store's bank electronically about the transaction. A message is also sent to the customer's bank. Unless there is reason for the EFTPOS transaction not to be completed, the funds will then be transferred between the two accounts. The EFTPOS transaction takes a matter of only a few seconds. Before the EFTPOS customer has had the goods put into a bag, the EFTPOS transaction will be complete. Confirmation of the EFTPOS transaction is sent to the store and passed on to the customer in the form of a printed EFTPOS transaction record.

How Do I Get Started?
First, configure the MFC application to get logs from either serial port or TCP/UDP socket connection. Please check the CConfigureDlg class for implementation details.

1591984858626.png

Next, now you can connect/disconnect from your data source. Please check the OnOpenSerialPort and OnCloseSerialPort functions for implementation details.

1591984871926.png


[/SHOWTOGROUPS]
 

emailx45

Местный
Регистрация
5 Май 2008
Сообщения
3,571
Реакции
2,438
Credits
573
[SHOWTOGROUPS=4,20]
Код:
void CMainFrame::OnOpenSerialPort()
{
   CString strMessage;
   switch (theApp.GetInt(_T("Connection"), 0))
   {
      case 0:
      {
         m_pSerialPort.Open(
            (LPCTSTR) theApp.GetString
            (_T("SerialName"), _T("COM1")),
            theApp.GetInt(_T("BaudRate"), CBR_115200),
            (CSerialPort::Parity) theApp.GetInt
            (_T("Parity"), CSerialPort::NoParity),
            (BYTE) theApp.GetInt(_T("DataBits"), 8),
            (CSerialPort::StopBits) theApp.GetInt
            (_T("StopBits"), CSerialPort::OneStopBit),
            (CSerialPort::FlowControl) theApp.GetInt
            (_T("FlowControl"), CSerialPort::NoFlowControl),
            FALSE);

         if (m_pSerialPort.IsOpen())
         {
            m_nThreadRunning = TRUE;
            AfxBeginThread(SerialPortThreadFunc, this);
            strMessage.Format(_T("Serial port %s has been opened."), 
            theApp.GetString(_T("SerialName"), _T("COM1")));
            SetCaptionBarText(strMessage);
         }
         break;
      }
      case 1:
      case 2:
      {
         CString strServerIP = theApp.GetString
         (_T("ServerIP"), _T("127.0.0.1"));
         if (strServerIP.IsEmpty()) strServerIP = _T("127.0.0.1");
         const UINT nServerPort = 
         theApp.GetInt(_T("ServerPort"), 0);
         CString strClientIP = theApp.GetString
         (_T("ClientIP"), _T("127.0.0.1"));
         if (strClientIP.IsEmpty()) strClientIP = _T("127.0.0.1");
         const UINT nClientPort = 
         theApp.GetInt(_T("ClientPort"), 0);

         m_pSocket.SetBindAddress(strClientIP);
         m_pSocket.CreateAndBind(nClientPort, ((theApp.GetInt
         (_T("Connection"), 0) == 1) ? SOCK_STREAM : SOCK_DGRAM), AF_INET);

         if (m_pSocket.IsCreated())
         {
            if (theApp.GetInt(_T("Connection"), 0) == 1) // TCP Socket
            {
               if (theApp.GetInt(_T("SocketType"), 0) == 1) // Client
               {
                  m_pSocket.Connect(strServerIP, nServerPort);
               }
               else // TCP Server
               {
                  m_dlgIncoming.ShowWindow(SW_SHOW);
                  m_dlgIncoming.CenterWindow(this);
                  m_dlgIncoming.Invalidate();
                  m_dlgIncoming.UpdateWindow();
                  m_pSocket.Listen();
                  m_pSocket.Accept(m_pIncomming);
                  m_dlgIncoming.ShowWindow(SW_HIDE);
               }
            }
            else // UDP Socket
            {
            }

            m_nThreadRunning = TRUE;
            AfxBeginThread(SocketThreadFunc, this);
            strMessage.Format(_T("%s socket %s:%d has been created."), 
            ((theApp.GetInt(_T("Connection"), 0) == 1) ? 
            _T("TCP") : _T("UDP")), strServerIP, nServerPort);
            SetCaptionBarText(strMessage);
         }
         break;
      }
   }
}

void CMainFrame::OnCloseSerialPort()
{
   CString strMessage;
   m_nThreadRunning = FALSE;
   ::Sleep(1000);
   switch (theApp.GetInt(_T("Connection"), 0))
   {
      case 0:
      {
         m_pSerialPort.Close();

         if (!m_pSerialPort.IsOpen())
         {
            strMessage.Format(_T("Serial port %s has been closed."), 
            theApp.GetString(_T("SerialName"), _T("COM1")));
            SetCaptionBarText(strMessage);
         }
         break;
      }
      case 1:
      case 2:
      {
         CString strServerIP = theApp.GetString
         (_T("ServerIP"), _T("127.0.0.1"));
         if (strServerIP.IsEmpty()) strServerIP = _T("127.0.0.1");
         const UINT nServerPort = theApp.GetInt(_T("ServerPort"), 0);

         m_pSocket.Close();
         m_pIncomming.Close();

         if (!m_pSocket.IsCreated())
         {
            strMessage.Format(_T("%s socket %s:%d has been closed."), 
            ((theApp.GetInt(_T("Connection"), 0) == 1) ? 
            _T("TCP") : _T("UDP")), strServerIP, nServerPort);
            SetCaptionBarText(strMessage);
         }
         break;
      }
   }
}

void CMainFrame::OnSendReceive()
{
   CInputDlg dlgInput(this);
   if (dlgInput.DoModal() == IDOK)
   {
      CStringA pBuffer(dlgInput.m_strSendData);
      const int nLength = pBuffer.GetLength();

      switch (theApp.GetInt(_T("Connection"), 0))
      {
         case 0:
         {
            m_pMutualAccess.Lock();
            m_pSerialPort.Write
            (pBuffer.GetBufferSetLength(nLength), nLength);
            m_pMutualAccess.Unlock();
            pBuffer.ReleaseBuffer();
            break;
         }
         case 1:
         case 2:
         {
            CString strServerIP = theApp.GetString
            (_T("ServerIP"), _T("127.0.0.1"));
            if (strServerIP.IsEmpty()) strServerIP = _T("127.0.0.1");
            const UINT nServerPort = theApp.GetInt(_T("ServerPort"), 0);
            // CString strClientIP = theApp.GetString
            (_T("ClientIP"), _T("127.0.0.1"));
            // if (strClientIP.IsEmpty()) strClientIP = _T("127.0.0.1");
            // const UINT nClientPort = theApp.GetInt(_T("ClientPort"), 0);

            if (theApp.GetInt(_T("Connection"), 0) == 1) // TCP Socket
            {
               if (theApp.GetInt(_T("SocketType"), 0) == 1) // Client
               {
                  if (m_pSocket.IsWritable(1000))
                  {
                     m_pMutualAccess.Lock();
                     m_pSocket.Send
                     (pBuffer.GetBufferSetLength(nLength), nLength, 0);
                     pBuffer.ReleaseBuffer();
                     m_pMutualAccess.Unlock();
                  }
               }
               else
               {
                  if (m_pIncomming.IsWritable(1000))
                  {
                     m_pMutualAccess.Lock();
                     m_pIncomming.Send
                     (pBuffer.GetBufferSetLength(nLength), nLength, 0);
                     pBuffer.ReleaseBuffer();
                     m_pMutualAccess.Unlock();
                  }
               }
            }
            else
            {
               if (m_pSocket.IsWritable(1000))
               {
                  m_pMutualAccess.Lock();
                  m_pSocket.SendTo(pBuffer.GetBufferSetLength(nLength), 
                  nLength, nServerPort, strServerIP, 0);
                  pBuffer.ReleaseBuffer();
                  m_pMutualAccess.Unlock();
               }
            }
            break;
         }
      }
   }
}

Points of Interest
In order to be GUI responsive, the MFC application does the reading in separate working threads:

Код:
UINT SerialPortThreadFunc(LPVOID pParam)
{
   COMSTAT status = { 0, };
   char pBuffer[0x1000] = { 0, };
   CMainFrame* pMainFrame = (CMainFrame*) pParam;
   CRingBuffer& pRingBuffer = pMainFrame->m_pRingBuffer;
   CSerialPort& pSerialPort = pMainFrame->m_pSerialPort;
   CMutex& pMutualAccess = pMainFrame->m_pMutualAccess;

   while (pMainFrame->m_nThreadRunning)
   {
      memset(&status, 0, sizeof(status));
      pSerialPort.GetStatus(status);
      if (status.cbInQue > 0)
      {
         memset(pBuffer, 0, sizeof(pBuffer));
         const int nLength = 
         pSerialPort.Read(pBuffer, sizeof(pBuffer));
         pMutualAccess.Lock();
         pRingBuffer.WriteBinary(pBuffer, nLength);
         pMutualAccess.Unlock();
      }
      ::Sleep(10);
   }
   return 0;
}

UINT SocketThreadFunc(LPVOID pParam)
{
   char pBuffer[0x1000] = { 0, };
   CMainFrame* pMainFrame = (CMainFrame*) pParam;
   CRingBuffer& pRingBuffer = pMainFrame->m_pRingBuffer;
   CWSocket& pSocket = pMainFrame->m_pSocket;
   CWSocket& pIncomming = pMainFrame->m_pIncomming;
   CMutex& pMutualAccess = pMainFrame->m_pMutualAccess;
   BOOL bIsTCP = (theApp.GetInt(_T("Connection"), 0) == 1);
   BOOL bIsClient = (theApp.GetInt(_T("SocketType"), 0) == 1);

   CString strServerIP = theApp.GetString
   (_T("ServerIP"), _T("127.0.0.1"));
   if (strServerIP.IsEmpty()) strServerIP = _T("127.0.0.1");
   UINT nServerPort = theApp.GetInt(_T("ServerPort"), 0);

   while (pMainFrame->m_nThreadRunning)
   {
      if (bIsTCP)
      {
         if (bIsClient)
         {
            if (pSocket.IsReadible(1000))
            {
               memset(pBuffer, 0, sizeof(pBuffer));
               const int nLength = 
               pSocket.Receive(pBuffer, sizeof(pBuffer), 0);
               pMutualAccess.Lock();
               pRingBuffer.WriteBinary(pBuffer, nLength);
               pMutualAccess.Unlock();
            }
         }
         else
         {
            if (pIncomming.IsReadible(1000))
            {
               memset(pBuffer, 0, sizeof(pBuffer));
               const int nLength = 
               pIncomming.Receive(pBuffer, sizeof(pBuffer), 0);
               pMutualAccess.Lock();
               pRingBuffer.WriteBinary(pBuffer, nLength);
               pMutualAccess.Unlock();
            }
         }
      }
      else
      {
         if (pSocket.IsReadible(1000))
         {
            memset(pBuffer, 0, sizeof(pBuffer));
            const int nLength = pSocket.ReceiveFrom
            (pBuffer, sizeof(pBuffer), strServerIP, nServerPort, 0);
            pMutualAccess.Lock();
            pRingBuffer.WriteBinary(pBuffer, nLength);
            pMutualAccess.Unlock();
         }
      }
      ::Sleep(10);
   }
   return 0;
}


Final Words
IntelliPort application uses many components that have been published on The Code Project. Many thanks to:
  • PJ Naughter for his EnumSerialPorts class
  • Larry Antram for his CRingBuffer class
  • PJ Naughter for his CSerialPort class
  • PJ Naughter for his CWSocket class
  • PJ Naughter for his CVersionInfo class
Further plans: I would like to add Telnet and SSH support as soon as possible.
History
  • Version 1.3 (20th July, 2014)
    • Initial release
  • Version 1.5 (28th July, 2014)
    • Fixed several bugs regarding logging functions for serial port and UDP socket
  • Version 1.6 (30th August, 2015)
    • Fix for Microsoft Windows 10 64bit
  • Version 1.7 (03rd April, 2019)
    • Performance and security fixes
  • Version 1.8 (15th June, 2019)
    • Added Romanian translation; could anyone add German/French/Spanish/etc. translations?
    • Added PJ Naughter's CInstanceChecker class;
  • Version 1.9 (27th July, 2019)
    • Bugfix for serial port name - please see the article mentioned in the comments
  • Moved source code from CodeProject to GitLab (7th December, 2019)
  • Version 1.10 (25th March, 2020)
    • Changed font size for main and input dialogs
  • Version 1.11 (9th May, 2020)
  • Version 1.12 (6th June, 2020)
  • Version 1.13 (13th June, 2020)
    • Added German translation, thanks to InterLingua
Official site: Для просмотра ссылки Войди или Зарегистрируйся
GitLab: Для просмотра ссылки Войди или Зарегистрируйся

License
This article, along with any associated source code and files, is licensed under The GNU General Public License (GPLv3)
[/SHOWTOGROUPS]