Skip to content

Pub/Sub

Note

Under construction.

A Publish / Subscribe mechanism for exchanging messages between applications. Provided as instance methods of FmrbApp.

Methods

Method Purpose
subscribe(topic) Start subscribing to a topic
unsubscribe(topic) Unsubscribe
publish(topic, data = nil) Send a message to a topic. data can be Hash / Array / number / String / nil
send_message(dest_pid, msg_type, data) Direct message to the kernel or a specific process (low-level)

data is automatically serialized to MessagePack internally (maximum 176 bytes).

Receive Handler

Topic messages are received in on_control(msg), not on_event(ev).

def on_control(msg)
  if msg["cmd"] == "topic_data" && msg["topic"] == "demo"
    payload = msg["data"]   # The content passed by the sender to publish
    # ...
  end
end
msg Key Description
"cmd" "topic_data" (when receiving a publish on a subscribed topic)
"topic" Topic name
"data" Payload passed by the publisher (Hash, etc.)

Note

subscribe, publish, unsubscribe, and send_message are syntactic sugar that send commands to the kernel via send_message(PROC_ID_KERNEL, MSG_TYPE_APP_CONTROL, ...). on_control is the entry point for all app control messages from the kernel, and Pub/Sub messages are routed through it.

Examples

Publisher

class PubDemo < FmrbApp
  TOPIC = "demo"

  def on_create
    @count = 0
    redraw
  end

  def on_event(ev)
    super
    if ev[:type] == :mouse_up && ev[:button] == 1
      @count += 1
      publish(TOPIC, {"msg" => "hello", "n" => @count})
      redraw
    end
  end

  def on_update; 100; end

  private

  def redraw
    clear_user_area(FmrbGfx::WHITE)
    @gfx.draw_text(@user_area_x0 + 4, @user_area_y0 + 4,
                   "Sent: #{@count}", FmrbGfx::BLACK)
    draw_window_frame
    @gfx.present
  end
end

PubDemo.new.start

Subscriber

class SubDemo < FmrbApp
  TOPIC = "demo"

  def on_create
    @last = ""
    subscribe(TOPIC)
    redraw
  end

  def on_control(msg)
    if msg["cmd"] == "topic_data" && msg["topic"] == TOPIC
      data = msg["data"]
      @last = "n=#{data["n"]} msg=#{data["msg"]}"
      redraw
    end
  end

  def on_destroy
    unsubscribe(TOPIC)
  end

  def on_update; 100; end

  private

  def redraw
    clear_user_area(FmrbGfx::WHITE)
    @gfx.draw_text(@user_area_x0 + 4, @user_area_y0 + 4, @last, FmrbGfx::BLACK)
    draw_window_frame
    @gfx.present
  end
end

SubDemo.new.start

/app/demo/pub_demo.app.rb and sub_demo.app.rb are a matching pair of samples that demonstrate this behavior.

Topic Design

Topic names are arbitrary strings. They work as long as the communicating apps agree on them. There are currently no widely-used reserved names in the project.

Recommended naming conventions:

  • Lowercase alphanumeric characters and underscores (e.g. "sensor_light")
  • Prefix app-specific messages with "<myapp>_<event>"
  • Document any public topics shared across multiple apps

Limitations

Item Value
Maximum payload size 176 bytes (after MessagePack serialization)
Types accepted for data Hash, Array, Integer, Float, String, Boolean, nil
Send timeout 5 seconds (kernel internal)

To send data larger than 176 bytes, write it to a file and publish only the file path, or split the data into multiple messages.

Difference from HID Events

Keyboard / mouse / gamepad input is delivered directly to on_event(ev) (routed by the kernel via MSG_TYPE_HID_EVENT). Do not confuse this with Pub/Sub.

Mechanism Receive Handler Use Case
HID Input on_event(ev) Physical user input
Pub/Sub on_control(msg) Arbitrary inter-app messages
Direct send on_control(msg) General kernel control messages

Direct Sending (send_message)

A low-level API for sending messages to the kernel or a specific app. subscribe and related methods are built on top of this.

send_message(FmrbConst::PROC_ID_KERNEL,
             FmrbConst::MSG_TYPE_APP_CONTROL,
             {"cmd" => "subscribe", "topic" => "foo"})
  • dest_pid: Destination process ID (FmrbConst::PROC_ID_*)
  • msg_type: Message type (MSG_TYPE_APP_CONTROL, etc.)
  • data: Any Ruby object (automatically serialized via MessagePack)