[Continued] Try PLC register access with Python

In "Try PLC register access in Python", I tried basic word access by SLMP in Python. This time, I will implement the data manipulation when reading and writing a bit device with binary code in Python.

Bit device access method

SLMP offers two continuous access methods to bit devices.

--Read and write values from bit devices (consecutive device numbers) in 1-point units --Read and write values in 16-point units from bit devices (consecutive device numbers)

In the case of access in 1-point units, it is a 4-bit BCD code representation as shown below. The following is an example of communication at the time of reading.

image.png

For access in units of 16 points, 1 bit is a binary representation of 1 point. The following is an example of communication at the time of reading.

image.png

Of course, 16-point units are more advantageous for continuous mass reading and writing.

The communication command used is the same as when accessing words, but since bit data is packed as described above, data conversion is required to handle it as array data such as a list in Python.

This is quite annoying, and especially in the case of 16-point units, if you try to extract bit by bit normally, there is a concern that it will affect the processing speed in Python. Here, I will implement it using numpy bit operations.

Access in 1-point units

reading

Read with the Read command (0401h) in the same way as word access. However, the subcommand is different from 0001h.

If the received data array is extracted as [0x00, 0x01, 0x00, 0x11, ...], then [0, 0, 0, 1, 0, 0, 1, 1, ...] Must be expanded like .

The sample code below expands the BDC code array. The argument data and the return value are both numpy ndarray (dtype = uint8).

Since array data can be calculated in a batch by using numpy, loop processing in Python syntax is not required, and high-speed processing can be expected especially when the amount of data is large.

import numpy as np

# ex. data = np.array([0x12, 0x34, 0x56], 'u1')

def decode_bcd(data):
    """
    Decode 4bit BCD array
      [0x12,0x34,...] --> [1,2,3,4,...]
    """
    binArrayH = (data >> 4) & 0x0F
    binArrayL = data & 0x0F

    binArray = np.empty(data.size * 2, 'u1')
    binArray[::2] = binArrayH
    binArray[1::2] = binArrayL

    return binArray

writing

The pattern is the reverse of reading. Pack in BCD code. If the original data is an odd number, the last 4 bits are unused, so fill them with 0.

def encode_bcd(data):
    """
    Encode 4bit BCD array
      [1,2,3,4,...] --> [0x12,0x34,...]
If the number of inputs is odd, fill the last 4 bits with 0
    """
    binArrayH = (data[::2] & 0x0F) << 4
    binArrayL = data[1::2] & 0x0F
    binArray = np.zeros_like(binArrayH)

    if data.size % 2 == 0:
        binArray = binArrayH | binArrayL
    else:
        binArray[:-1] = binArrayH[:-1] | binArrayL
        binArray[-1] = binArrayH[-1]

    return binArray

Access in units of 16 points

reading

As with word access, the Read command (0401h) reads and the subcommands are the same. Since the content is word data, it is the same as a communication command.

As shown in the communication example above, the received 4-byte data [34h, 12h, 02h, 00h] is

[<M107>, ..., <M100>, <M115>, ..., <M108>, <M123>, ..., <M116>, <M131>, ..., <M124>]
                    ^                    ^                    ^

It will be expanded into a data array of 16 * 4 = 32 points by bit expansion as in.

The confusing thing here is that ** the addresses are stored in reverse order per byte **. In other words, in the above example, the LSB of the first 1 byte 34h is the value of the start address when the read command is sent, and the value of the data whose address is incremented toward the MSB. And for the 2nd byte 12h, the LSB is the value of" start address +8 "...

The sample code below uses numpy's unpackbit to expand each bit data into a one-dimensional array. numpy.packbits, [numpy.unpackbits](https://docs.scipy.org/doc/numpy /reference/generated/numpy.unpackbits.html) is a function that converts a decimal number ⇔ binary number array.

Where the order of LSB and MSB must be reversed, the miso is that the order in the column direction is reversed by specifying the slice after once arranging it in two dimensions and expanding the bits.

def unpack_bits(data):
    """
Expands the bit strings stored in order from the LSB into an array
    [<M107 ... M100>, <M115 ... M108>] --> [<M100>, ... ,<M107>, <M108>, ... ,<M115>]
    """

    #In order to reverse the data order after unpackbits, as a pseudo two-dimensional array,
    #Bit data should be stored for each byte
    #   ex. [1,2,3] --> [[1],[2],[3]]
    byteArray2D = data.reshape((data.size, 1))

    #Expand bit data
    #   ex. [[1],[2],[3]] --> [[0,0,0,0,0,0,0,1],[0,0,0,0,0,0,1,0],[0,0,0,0,0,0,1,1]]
    byteArray2D_bin = np.unpackbits(byteArray2D, axis=1)
            
    #After reversing the order in the column direction, return to the one-dimensional array
    return byteArray2D_bin[:, ::-1].flatten()

writing

The pattern is the reverse of reading. Packs 0/1 one-dimensional array data into a byte string.

def pack_bits(data):
    """
Pack an array of bit data into a byte string stored in order from the LSB
    [<M100>, ... ,<M107>, <M108>, ... ,<M115>]  --> [<M107 ... M100>, <M115 ... M108>]
    """
    #Make sure the number of data is a multiple of 8
    size8 = -(-data.size // 8) * 8

    #Fill in 0 where the last size is insufficient
    byteArray_bin = np.zeros(size8, 'u1')
    byteArray_bin[:size8] = data

    #Converted to a two-dimensional array to invert the data order every 8 bits
    byteArray2D_bin = byteArray_bin.reshape((size8//8, 8))

    #Pack bit data
    return np.packbits(byteArray2D_bin[:, ::-1])

References

--Mitsubishi Electric SLMP Reference Manual

Recommended Posts

[Continued] Try PLC register access with Python
Try PLC register access in Python
Try scraping with Python.
Try Python output with Haxe 3.2
Try running Python with Try Jupyter
Try scraping with Python + Beautiful Soup
Try to operate Facebook with Python
Try singular value decomposition with Python
Try http-prompt with interactive http access
Try face recognition with python + OpenCV
Try frequency control simulation with Python
Try python
Try to reproduce color film with Python
Try logging in to qiita with Python
Try mathematical formulas using Σ with python
Try using Python with Google Cloud Functions
Try HTML scraping with a Python library
Try calling Python from Ruby with thrift
Try drawing a map with python + cartopy 0.18.0
Try assigning or switching with Python: lambda
[For beginners] Try web scraping with Python
Access WebAPI with Python and register / acquire IoT data (dweet.io, Requests, HTTPie)
[Cloudian # 1] Try to access object storage with AWS SDK for Python (boto3)
FizzBuzz with Python3
Access Cyclone V's Lightweight HPS-to-FPGA Bridge with Python
Scraping with Python
Try it with Word Cloud Japanese Python JupyterLab.
Scraping with Python
Python with Go
Try running Google Chrome with Python and Selenium
Try to solve the man-machine chart with Python
Try to draw a life curve with python
Twilio with Python
Integrate with Python
Play with 2016-Python
Python> try: / except:
Try to make a "cryptanalysis" cipher with Python
AES256 with python
Tested with Python
Try to automatically generate Python documents with Sphinx
python starts with ()
with syntax (Python)
Try working with Mongo in Python on Mac
[Python3] [Ubuntu16] [Docker] Try face recognition with OpenFace
Bingo with python
Try to make a dihedral group with Python
Zundokokiyoshi with python
Excel with Python
Try to detect fish with python + OpenCV2.4 (unfinished)
Microcomputer with Python
Cast with python
Try to solve the programming challenge book with python3
Try to make a command standby tool with python
[Cloudian # 8] Try setting the bucket versioning with Python (boto3)
Try translating with Python while maintaining the PDF layout
Easily try Amazon EMR / Cloud Dataproc with Python [mrjob]
Try to solve the internship assignment problem with Python
Try touching the micro: bit with VS Code + Python
Install selenium on Mac and try it with python
Try debugging Python on Raspberry Pi with Visual Studio.
Try implementing associative memory with Hopfield network in Python