#!/usr/bin/env python3

import gi
gi.require_versions({'GLib': '2.0', 'Hinoko': '1.0'})
from gi.repository import GLib, Hinoko

from threading import Thread
from time import sleep

bytes_per_payload = (2 + 8 * 3) * 4
use_channel = 10
use_bandwidth = Hinoko.FwIsoResource.calculate_bandwidth(bytes_per_payload,
                                                         Hinoko.FwScode.S400)

ctx = GLib.MainContext.new()
dispatcher = GLib.MainLoop.new(ctx, False)
th = Thread(target=lambda d: d.run(), args=(dispatcher,))
th.start()

def handle_event(res, channel, bandwidth, exception, ev_name):
    print('event:', ev_name)
    if exception is None:
        print('  ', channel, bandwidth, res.get_property('generation'))
    elif exception.matches(Hinoko.fw_iso_resource_error_quark(), Hinoko.FwIsoResourceError.EVENT):
        print('  ', exception)

# For Once mode. The allocation is bound to current generation of the bus and
# lost automatically by bus reset without notification.
res = Hinoko.FwIsoResourceOnce.new()
res.open('/dev/fw0', 0)
res.connect('allocated', handle_event, 'allocated')
res.connect('deallocated', handle_event, 'deallocated')

_, src = res.create_source()
src.attach(ctx)

for i in range(2):
    try:
        res.allocate_wait((use_channel, ), use_bandwidth, 100)
    except GLib.Error as e:
        if e.matches(Hinoko.fw_iso_resource_error_quark(), Hinoko.FwIsoResourceError.EVENT):
            print(e)
    else:
        print('result: allocate')
        print('  ', use_channel, use_bandwidth, res.get_property('generation'))

    sleep(2)

    try:
        res.deallocate_wait(use_channel, use_bandwidth, 100)
    except GLib.Error as e:
        if e.matches(Hinoko.fw_iso_resource_error_quark(), Hinoko.FwIsoResourceError.EVENT):
            print(e)
    else:
        print('result: deallocate')
        print('  ', use_channel, use_bandwidth, res.get_property('generation'))

    sleep(2)

src.destroy()
del res

# For Auto mode. The allocation is kept by Linux FireWire subsystem as long as
# the lifetime of file descriptor. The instance of object represents state
# machine.
res = Hinoko.FwIsoResourceAuto.new()
res.open('/dev/fw0', 0)
res.connect('allocated', handle_event, 'allocated')
res.connect('deallocated', handle_event, 'deallocated')

_, src = res.create_source()
src.attach(ctx)

def print_props(res):
    for prop in ('is-allocated', 'channel', 'bandwidth', 'generation'):
        print('  {}: {}'.format(prop, res.get_property(prop)))

for i in range(2):
    print_props(res)

    try:
        res.allocate_wait([use_channel], use_bandwidth, 100)
    except GLib.Error as e:
        if e.matches(Hinoko.fw_iso_resource_error_quark(), Hinoko.FwIsoResourceError.EVENT):
            print(e)
    else:
        print('result: allocate')
        print_props(res)

    sleep(1)

    try:
        res.deallocate_wait(100)
    except GLib.Error as e:
        if e.matches(Hinoko.fw_iso_resource_error_quark(), Hinoko.FwIsoResourceError.EVENT):
            print(e)
    else:
        print('result: deallocate')
        print_props(res)

    sleep(1)

dispatcher.quit()
th.join()
