Skip to main content

Serial Communication Framework for Raspberry PI

Project description

picmd

picmd is a framework for creating applications that request and respond to AT commands using serial communication.

Its main purpose is for use with Raspberry PI.

Quick Sample

Create an instance of PiCmd with the create method and register the command handler with the handler decorator.

Start the application with the run method and wait for a command request.

from picmd import PiCmd
import time

app = PiCmd.create('/dev/serial0')

@app.handler(0x01)
def greeting_handler() -> str:
    return 'hello world'

@app.handler(0x02)
def file_receive_handler(data: bytes):
    with open('./tmp/received-%s.bin' % int(time.time()), 'wb') as f:
        f.write(data)

app.run()

AT Command Format

Command Request (Client -> Application)

Hexadecimal data starting with AT*PIC= and ending with CRLF.

The command type is specified by the first 8 bits.

The command parameter size is represented by the second 16 bits. Then there is the content of the command parameters.

The check parity is the XOR of the values from command type to command parameter.

AT*PIC=\x01\x04\x00\x01\x00\x00\x00\x04\r\n
<-----><--><------><--------------><--><-->
   \     \      \     \               \  \_ command end delimiter (CRLF)
    \     \      \     \               \_ check parity
     \     \      \     \_ command data (The length changes depending on the value of "command data size")
      \     \      \_ command data size (max 0xffff)
       \     \_ command (max 0xff)
        \_ command start prefix

Command Response (Application -> Client)

Hexadecimal data starting with *PIC: and ending with CRLF.

The response status is specified by the first 8 bits.

The response data size is represented by the second 16 bits. Then there is the content of the response datas.

The check parity is the XOR of the values from response status to response data.

OK

*PIC:\x01\x04\x00\x01\x00\x00\x00\x04\r\nOK\r\n
<---><--><------><--------------><--><-------->
  \    \      \       \             \      \_ response end delimiter
   \    \      \       \             \_ check parity
    \    \      \       \_ response data (The length changes depending on the value of "response data size")
     \    \      \_ response data size (max 0xffff)
      \    \_ response status (0x01)
       \_ response start prefix

ERROR

*PIC:\x07\x04\x00\x01\x00\x00\x00\x02\r\nERROR\r\n
<---><--><------><--------------><--><----------->
  \    \      \       \            \       \_ response end delimiter
   \    \      \       \            \_ check parity
    \    \      \       \_ response data (The length changes depending on the value of "response data size")
     \    \      \_ response data size (max 0xffff)
      \    \_ response status (values from 0x02 to 0xff)
       \_ response start prefix

Reserved value of response status

status description
0x01 No error
0x02 Invalid command format error
0x03 Invalid parity error
0x04 Command not found error
0x05 Invalid data length error
0x06 Command fail error

How to confirm communication

Sends the following command.

AT\r\n

If the next message is received in the response, the communication confirmation is successful.

\r\n
OK
\r\n

Command Handler Interface

The command handler function receives the byte data of the command parameter in the first argument data and the size of the command parameter in the second argument size. It is also possible to omit either or both of these.

You can take a dependency set by the provide function (see later) as an argument.

Examples of handlers' arguments

An example of a case where you want to receive both data and size.

@app.handler(0x01)
def handler(data: bytes, size: int):
    ....

An example of receiving data only.

@app.handler(0x01)
def handler(data: bytes):
    ....

Example of a case where both are not received.

@app.handler(0x01)
def handler():
    ....

An example of receiving data and dependencies.

@app.handler(0x01)
def handler(data: bytes, service1: Service1, service2: Service2):
    ....

When returning some kind of response

Returns a value of type bool, int, float,str, or bytes.

@app.handler(0x01)
def handler(data: bytes, size: int) -> Union[bool, int, float, str, bytes]:
    ....
    return response_data

When returning no response

Returns nothing.

@app.handler(0x01)
def handler(data: bytes, size: int):
    ....
    # nothing return

If you want to return your domain error status

Raise an exception with the status_code attribute. If you want to return error message etc. as response data, add description attribute.

class DomainException(Exception):
    status_code = 0xff
    description = 'any error message'

@app.handler(0x01)
def handler(data: bytes, size: int):
    ....
    raise DomainException

API

PiCmd

PiCmd.create(serial_port: str) -> PiCmd

Take the serial port path as an argument and create an instance.

@handler(command: int)

Decorator that takes a command type as an argument and registers it as a handler.

provide(provided: Dict[str, Any])

Specifies the dependency to pass to the handler by dict. The handler will receive the same arguments as the key name.

for example.

app.provide({
    'service1': service1,
    'service2': service2
})

import_handler_register(handler_register: HandlerRegister)

Import the handlers registered in the HandlerRegister.

run()

Start accepting and responding to commands.

HandlerRegister

It is used to register handlers to be imported into PiCmd.

@handler(command: int)

Decorator that takes a command type as an argument and registers it as a handler.

Client library

The libraries for the client are as follows.

Change Log

0.7.0

Added HandlerRegister feature.

0.6.1

Fixed a response bug of the PING command.

0.6.0

Added a feature to confirm communication.

0.5.0

Added the feature to provide dependency.

0.4.0

Added support for omitting the arguments of the handler function.

0.3.0

Change the data format of the protocol.

0.2.0

Change request and resopnse prefix.

0.1.0

Initial release.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

picmd-0.7.0.tar.gz (10.2 kB view hashes)

Uploaded Source

Built Distribution

picmd-0.7.0-py3-none-any.whl (10.4 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page