Skip to main content

Dump (PX-41CX)

·

px-41cx
px-41cx

Introduction #

The PX-41CX allows the user to backup the memory contend using the enclosed USB serial connection cable. For details I suggest you download the PX-41CX documentation from Pierre Houbert’s hompage. The documentation describes how to receive and send memory dumps manually using CoolTerm.

However you might want to automate the process so no copy/paste from a terminal window is needed. On macOS this has proven more difficult then expected. Trying to open the device with cat , a shell redirection or even open all failed. The process just hung on the process. There is a known bug.

Since Miniterm from Python’s pyserial package worked I begrudgingly decided to write a tool in Python.

Preparation #

You need to install Python 3 if you have not done so already as well as the pyserial package.

macOS #

On macOS you can use the following commands.

brew install				\
    "coolterm"				\
    "python3"

pip3 install --break-system-packages	\
    "pyserial"
Download Install.command

Windows & Linux #

Windows installation is described in Pierre Houbert’s document and for Linux you use the package manager of your distribution.

Using git clone #

Alternatively you can clone git clone Calculator-Scripts project with it’s sub modules which will set up everything with correct directory structure:

git clone https://git.code.sf.net/p/calculator-scripts/code calculator-scripts
cd calculator-scripts
git checkout --track master
git submodule init
git submodule update
Utilities/Install.command
cd PX-41CX/Dump

Receive #

Receive.py is meant to be used with the executable flag set. It takes the file name to store the memory dump in. It will ignore the garbage data the calculator sends before and after the transmission and only stores the actual memory data.

Usage #

  1. Set the environment variables USB_Serial_Device and USB_Serial_Speed. At least on macOS the device name changes depending how the device is connected so hard coding the device is not helpful.
  2. Start Receive.py
  3. Use the calculators MENUCOMDUMP to start the dump

macOS & Linux #

export USB_Serial_Device=/dev/tty.usbserial-14440
export USB_Serial_Speed=115200

python3 Receive.py Dump.px41

Windows #

SET USB_Serial_Device=COM8:
SET USB_Serial_Speed=115200

python Receive.py Dump.px41

Source #

#!/usr/bin/env python3

import os
import serial
import sys

# Set connection data from environment variables.
#
USB_Serial_Device = os.getenv ('USB_Serial_Device')
USB_Serial_Speed  = os.getenv ('USB_Serial_Speed')
Start             = False
Output_Array      = bytearray ()

# The script takes a single parameter from the command line which is the file
# name. If no file name is given "Dump.px41" is used
#
if len (sys.argv) > 1:
  Output_File = sys.argv[1]
else:
  Output_File = "Dump.px41"
# end if

# open serial port
#
with serial.Serial (USB_Serial_Device, USB_Serial_Speed, timeout=1) as Device:
  while True:
    # Read one line from serial port. The result is a byte array.
    #
    Line_Array =Device.readline ()

    # Ignore all data until line with "PX41" is received.
    #
    if Line_Array == b'PX41\n':
      Start = True
    # end if

    # Once the start of transmission was detected add each line to the output
    # array as well as print the line to the console so the user knows that
    # stuff is happening. The start and end lines are also added.
    #
    if Start:
      Output_Array.extend (Line_Array)
      print (Line.decode ("Latin1"), end='')
    # end if

    # End reading when a line with "EOF" is received.
    #
    if Line_Array == b'EOF\n':
      break
    # end if
  # end while
# end with

# write the received data as binary so nothing is corrupted by text encoding
#
with open (Output_File, "wb") as Binary_File:
  Binary_File.write (Output_Array)
# end with
Download Receive.py

Send #

Send.py sends the previously stored data back to the calculator. Like Receive.py it the file name to send as one parameter.

Usage #

  1. Set the environment variables USB_Serial_Device and USB_Serial_Speed.
  2. Use the calculators MENUCOMLOAD start the load
  3. Start Send.py

macOS & Linux #

export USB_Serial_Device=/dev/tty.usbserial-14440
export USB_Serial_Speed=115200

python3 Send.py Dump.px41

Windows #

SET USB_Serial_Device=COM8:
SET USB_Serial_Speed=115200

python3 Send.py Dump.px41

Source #

#!/usr/bin/env python3

# Set connection data from environment variables.
#
USB_Serial_Device = os.getenv ('USB_Serial_Device')
USB_Serial_Speed  = os.getenv ('USB_Serial_Speed')

# The script takes a single parameter frome the command line which is the
# file name. If no filename is given  "Dump.px41" is used
#
if len (sys.argv) > 1:
  Input_File = sys.argv[1]
else:
  Input_File = "Dump.px41"
# end if

# read data as binary so nothing is corrupted by text encoding
#
with open (Input_File, "rb") as Binary_File:
  Read_Array = bytearray (Binary_File.read ())
# end with

# open serial port
#
with serial.Serial (USB_Serial_Device, USB_Serial_Speed, timeout=1) as Device:
  # Sending the whole data in one go seem to overload and crash the calculator
  # so we Split the received data at new line charcters (10) so we can slow the
  # transmission down
  #
  for _, Line in itertools.groupby(Read_Array, lambda x: x == 10):
    Line_Array = bytearray(Line)
    print (Line_Array.decode ("Latin1"), end='')
    Device.write (Line_Array)
    time.sleep(0.1)
  # end for
# end with
Download Send.py