FreeMASTER communication library in a Python script

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

FreeMASTER communication library in a Python script

FreeMASTER communication library in a Python script

Intro

One not widely known feature of the FreeMASTER tool is the ability of using FreeMASTER communication library in 3rd party applications or scripts. This library implements the proprietary communication protocol and allows developers to interact with the target board from their own desktop application (complementary to FreeMASTER GUI and JSON-RPC API usage).

Note: although this approach grants developers full control over the communication with the target board it lacks some advanced features of the FreeMASTER tool such as symbol loading (it does not include TSA loading and ELF parsing functionalities) and users need to pass numeric addresses when reading and writing embedded project variables.    

This article is meant to provide a basic example on the communication library usage in a custom Python script using ctypes based on the shared library distributed with FreeMASTER Lite.

An similar articles covering the same topic using C/C++ can be found here.

Prerequisites

Required files for this example are located under FreeMASTER Lite installation directory (default location C:\NXP\FreeMASTER 3.x\FreeMASTER):

  • include - folder containing required header files
  • lib - folder containing shared library

Considering the library targets 32bit architecture you would need a 32bit variant of Python (tested with version 3.6)

Code Example

from ctypes import *

def hex32(val):
  return hex(val & (1 << 32 - 1))

def MCB_FAILED(val):
  return val < 0

def MCB_SUCCEEDED(val):
  return val >= 0

class DESCRIPTION(Array):
  _length_ = 25
  _type_ = c_uint8

class MCB_RESP_GETINFO_t(Structure):
  _fields_ = [("protVer", c_uint8),
              ("cfgFlags", c_uint8),
              ("dataBusWdt", c_uint8),
              ("globVerMajor", c_uint8),
              ("globVerMinor", c_uint8),
              ("cmdBuffSize", c_uint8),
              ("recBuffSize", c_uint16),
              ("recTimeBase", c_uint16),
              ("descr", DESCRIPTION)]

mcbcom = CDLL("C:/NXP/FreeMASTER 3.1/FreeMASTER Lite/lib/mcbcom.dll")

pCom = c_void_p()

result = mcbcom.McbOpenComEx(byref(pCom), c_char_p(b"RS232;port=COM3;speed=115200;tmoRI=40;tmoRTM=40;tmoRTC=50;tmoWTM=40;tmoWTC=50"))

if (MCB_FAILED(result)):
  print("Could not open communication channel. Error code: ", hex32(result))
  exit(1)

boardInfo = MCB_RESP_GETINFO_t()
result = mcbcom.McbGetInfo(pCom, byref(boardInfo))

if (MCB_SUCCEEDED(result)):
  print("Board is using FreeMASTER Driver v", boardInfo.protVer, sep='')
  print("Embedded application description", str(boardInfo.descr, 'utf-8'))

mcbcom.McbCloseCom(pCom)

Breaking down code example

  • It uses ctypesis a foreign function library for Python. It provides C compatible data types, and allows calling functions in DLLs or shared libraries. It can be used to wrap these libraries in pure Python.
  • All exported functions signatures can be found in the mcbcom.h files inside include folder
  • Macros cannot be used in Python and need to implemented in Python or replaced with alternatives (where applicable).
    Ex: C macros:
    #define MCB_FAILED(code)    (((int32_t)(code)) < 0)
    #define MCB_SUCCEEDED(code) (((int32_t)(code)) >= 0)

    Python implementation:

    def MCB_FAILED(val):
      return val < 0
    
    def MCB_SUCCEEDED(val):
      return val >= 0
  • C structures also need to be implemented in Python 
    Ex: C structure:
    typedef struct MCB_RESP_GETINFO_t
    {
      uint8_t protVer;                /**< @brief protocol version */
      uint8_t cfgFlags;               /**< @brief MCB_CFGFLAG_ bits */
      uint8_t dataBusWdt;             /**< @brief data bus width (bytes) */
      uint8_t globVerMajor;           /**< @brief board firmware version major number */
      uint8_t globVerMinor;           /**< @brief board firmware version minor number */
      uint8_t cmdBuffSize;            /**< @brief receive/transmit buffer size (without SOB, CMD/STS and CS) */
      uint16_t recBuffSize;           /**< @brief recorder buffer memory */
      uint16_t recTimeBase;           /**< @brief recorder time base (2 MSB exponent 1 = m, 2 = u, 3 = n) */
      uint8_t descr[MCB_DESCR_SIZE];  /**< @brief ANSI string, board description */
    } MCB_RESP_GETINFO_t;​

    Python implementation using ctypes:

    class DESCRIPTION(Array):
      _length_ = 25
      _type_ = c_uint8
    
    class MCB_RESP_GETINFO_t(Structure):
      _fields_ = [("protVer", c_uint8),
                  ("cfgFlags", c_uint8),
                  ("dataBusWdt", c_uint8),
                  ("globVerMajor", c_uint8),
                  ("globVerMinor", c_uint8),
                  ("cmdBuffSize", c_uint8),
                  ("recBuffSize", c_uint16),
                  ("recTimeBase", c_uint16),
                  ("descr", DESCRIPTION)]
  • Finally, C functions can be called from Python using the signatures that can be found in the mcbcom.h file:
    pCom = c_void_p()
    result = mcbcom.McbOpenComEx(byref(pCom), c_char_p(b"RS232;port=COM3;speed=115200;tmoRI=40;tmoRTM=40;tmoRTC=50;tmoWTM=40;tmoWTC=50"))
    
    boardInfo = MCB_RESP_GETINFO_t()
    result = mcbcom.McbGetInfo(pCom, byref(boardInfo))​
     
No ratings
Version history
Last update:
‎11-01-2021 01:40 AM
Updated by: