aboutsummaryrefslogtreecommitdiffstats
path: root/samples/iso-it
blob: 470626c5a94c58041c918ee111504146891397a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/env python3

from threading import Timer
from struct import unpack,pack

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

class IsoIt(Hinoko.FwIsoIt):
    def new(self, path, channel, maximum_bytes_per_payload, packets_per_buffer):
        # Use 8 byte header for CIP header.
        cip_header_size = 8
        self.cip_payload = [i for i in range(maximum_bytes_per_payload)]

        self.allocate(path, Hinoko.FwScode.S400, channel, cip_header_size)

        self.map_buffer(maximum_bytes_per_payload, packets_per_buffer)

        self.channel = channel
        self.packets_per_buffer = packets_per_buffer

    def destroy(self):
        self.unmap_buffer()
        self.release()

    def queue_packet(self, cip_header, cip_payload):
        self.accumulated_packet_count += 1
        if self.accumulated_packet_count % self.packets_per_interrupt == 0:
            schedule_interrupt = True
        else:
            schedule_interrupt = False
        self.register_packet(self.tag, self.sy, cip_header, cip_payload, schedule_interrupt)

    def begin(self, dispatcher, packets_per_interrupt, duration):
        _, self.__src = self.create_source()
        self.__src.attach(dispatcher.get_context())
        self.__dispatcher = dispatcher

        # Roughly finish event loop.
        self.__timer = Timer(duration, lambda dispatcher: dispatcher.quit(),
                             args=(dispatcher,))

        self.tag = Hinoko.FwIsoCtxMatchFlag.TAG1
        self.sy = 0

        # Start 100 msec later. Scheduling is available with lower 2 bits of second field.
        cycle_time = Hinawa.CycleTime.new()
        clock_id = 4    # CLOCK_MONOTONIC_RAW
        _, cycle_time = self.read_cycle_time(clock_id, cycle_time)
        (sec, cycle, tick) = cycle_time.get_fields()
        sec, cycle = self.__increment_cycle(sec, cycle, 800)
        cycle_match = (sec & 0x3, cycle)

        self.accumulated_packet_count = 0
        self.packets_per_interrupt = packets_per_interrupt

        # Schedule some isochronous cycles to skip.
        for i in range(packets_per_interrupt * 2):
            self.queue_packet(None, None)

        self.__timer.start()
        self.start(cycle_match)

    @staticmethod
    def __increment_cycle(sec, cycle, addend):
        cycle += addend
        if cycle >= 8000:
            cycle %= 8000
            sec += 1
            if sec >= 128:
                sec %= 128
        return (sec, cycle)

    def finish(self):
        self.__src.destroy()
        self.stop()

    def do_stopped(self, error):
        self.__dispatcher.quit()
        if error:
            self.__timer.cancel()
            print(error)

    @staticmethod
    def __ohci1394_tstamp_to_isoc_cycle(tstamp):
        sec = (tstamp & 0x0000e000) >> 13
        cycle = tstamp & 0x00001fff
        return (sec, cycle)

    def do_interrupted(self, sec, cycle, header, header_length, count):
        tstamps = unpack('>{0}I'.format(header_length // 4), header)
        for i in range(count):
            sec, cycle = self.__ohci1394_tstamp_to_isoc_cycle(tstamps[i])

            # Schedule packet at the completed isochronous cycle plus packets per buffer. The header
            # of packet has data for the completed isochronous cycle.
            next_sec, next_cycle = self.__increment_cycle(sec, cycle, self.packets_per_buffer)
            cip_header = pack('>2I', next_sec, next_cycle)
            self.queue_packet(cip_header, self.cip_payload)

            # Print the data of packet already sent.
            iso_header = (len(self.cip_payload) << 16) | \
                         (self.tag << 14) | \
                         (self.channel << 8) | \
                         (0xa << 4) | \
                         self.sy
            print('{0:2d},{1:4d},{2:08x},{3}'.format(sec, cycle, iso_header, i))

channel = 30
maximum_bytes_per_payload = 32
packets_per_buffer = 32
packets_per_interrupt = 4
duration = 4

ctx = IsoIt()
ctx.new('/dev/fw0', channel, maximum_bytes_per_payload, packets_per_buffer)

dispatcher = GLib.MainLoop.new(None, False)

ctx.begin(dispatcher, packets_per_interrupt, duration)
dispatcher.run()
ctx.finish()
ctx.destroy()

del dispatcher
del ctx