OS Memory Bridge

The OS memory bridge pattern maps memory transactions to host-side Python functions so standard RemoteVariable access can target non-hardware data sources.

The bridge is typically built from two parts used together:

  • OsCommandMemorySlave: a memory Slave that maps addresses to Python command callbacks.

  • OsMemMaster: an example Device that exposes typed RemoteVariable Nodes at those same offsets.

This pairing is useful for prototyping register maps, exposing host metrics inside a tree, and testing memory-control paths before firmware is available.

OsCommandMemorySlave

OsCommandMemorySlave maps read/write transactions to Python callables keyed by address.

How mapping works:

  • Write and Post transactions are decoded with the registered base Model and passed to the callback as arg.

  • Read transactions call the same callback with arg=None and encode the return value with that same Model before returning it to the transaction.

Commands are registered with @self.command(addr=..., base=...).

Method And Mapping Overview

  • @self.command(addr=..., base=...) registers one address callback.

  • addr defines the transaction-mapped register offset.

  • base defines encode/decode model for read/write payload conversion.

  • Callback arg behavior: - arg is None on read transactions. - arg contains decoded write value on write and Post transactions.

import os
import pathlib
import time
import pyrogue as pr
import pyrogue.interfaces as pri

class MyCmdSlave(pri.OsCommandMemorySlave):
    def __init__(self):
        super().__init__(minWidth=4, maxSize=256)

        @self.command(addr=0x00, base=pr.Float(32))
        def Uptime(self, arg):
            # Read-only command: ignore writes.
            if arg is None:
                return float(time.monotonic())
            return float(time.monotonic())

        @self.command(addr=0x04, base=pr.Float(32))
        def SysLoad1Min(self, arg):
            if arg is None:
                return float(os.getloadavg()[0])
            return float(os.getloadavg()[0])

        @self.command(addr=0x08, base=pr.Float(32))
        def SysLoad5Min(self, arg):
            if arg is None:
                return float(os.getloadavg()[1])
            return float(os.getloadavg()[1])

        @self.command(addr=0x0C, base=pr.Float(32))
        def SysLoad15Min(self, arg):
            if arg is None:
                return float(os.getloadavg()[2])
            return float(os.getloadavg()[2])

        @self.command(addr=0x10, base=pr.UInt(32))
        def FileTest(self, arg):
            # RW path matching OsMemMaster.FileTest.
            if arg is not None:
                pathlib.Path('/tmp/osCmdTest.txt').write_text(f'{int(arg)}\n')
                return int(arg)

            file_path = pathlib.Path('/tmp/osCmdTest.txt')
            if file_path.exists():
                return int(file_path.read_text().strip())
            return 0

        @self.command(addr=0x14, base=pr.Float(32))
        def CpuTempC(self, arg):
            # Optional Linux thermal-zone example (millidegrees C -> C).
            if arg is None:
                thermal = pathlib.Path('/sys/class/thermal/thermal_zone0/temp')
                if thermal.exists():
                    return float(thermal.read_text().strip()) / 1000.0
                return -1.0
            return -1.0

OsMemMaster Device Pattern

OsMemMaster is an example Device that defines typed RemoteVariable Nodes at offsets serviced by an OsCommandMemorySlave.

In the example flow:

  • OsMemMaster defines offsets/types for Uptime, SysLoad*, and FileTest.

  • MyCmdSlave (subclass of OsCommandMemorySlave) implements matching callbacks at those offsets. It can also expose extra commands such as CpuTempC at another address.

  • Variable reads/writes are executed as memory transactions through memBase=os_slave.

import pyrogue as pr
class OsMemMaster(pr.Device):
    def __init__(self, name='OsMemMaster', description='OS Memory Master Device', **kwargs):
        super().__init__(name=name, description=description, **kwargs)

        self.add(pr.RemoteVariable(
            name='Uptime',
            description='System Uptime In Seconds',
            offset=0x00,
            bitSize=32,
            base=pr.Float,
            mode='RO',
            pollInterval=1,
        ))

        self.add(pr.RemoteVariable(
            name='SysLoad1Min',
            description='1 Minute System Load',
            offset=0x04,
            bitSize=32,
            base=pr.Float,
            mode='RO',
            pollInterval=1,
        ))

        self.add(pr.RemoteVariable(
            name='SysLoad5Min',
            description='5 Minute System Load',
            offset=0x08,
            bitSize=32,
            base=pr.Float,
            mode='RO',
            pollInterval=1,
        ))

        self.add(pr.RemoteVariable(
            name='SysLoad15Min',
            description='15 Minute System Load',
            offset=0x0C,
            bitSize=32,
            base=pr.Float,
            mode='RO',
            pollInterval=1,
        ))

        self.add(pr.RemoteVariable(
            name='FileTest',
            description='File Read Write Test',
            offset=0x10,
            bitSize=32,
            base=pr.UInt,
            mode='RW',
        ))

        self.add(pr.RemoteVariable(
            name='CpuTempC',
            description='CPU Temperature In Degrees C (if available)',
            offset=0x14,
            bitSize=32,
            base=pr.Float,
            mode='RO',
            pollInterval=1,
        ))

class ExampleRoot(pr.Root):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        os_slave = MyCmdSlave()
        os_slave.setName('OsSlave')
        self.addInterface(os_slave)
        self.add(OsMemMaster(memBase=os_slave))

Operational Notes

  • Poll intervals on read-only variables drive periodic reads through memBase.

  • Address offsets and base Model types must match across the master and the command Slave.

  • This pattern is ideal for integration and prototyping work, not for high-rate paths.

API Reference