Index: ammosreader/AmmosGlobalFrameHeader.py
===================================================================
--- ammosreader/AmmosGlobalFrameHeader.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ ammosreader/AmmosGlobalFrameHeader.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -1,8 +1,5 @@
 """I provide an AMMOS global frame header."""
 import struct
-import logging
-
-logging.basicConfig(filename='ammos.log', level=logging.DEBUG)
-
+from ammosreader import logger
 
 class AmmosGlobalFrameHeader:
@@ -21,4 +18,5 @@
         magic_word = elements[0].hex()
 
+        logger.debug("Header created")
         if magic_word != cls.MAGIC_WORD:
             return None
@@ -40,5 +38,5 @@
         """I return a new instance of myself initialized with above parameters."""
         if magic_word != type(self).MAGIC_WORD:
-            logging.error("Wrong magic word found")
+            logger.error("Wrong magic word found")
             self.magic_word = magic_word
         else:
Index: ammosreader/PDW.py
===================================================================
--- ammosreader/PDW.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ ammosreader/PDW.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -4,5 +4,5 @@
 import math
 import numpy as np
-
+from ammosreader import logger
 
 class PDW():
@@ -24,8 +24,16 @@
         :rtype: PDW
         """
-        assert(len(byte_string) == 32)
+
+        logger.info("from bytes")
+        if (len(byte_string) != 32):
+            logger.error("Byte count invalid")
+            raise TypeError("Byte count invalid")
 
         parts = struct.unpack('<Q4s4s4s4s4s4s', byte_string)
+
         nanoseconds = (parts[0])
+        unix_time = np.datetime64('now', 'ns').astype(int)
+        if nanoseconds >= unix_time:
+            raise OverflowError("Timestamp invalid")
         time_of_arrival = np.datetime64(nanoseconds, 'ns')
 
@@ -61,5 +69,5 @@
         modulations = {0: 'Unknown', 1: 'Unmodulated', 2: 'FM', 3: 'LFM', 4: 'PSK-2', 5: 'PSK-3', 6: 'PSK-4',
                        7: 'PSK-m', 8: 'NLFM', 9: 'SFM', 10: 'TFM', 11: 'Pulse too short'}
-        modulation = modulations[int(sixth_entry_bit_string[7:12], 2)]
+        modulation = modulations.get(int(sixth_entry_bit_string[7:12], 2), 0)
         sector = int(sixth_entry_bit_string[28:32], 2)
 
Index: ammosreader/__init__.py
===================================================================
--- ammosreader/__init__.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ ammosreader/__init__.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,29 @@
+import logging
+import logging.config
+import os
+from pathlib import Path
+
+# change the default log path to /var/log/ammos/ammos.log when system configuration created this dir
+# with the appropriate rights
+
+log_dir = Path(os.environ.get('AMMOS_LOG_DIR', '/tmp/'))
+
+log_path = log_dir / 'ammos.log'
+
+if not log_path.exists():
+#   print(log_path, "does not exist")
+    try:
+#       print("Trying to create logfile", str(log_path))
+        log_path.touch()
+    except PermissionError:
+#       print("Logging to file disabled")
+        conf_file = Path(__file__).parent / 'ammos_logging.conf'
+        print("Conf file", conf_file)
+        logging.config.fileConfig(conf_file)
+else:
+#   print("Logging to", str(log_path))
+    logging.basicConfig(filename=str(log_path), encoding='utf-8', level=logging.DEBUG)
+
+logger = logging.getLogger(__name__)
+
+logger.warning("Text")
Index: ammosreader/ammos_logging.conf
===================================================================
--- ammosreader/ammos_logging.conf	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ ammosreader/ammos_logging.conf	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,21 @@
+[loggers]
+keys=root
+
+[handlers]
+keys=stream_handler
+
+[formatters]
+keys=formatter
+
+[logger_root]
+level=DEBUG
+handlers=stream_handler
+
+[handler_stream_handler]
+class=StreamHandler
+level=DEBUG
+formatter=formatter
+args=(sys.stderr,)
+
+[formatter_formatter]
+format=%(asctime)s %(name)-12s %(levelname)-8s %(message)s
Index: doc/ammosreader/AbstractAmmosReader.html
===================================================================
--- doc/ammosreader/AbstractAmmosReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AbstractAmmosReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,648 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AbstractAmmosReader API documentation</title>
+<meta name="description" content="I provide a base class for specialized AmmosReaders." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AbstractAmmosReader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide a base class for specialized AmmosReaders.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide a base class for specialized AmmosReaders.&#34;&#34;&#34;
+import logging
+
+from abc import ABC, abstractmethod
+
+from ammosreader.AmmosGlobalFrameHeader import AmmosGlobalFrameHeader
+from ammosreader.AmmosSingleFrame import AmmosSingleFrame
+from ammosreader.AmmosContainer import AmmosContainer
+from ammosreader.AmmosConstants import FrameType
+
+logging.basicConfig(filename=&#39;ammos.log&#39;, level=logging.DEBUG)
+
+
+class AbstractAmmosReader(ABC):
+    &#34;&#34;&#34;I implement a base class for specialized AmmosReaders.&#34;&#34;&#34;
+
+    def __init__(self, file_name):
+        &#34;&#34;&#34;
+        I am the standard constructor for Ammos Readers.
+
+        Additional information about the file can be added as key/value pairs in tags
+
+        :param file_name: The file to read Ammos data from
+        :type file_name: str
+        &#34;&#34;&#34;
+        self.__file_name = file_name
+        self.__ammos_file = open(self.file_name, &#34;rb&#34;)
+        self.__container = AmmosContainer(self.file_name, [])
+        self.__tags = {}
+
+    @property
+    def file_name(self):
+        &#34;&#34;&#34;I return the name of the original file.&#34;&#34;&#34;
+        return self.__file_name
+
+    @property
+    def ammos_file(self):
+        &#34;&#34;&#34;I return the file to read the data from.&#34;&#34;&#34;
+        return self.__ammos_file
+
+    @property
+    def container(self):
+        &#34;&#34;&#34;I return the container which stores the data read.&#34;&#34;&#34;
+        return self.__container
+
+    @property
+    def tags(self):
+        &#34;&#34;&#34;I return all the tags.&#34;&#34;&#34;
+        return self.__tags
+
+    def add_tag(self, a_key, a_value):
+        &#34;&#34;&#34;I add information to tags using a key/value pair.&#34;&#34;&#34;
+        assert a_key not in self.__tags
+        self.__tags[a_key] = a_value
+
+    def rewind_to_start(self):
+        &#34;&#34;&#34;I set the file pointer to the beginning of the file for the next operation.&#34;&#34;&#34;
+        self.ammos_file.seek(0)
+
+    def read_all_frames_left(self):
+        &#34;&#34;&#34;
+        I read all remaining frames into my container until end of file is reached.
+
+        :return: a container containing all frames read
+        :rtype: AmmosContainer
+        &#34;&#34;&#34;
+        frames_read = 0
+        while True:
+            logging.info(&#34;Reading single frame %s ...&#34;, frames_read)
+            current_frame = self.read_next_single_frame()
+            if current_frame is not None:
+                frames_read += 1
+                self.container.add_frame(current_frame)
+            else:
+                logging.debug(&#34;Frame: %s incomplete&#34;, frames_read+1)
+                break
+        logging.info(&#34;%s frames read&#34;, len(self.container.global_frames))
+        return self.container
+
+    def read_next_global_frame_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame header read from current position in file.
+
+        :return: the next global frame header or None if incomplete
+        :rtype: AmmosGlobalFrameHeader
+        &#34;&#34;&#34;
+        header_size = AmmosGlobalFrameHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+        logging.info(&#34;Reading next global frame header&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame header&#34;, header_size)
+            return None
+
+        current_global_frame_header = AmmosGlobalFrameHeader.from_bytes(bytes)
+
+        if current_global_frame_header is None:
+            return None
+
+        # logging.info(&#34;Current global frame header %s&#34;, current_global_frame_header)
+        return current_global_frame_header
+
+    @abstractmethod
+    def read_next_global_frame_body(self, data_header_length):
+        &#34;&#34;&#34;My descendents have to implement this.&#34;&#34;&#34;
+        pass
+
+    def read_next_single_frame(self):
+        &#34;&#34;&#34;
+        I read and return a single global frame.
+
+        :return: a single global frame
+        :rtype: AmmosSingleFrame
+        &#34;&#34;&#34;
+        global_frame_header = self.read_next_global_frame_header()
+
+        if global_frame_header is None:
+            return None
+
+        if global_frame_header is None:
+            logging.debug(&#34;Global frame header missing&#34;)
+            return None
+
+        if global_frame_header.data_header_length is None:
+            logging.debug(&#34;Data header length empty&#34;)
+            return None
+
+        if global_frame_header.frame_type not in list(FrameType):
+            logging.info(&#34;Unknown frame type %s found&#34;, global_frame_header.frame_type)
+            return None
+
+        # FIXME: Refactor duplicate logic - This code stinks
+
+        global_frame_body = None
+
+        if_data_types = [FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT.value,
+                         FrameType.IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT.value,
+                         FrameType.IF_DATA_16BIT_REAL_REAL.value,
+                         FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED.value,
+                         FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED.value]
+
+        if global_frame_header.frame_type == FrameType.AUDIO_DATA.value:
+            logging.info(&#34;Audio Datastream found&#34;)
+            global_frame_body = self.read_next_global_frame_body(global_frame_header.data_header_length)
+            if global_frame_body is None:
+                return None
+            return AmmosSingleFrame(global_frame_header, global_frame_body)
+
+        if global_frame_header.frame_type in if_data_types:
+            logging.info(&#34;IF Datastream found&#34;)
+            global_frame_body = self.read_next_global_frame_body(global_frame_header.data_header_length)
+            if global_frame_body is None:
+                return None
+            return AmmosSingleFrame(global_frame_header, global_frame_body)
+
+        if global_frame_body is None:
+            return None
+
+        logging.info(&#34;Unsupported frame type %s found&#34;, global_frame_header.frame_type)
+        return None</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader"><code class="flex name class">
+<span>class <span class="ident">AbstractAmmosReader</span></span>
+<span>(</span><span>file_name)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement a base class for specialized AmmosReaders.</p>
+<p>I am the standard constructor for Ammos Readers.</p>
+<p>Additional information about the file can be added as key/value pairs in tags</p>
+<p>:param file_name: The file to read Ammos data from
+:type file_name: str</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AbstractAmmosReader(ABC):
+    &#34;&#34;&#34;I implement a base class for specialized AmmosReaders.&#34;&#34;&#34;
+
+    def __init__(self, file_name):
+        &#34;&#34;&#34;
+        I am the standard constructor for Ammos Readers.
+
+        Additional information about the file can be added as key/value pairs in tags
+
+        :param file_name: The file to read Ammos data from
+        :type file_name: str
+        &#34;&#34;&#34;
+        self.__file_name = file_name
+        self.__ammos_file = open(self.file_name, &#34;rb&#34;)
+        self.__container = AmmosContainer(self.file_name, [])
+        self.__tags = {}
+
+    @property
+    def file_name(self):
+        &#34;&#34;&#34;I return the name of the original file.&#34;&#34;&#34;
+        return self.__file_name
+
+    @property
+    def ammos_file(self):
+        &#34;&#34;&#34;I return the file to read the data from.&#34;&#34;&#34;
+        return self.__ammos_file
+
+    @property
+    def container(self):
+        &#34;&#34;&#34;I return the container which stores the data read.&#34;&#34;&#34;
+        return self.__container
+
+    @property
+    def tags(self):
+        &#34;&#34;&#34;I return all the tags.&#34;&#34;&#34;
+        return self.__tags
+
+    def add_tag(self, a_key, a_value):
+        &#34;&#34;&#34;I add information to tags using a key/value pair.&#34;&#34;&#34;
+        assert a_key not in self.__tags
+        self.__tags[a_key] = a_value
+
+    def rewind_to_start(self):
+        &#34;&#34;&#34;I set the file pointer to the beginning of the file for the next operation.&#34;&#34;&#34;
+        self.ammos_file.seek(0)
+
+    def read_all_frames_left(self):
+        &#34;&#34;&#34;
+        I read all remaining frames into my container until end of file is reached.
+
+        :return: a container containing all frames read
+        :rtype: AmmosContainer
+        &#34;&#34;&#34;
+        frames_read = 0
+        while True:
+            logging.info(&#34;Reading single frame %s ...&#34;, frames_read)
+            current_frame = self.read_next_single_frame()
+            if current_frame is not None:
+                frames_read += 1
+                self.container.add_frame(current_frame)
+            else:
+                logging.debug(&#34;Frame: %s incomplete&#34;, frames_read+1)
+                break
+        logging.info(&#34;%s frames read&#34;, len(self.container.global_frames))
+        return self.container
+
+    def read_next_global_frame_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame header read from current position in file.
+
+        :return: the next global frame header or None if incomplete
+        :rtype: AmmosGlobalFrameHeader
+        &#34;&#34;&#34;
+        header_size = AmmosGlobalFrameHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+        logging.info(&#34;Reading next global frame header&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame header&#34;, header_size)
+            return None
+
+        current_global_frame_header = AmmosGlobalFrameHeader.from_bytes(bytes)
+
+        if current_global_frame_header is None:
+            return None
+
+        # logging.info(&#34;Current global frame header %s&#34;, current_global_frame_header)
+        return current_global_frame_header
+
+    @abstractmethod
+    def read_next_global_frame_body(self, data_header_length):
+        &#34;&#34;&#34;My descendents have to implement this.&#34;&#34;&#34;
+        pass
+
+    def read_next_single_frame(self):
+        &#34;&#34;&#34;
+        I read and return a single global frame.
+
+        :return: a single global frame
+        :rtype: AmmosSingleFrame
+        &#34;&#34;&#34;
+        global_frame_header = self.read_next_global_frame_header()
+
+        if global_frame_header is None:
+            return None
+
+        if global_frame_header is None:
+            logging.debug(&#34;Global frame header missing&#34;)
+            return None
+
+        if global_frame_header.data_header_length is None:
+            logging.debug(&#34;Data header length empty&#34;)
+            return None
+
+        if global_frame_header.frame_type not in list(FrameType):
+            logging.info(&#34;Unknown frame type %s found&#34;, global_frame_header.frame_type)
+            return None
+
+        # FIXME: Refactor duplicate logic - This code stinks
+
+        global_frame_body = None
+
+        if_data_types = [FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT.value,
+                         FrameType.IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT.value,
+                         FrameType.IF_DATA_16BIT_REAL_REAL.value,
+                         FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED.value,
+                         FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED.value]
+
+        if global_frame_header.frame_type == FrameType.AUDIO_DATA.value:
+            logging.info(&#34;Audio Datastream found&#34;)
+            global_frame_body = self.read_next_global_frame_body(global_frame_header.data_header_length)
+            if global_frame_body is None:
+                return None
+            return AmmosSingleFrame(global_frame_header, global_frame_body)
+
+        if global_frame_header.frame_type in if_data_types:
+            logging.info(&#34;IF Datastream found&#34;)
+            global_frame_body = self.read_next_global_frame_body(global_frame_header.data_header_length)
+            if global_frame_body is None:
+                return None
+            return AmmosSingleFrame(global_frame_header, global_frame_body)
+
+        if global_frame_body is None:
+            return None
+
+        logging.info(&#34;Unsupported frame type %s found&#34;, global_frame_header.frame_type)
+        return None</code></pre>
+</details>
+<h3>Ancestors</h3>
+<ul class="hlist">
+<li>abc.ABC</li>
+</ul>
+<h3>Subclasses</h3>
+<ul class="hlist">
+<li><a title="ammosreader.AmmosAudioReader.AmmosAudioReader" href="AmmosAudioReader.html#ammosreader.AmmosAudioReader.AmmosAudioReader">AmmosAudioReader</a></li>
+<li><a title="ammosreader.AmmosIFReader.AmmosIFReader" href="AmmosIFReader.html#ammosreader.AmmosIFReader.AmmosIFReader">AmmosIFReader</a></li>
+</ul>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file"><code class="name">var <span class="ident">ammos_file</span></code></dt>
+<dd>
+<div class="desc"><p>I return the file to read the data from.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def ammos_file(self):
+    &#34;&#34;&#34;I return the file to read the data from.&#34;&#34;&#34;
+    return self.__ammos_file</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.container"><code class="name">var <span class="ident">container</span></code></dt>
+<dd>
+<div class="desc"><p>I return the container which stores the data read.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def container(self):
+    &#34;&#34;&#34;I return the container which stores the data read.&#34;&#34;&#34;
+    return self.__container</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name"><code class="name">var <span class="ident">file_name</span></code></dt>
+<dd>
+<div class="desc"><p>I return the name of the original file.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def file_name(self):
+    &#34;&#34;&#34;I return the name of the original file.&#34;&#34;&#34;
+    return self.__file_name</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags"><code class="name">var <span class="ident">tags</span></code></dt>
+<dd>
+<div class="desc"><p>I return all the tags.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def tags(self):
+    &#34;&#34;&#34;I return all the tags.&#34;&#34;&#34;
+    return self.__tags</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag"><code class="name flex">
+<span>def <span class="ident">add_tag</span></span>(<span>self, a_key, a_value)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I add information to tags using a key/value pair.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def add_tag(self, a_key, a_value):
+    &#34;&#34;&#34;I add information to tags using a key/value pair.&#34;&#34;&#34;
+    assert a_key not in self.__tags
+    self.__tags[a_key] = a_value</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left"><code class="name flex">
+<span>def <span class="ident">read_all_frames_left</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I read all remaining frames into my container until end of file is reached.</p>
+<p>:return: a container containing all frames read
+:rtype: AmmosContainer</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_all_frames_left(self):
+    &#34;&#34;&#34;
+    I read all remaining frames into my container until end of file is reached.
+
+    :return: a container containing all frames read
+    :rtype: AmmosContainer
+    &#34;&#34;&#34;
+    frames_read = 0
+    while True:
+        logging.info(&#34;Reading single frame %s ...&#34;, frames_read)
+        current_frame = self.read_next_single_frame()
+        if current_frame is not None:
+            frames_read += 1
+            self.container.add_frame(current_frame)
+        else:
+            logging.debug(&#34;Frame: %s incomplete&#34;, frames_read+1)
+            break
+    logging.info(&#34;%s frames read&#34;, len(self.container.global_frames))
+    return self.container</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_body"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body</span></span>(<span>self, data_header_length)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>My descendents have to implement this.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@abstractmethod
+def read_next_global_frame_body(self, data_header_length):
+    &#34;&#34;&#34;My descendents have to implement this.&#34;&#34;&#34;
+    pass</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_header</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next global frame header read from current position in file.</p>
+<p>:return: the next global frame header or None if incomplete
+:rtype: AmmosGlobalFrameHeader</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_header(self):
+    &#34;&#34;&#34;
+    I return the next global frame header read from current position in file.
+
+    :return: the next global frame header or None if incomplete
+    :rtype: AmmosGlobalFrameHeader
+    &#34;&#34;&#34;
+    header_size = AmmosGlobalFrameHeader.HEADER_SIZE
+
+    bytes = self.ammos_file.read(header_size)
+    logging.info(&#34;Reading next global frame header&#34;)
+    if ((not bytes) or (len(bytes) &lt; header_size)):
+        logging.debug(&#34;Can not read all %s bytes of global frame header&#34;, header_size)
+        return None
+
+    current_global_frame_header = AmmosGlobalFrameHeader.from_bytes(bytes)
+
+    if current_global_frame_header is None:
+        return None
+
+    # logging.info(&#34;Current global frame header %s&#34;, current_global_frame_header)
+    return current_global_frame_header</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame"><code class="name flex">
+<span>def <span class="ident">read_next_single_frame</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I read and return a single global frame.</p>
+<p>:return: a single global frame
+:rtype: AmmosSingleFrame</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_single_frame(self):
+    &#34;&#34;&#34;
+    I read and return a single global frame.
+
+    :return: a single global frame
+    :rtype: AmmosSingleFrame
+    &#34;&#34;&#34;
+    global_frame_header = self.read_next_global_frame_header()
+
+    if global_frame_header is None:
+        return None
+
+    if global_frame_header is None:
+        logging.debug(&#34;Global frame header missing&#34;)
+        return None
+
+    if global_frame_header.data_header_length is None:
+        logging.debug(&#34;Data header length empty&#34;)
+        return None
+
+    if global_frame_header.frame_type not in list(FrameType):
+        logging.info(&#34;Unknown frame type %s found&#34;, global_frame_header.frame_type)
+        return None
+
+    # FIXME: Refactor duplicate logic - This code stinks
+
+    global_frame_body = None
+
+    if_data_types = [FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT.value,
+                     FrameType.IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT.value,
+                     FrameType.IF_DATA_16BIT_REAL_REAL.value,
+                     FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED.value,
+                     FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED.value]
+
+    if global_frame_header.frame_type == FrameType.AUDIO_DATA.value:
+        logging.info(&#34;Audio Datastream found&#34;)
+        global_frame_body = self.read_next_global_frame_body(global_frame_header.data_header_length)
+        if global_frame_body is None:
+            return None
+        return AmmosSingleFrame(global_frame_header, global_frame_body)
+
+    if global_frame_header.frame_type in if_data_types:
+        logging.info(&#34;IF Datastream found&#34;)
+        global_frame_body = self.read_next_global_frame_body(global_frame_header.data_header_length)
+        if global_frame_body is None:
+            return None
+        return AmmosSingleFrame(global_frame_header, global_frame_body)
+
+    if global_frame_body is None:
+        return None
+
+    logging.info(&#34;Unsupported frame type %s found&#34;, global_frame_header.frame_type)
+    return None</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start"><code class="name flex">
+<span>def <span class="ident">rewind_to_start</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I set the file pointer to the beginning of the file for the next operation.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def rewind_to_start(self):
+    &#34;&#34;&#34;I set the file pointer to the beginning of the file for the next operation.&#34;&#34;&#34;
+    self.ammos_file.seek(0)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader">AbstractAmmosReader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag">add_tag</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file">ammos_file</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.container" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.container">container</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name">file_name</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left">read_all_frames_left</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_body" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_body">read_next_global_frame_body</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header">read_next_global_frame_header</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame">read_next_single_frame</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start">rewind_to_start</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags" href="#ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags">tags</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosAudioDataBody.html
===================================================================
--- doc/ammosreader/AmmosAudioDataBody.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosAudioDataBody.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,190 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosAudioDataBody API documentation</title>
+<meta name="description" content="I provide an AMMOS data block for audio data frames." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosAudioDataBody</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide an AMMOS data block for audio data frames.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide an AMMOS data block for audio data frames.&#34;&#34;&#34;
+
+
+class AmmosAudioDataBody:
+    &#34;&#34;&#34;I implement an AMMOS data block for audio data frames.&#34;&#34;&#34;
+
+    def __init__(self, pcm_data, number_of_channels=1, samples_per_channel=1, sample_size=1):
+        &#34;&#34;&#34;I return a new AMMOS data block for audio data frames.&#34;&#34;&#34;
+        self.__number_of_channels = number_of_channels
+        self.__samples_per_channel = samples_per_channel
+        self.__sample_size = sample_size
+        self.__payload = pcm_data
+
+    @property
+    def payload(self):
+        &#34;&#34;&#34;I return the raw pcm data with channels interweaved.&#34;&#34;&#34;
+        return self.__payload
+
+    def pcm_for_channel(self, channel_number):
+        &#34;&#34;&#34;I return the raw pcm data for a given channel.&#34;&#34;&#34;
+        start_offset = channel_number * self.__sample_size
+        step = self.__sample_size * self.__number_of_channels
+        end = (len(self.__payload) // step) * step
+        channel_bytes = b&#34;&#34;
+        for each in range(start_offset, end, step):
+            channel_bytes += self.__payload[each:each+self.__sample_size]
+        return channel_bytes
+
+    def __str__(self):
+        &#34;&#34;&#34;I return the string representation of myself.&#34;&#34;&#34;
+        return (&#34;Number of channels:&#34; + str(self.__number_of_channels) +
+                &#34;\nSamples per channel:&#34; + str(self.__samples_per_channel) +
+                &#34;\nSample size:&#34; + str(self.__sample_size) +
+                &#34;\nData size:&#34; + str(len(self.__payload)))</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosAudioDataBody.AmmosAudioDataBody"><code class="flex name class">
+<span>class <span class="ident">AmmosAudioDataBody</span></span>
+<span>(</span><span>pcm_data, number_of_channels=1, samples_per_channel=1, sample_size=1)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an AMMOS data block for audio data frames.</p>
+<p>I return a new AMMOS data block for audio data frames.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosAudioDataBody:
+    &#34;&#34;&#34;I implement an AMMOS data block for audio data frames.&#34;&#34;&#34;
+
+    def __init__(self, pcm_data, number_of_channels=1, samples_per_channel=1, sample_size=1):
+        &#34;&#34;&#34;I return a new AMMOS data block for audio data frames.&#34;&#34;&#34;
+        self.__number_of_channels = number_of_channels
+        self.__samples_per_channel = samples_per_channel
+        self.__sample_size = sample_size
+        self.__payload = pcm_data
+
+    @property
+    def payload(self):
+        &#34;&#34;&#34;I return the raw pcm data with channels interweaved.&#34;&#34;&#34;
+        return self.__payload
+
+    def pcm_for_channel(self, channel_number):
+        &#34;&#34;&#34;I return the raw pcm data for a given channel.&#34;&#34;&#34;
+        start_offset = channel_number * self.__sample_size
+        step = self.__sample_size * self.__number_of_channels
+        end = (len(self.__payload) // step) * step
+        channel_bytes = b&#34;&#34;
+        for each in range(start_offset, end, step):
+            channel_bytes += self.__payload[each:each+self.__sample_size]
+        return channel_bytes
+
+    def __str__(self):
+        &#34;&#34;&#34;I return the string representation of myself.&#34;&#34;&#34;
+        return (&#34;Number of channels:&#34; + str(self.__number_of_channels) +
+                &#34;\nSamples per channel:&#34; + str(self.__samples_per_channel) +
+                &#34;\nSample size:&#34; + str(self.__sample_size) +
+                &#34;\nData size:&#34; + str(len(self.__payload)))</code></pre>
+</details>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosAudioDataBody.AmmosAudioDataBody.payload"><code class="name">var <span class="ident">payload</span></code></dt>
+<dd>
+<div class="desc"><p>I return the raw pcm data with channels interweaved.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def payload(self):
+    &#34;&#34;&#34;I return the raw pcm data with channels interweaved.&#34;&#34;&#34;
+    return self.__payload</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosAudioDataBody.AmmosAudioDataBody.pcm_for_channel"><code class="name flex">
+<span>def <span class="ident">pcm_for_channel</span></span>(<span>self, channel_number)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the raw pcm data for a given channel.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def pcm_for_channel(self, channel_number):
+    &#34;&#34;&#34;I return the raw pcm data for a given channel.&#34;&#34;&#34;
+    start_offset = channel_number * self.__sample_size
+    step = self.__sample_size * self.__number_of_channels
+    end = (len(self.__payload) // step) * step
+    channel_bytes = b&#34;&#34;
+    for each in range(start_offset, end, step):
+        channel_bytes += self.__payload[each:each+self.__sample_size]
+    return channel_bytes</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosAudioDataBody.AmmosAudioDataBody" href="#ammosreader.AmmosAudioDataBody.AmmosAudioDataBody">AmmosAudioDataBody</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosAudioDataBody.AmmosAudioDataBody.payload" href="#ammosreader.AmmosAudioDataBody.AmmosAudioDataBody.payload">payload</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioDataBody.AmmosAudioDataBody.pcm_for_channel" href="#ammosreader.AmmosAudioDataBody.AmmosAudioDataBody.pcm_for_channel">pcm_for_channel</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosAudioDataHeader.html
===================================================================
--- doc/ammosreader/AmmosAudioDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosAudioDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,216 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosAudioDataHeader API documentation</title>
+<meta name="description" content="I provide an AMMOS data header for audio data frames." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosAudioDataHeader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide an AMMOS data header for audio data frames.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide an AMMOS data header for audio data frames.&#34;&#34;&#34;
+
+import struct
+from ammosreader.AmmosConstants import AmmosAudioDemodType
+
+
+class AmmosAudioDataHeader:
+    &#34;&#34;&#34;I implement an AMMOS data header for audio data frames.&#34;&#34;&#34;
+
+    HEADER_SIZE = 36  # 9 words
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS data header from given bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        elements = struct.unpack(&#39;&lt;IIQIIIII&#39;, bytes)
+        sample_rate = elements[0]
+        status = elements[1]
+        frequency = elements[2]
+        demod_bandwidth = elements[3]
+        demod_type = AmmosAudioDemodType(elements[4])
+        number_of_samples = elements[5]
+        number_of_channels = elements[6]
+        sample_size = elements[7]
+        return AmmosAudioDataHeader(sample_rate, status, frequency, demod_bandwidth, demod_type,
+                                    number_of_samples, number_of_channels, sample_size)
+
+    def __init__(self, sample_rate, status, frequency, demod_bandwidth, demod_type, number_of_samples,
+                 number_of_channels, sample_size):
+        &#34;&#34;&#34;I create a new instance of myself using the above parameters.&#34;&#34;&#34;
+        self.sample_rate = sample_rate
+        self.status = status
+        self.frequency = frequency
+        self.demod_bandwidth = demod_bandwidth
+        self.demod_type = AmmosAudioDemodType(demod_type)
+        self.number_of_samples = number_of_samples
+        self.number_of_channels = number_of_channels
+        self.sample_size = sample_size
+
+    def __str__(self):
+        &#34;&#34;&#34;I return the string representation of myself.&#34;&#34;&#34;
+        return (&#34;\nAmmosAudioDataHeader\n&#34; +
+                &#34;Sample rate:&#34; + str(self.sample_rate) + &#34;\n&#34; +
+                &#34;Status:&#34; + str(self.status) + &#34;\n&#34; +
+                &#34;Frequency:&#34; + str(self.frequency) + &#34;\n&#34; +
+                &#34;Demodulation bandwidth:&#34; + str(self.demod_bandwidth) + &#34;\n&#34; +
+                &#34;Demodulation type:&#34; + str(self.demod_type) + &#34;\n&#34; +
+                &#34;Sample count:&#34; + str(self.number_of_samples) + &#34;\n&#34; +
+                &#34;Channel count:&#34; + str(self.number_of_channels) + &#34;\n&#34; +
+                &#34;Sample size:&#34; + str(self.sample_size) + &#34;\n&#34;)</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader"><code class="flex name class">
+<span>class <span class="ident">AmmosAudioDataHeader</span></span>
+<span>(</span><span>sample_rate, status, frequency, demod_bandwidth, demod_type, number_of_samples, number_of_channels, sample_size)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an AMMOS data header for audio data frames.</p>
+<p>I create a new instance of myself using the above parameters.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosAudioDataHeader:
+    &#34;&#34;&#34;I implement an AMMOS data header for audio data frames.&#34;&#34;&#34;
+
+    HEADER_SIZE = 36  # 9 words
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS data header from given bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        elements = struct.unpack(&#39;&lt;IIQIIIII&#39;, bytes)
+        sample_rate = elements[0]
+        status = elements[1]
+        frequency = elements[2]
+        demod_bandwidth = elements[3]
+        demod_type = AmmosAudioDemodType(elements[4])
+        number_of_samples = elements[5]
+        number_of_channels = elements[6]
+        sample_size = elements[7]
+        return AmmosAudioDataHeader(sample_rate, status, frequency, demod_bandwidth, demod_type,
+                                    number_of_samples, number_of_channels, sample_size)
+
+    def __init__(self, sample_rate, status, frequency, demod_bandwidth, demod_type, number_of_samples,
+                 number_of_channels, sample_size):
+        &#34;&#34;&#34;I create a new instance of myself using the above parameters.&#34;&#34;&#34;
+        self.sample_rate = sample_rate
+        self.status = status
+        self.frequency = frequency
+        self.demod_bandwidth = demod_bandwidth
+        self.demod_type = AmmosAudioDemodType(demod_type)
+        self.number_of_samples = number_of_samples
+        self.number_of_channels = number_of_channels
+        self.sample_size = sample_size
+
+    def __str__(self):
+        &#34;&#34;&#34;I return the string representation of myself.&#34;&#34;&#34;
+        return (&#34;\nAmmosAudioDataHeader\n&#34; +
+                &#34;Sample rate:&#34; + str(self.sample_rate) + &#34;\n&#34; +
+                &#34;Status:&#34; + str(self.status) + &#34;\n&#34; +
+                &#34;Frequency:&#34; + str(self.frequency) + &#34;\n&#34; +
+                &#34;Demodulation bandwidth:&#34; + str(self.demod_bandwidth) + &#34;\n&#34; +
+                &#34;Demodulation type:&#34; + str(self.demod_type) + &#34;\n&#34; +
+                &#34;Sample count:&#34; + str(self.number_of_samples) + &#34;\n&#34; +
+                &#34;Channel count:&#34; + str(self.number_of_channels) + &#34;\n&#34; +
+                &#34;Sample size:&#34; + str(self.sample_size) + &#34;\n&#34;)</code></pre>
+</details>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader.HEADER_SIZE"><code class="name">var <span class="ident">HEADER_SIZE</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>bytes)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return an AMMOS data header from given bytes.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, bytes):
+    &#34;&#34;&#34;I return an AMMOS data header from given bytes.&#34;&#34;&#34;
+    assert len(bytes) == cls.HEADER_SIZE
+    elements = struct.unpack(&#39;&lt;IIQIIIII&#39;, bytes)
+    sample_rate = elements[0]
+    status = elements[1]
+    frequency = elements[2]
+    demod_bandwidth = elements[3]
+    demod_type = AmmosAudioDemodType(elements[4])
+    number_of_samples = elements[5]
+    number_of_channels = elements[6]
+    sample_size = elements[7]
+    return AmmosAudioDataHeader(sample_rate, status, frequency, demod_bandwidth, demod_type,
+                                number_of_samples, number_of_channels, sample_size)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader" href="#ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader">AmmosAudioDataHeader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader.HEADER_SIZE" href="#ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader.HEADER_SIZE">HEADER_SIZE</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader.from_bytes" href="#ammosreader.AmmosAudioDataHeader.AmmosAudioDataHeader.from_bytes">from_bytes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosAudioReader.html
===================================================================
--- doc/ammosreader/AmmosAudioReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosAudioReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,525 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosAudioReader API documentation</title>
+<meta name="description" content="I provide a specialized Ammos Reader for audio data." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosAudioReader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide a specialized Ammos Reader for audio data.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide a specialized Ammos Reader for audio data.&#34;&#34;&#34;
+import logging
+
+from ammosreader.AbstractAmmosReader import AbstractAmmosReader
+from ammosreader.AmmosGlobalFrameBody import AmmosGlobalFrameBody
+from ammosreader.AmmosAudioDataHeader import AmmosAudioDataHeader
+from ammosreader.AmmosExtendedAudioDataHeader import AmmosExtendedAudioDataHeader
+from ammosreader.AmmosAudioDataBody import AmmosAudioDataBody
+
+
+class AmmosAudioReader(AbstractAmmosReader):
+    &#34;&#34;&#34;I read the audio data embedded in an R&amp;S AMMOS recording.&#34;&#34;&#34;
+
+    def __init__(self, file_name):
+        &#34;&#34;&#34;
+        I return an instance of AmmosAudioReader initialized with a given file name.
+
+        :param file_name: the file to read from
+        :type file_name: str
+        &#34;&#34;&#34;
+        super().__init__(file_name)
+
+    def read_next_global_frame_body_data_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame body data header from current position in file.
+
+        :param data_header_size: the number of bytes to read
+        :type data_header_size: int
+        :return: the next Ammos Audio Data header or None if incomplete
+        :rtype: AmmosAudioDataHeader
+        &#34;&#34;&#34;
+        header_size = AmmosAudioDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        logging.info(&#34;\nReading global frame body standard data header\n&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame body data header&#34;, header_size)
+            return None
+        return AmmosAudioDataHeader.from_bytes(bytes)
+
+    def read_next_global_frame_body_extended_data_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame body extended data header from current position in file.
+
+        :return: the next Ammos Audio Extended Data header or None if incomplete
+        :rtype: AmmosExtendedAudioDataHeader
+        &#34;&#34;&#34;
+        header_size = AmmosExtendedAudioDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame extended data header&#34;, header_size)
+            return None
+        return AmmosExtendedAudioDataHeader.from_bytes(bytes)
+
+    def read_next_audio_data_body(self, number_of_samples, number_of_channels, sample_size):
+        &#34;&#34;&#34;
+        I return the next audio data read from current position in file.
+
+        :param number_of_samples: the number of samples per channel inside data body
+        :type number_of_samples: int
+
+        :param number_of_channels: number of channels (e.g. mono, stereo or even more)
+        :type number_of_channels: int
+
+        :param sample_size: sample size in bytes (1, 2 or 4 bytes)
+        :type sample_size: int
+
+        :return: the next audio data or None if incomplete
+        :rtype: bytes
+        &#34;&#34;&#34;
+        total = number_of_samples*number_of_channels*sample_size
+
+        byte_string = self.ammos_file.read(total)
+
+        if len(byte_string) != total:
+            logging.debug(&#34;Can not read all %s bytes of data body&#34;, total)
+            return None
+        return AmmosAudioDataBody(byte_string, number_of_channels, number_of_samples, sample_size)
+
+    def read_next_global_frame_body(self, data_header_length):
+        &#34;&#34;&#34;
+        I return the next global frame body read from current position in file.
+
+        :param data_header_length: the length of the data header
+        :type data_header_length: int
+        &#34;&#34;&#34;
+        audio_data_header = None
+
+        if data_header_length == AmmosAudioDataHeader.HEADER_SIZE:
+            logging.info(&#34;Read standard data header&#34;)
+            audio_data_header = self.read_next_global_frame_body_data_header()
+
+        logging.info(&#34;Data header length %s&#34;, data_header_length)
+        if data_header_length == AmmosExtendedAudioDataHeader.HEADER_SIZE:
+            logging.info(&#34;Read extended data header&#34;)
+            audio_data_header = self.read_next_global_frame_body_extended_data_header()
+
+        if audio_data_header is None:
+            logging.debug(&#34;Data header missing or format unknown&#34;)
+            return None
+
+        audio_data_body = self.read_next_audio_data_body(audio_data_header.number_of_samples,
+                                                         audio_data_header.number_of_channels,
+                                                         audio_data_header.sample_size)
+
+        if audio_data_body is None:
+            logging.debug(&#34;Data body missing&#34;)
+            return None
+
+        return AmmosGlobalFrameBody(audio_data_header, audio_data_body)
+
+    def pcm_for_channel(self, a_channel):
+        &#34;&#34;&#34;
+        I return the raw pcm audio data for a given channel.
+
+        :param a_channel: the channel I have to extract
+        :type a_channel: int
+
+        :rtype: bytes
+        &#34;&#34;&#34;
+        return b&#34;&#34;.join([each.global_frame_body.data_body.pcm_for_channel(a_channel) for each in self.container.global_frames])</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosAudioReader.AmmosAudioReader"><code class="flex name class">
+<span>class <span class="ident">AmmosAudioReader</span></span>
+<span>(</span><span>file_name)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I read the audio data embedded in an R&amp;S AMMOS recording.</p>
+<p>I return an instance of AmmosAudioReader initialized with a given file name.</p>
+<p>:param file_name: the file to read from
+:type file_name: str</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosAudioReader(AbstractAmmosReader):
+    &#34;&#34;&#34;I read the audio data embedded in an R&amp;S AMMOS recording.&#34;&#34;&#34;
+
+    def __init__(self, file_name):
+        &#34;&#34;&#34;
+        I return an instance of AmmosAudioReader initialized with a given file name.
+
+        :param file_name: the file to read from
+        :type file_name: str
+        &#34;&#34;&#34;
+        super().__init__(file_name)
+
+    def read_next_global_frame_body_data_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame body data header from current position in file.
+
+        :param data_header_size: the number of bytes to read
+        :type data_header_size: int
+        :return: the next Ammos Audio Data header or None if incomplete
+        :rtype: AmmosAudioDataHeader
+        &#34;&#34;&#34;
+        header_size = AmmosAudioDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        logging.info(&#34;\nReading global frame body standard data header\n&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame body data header&#34;, header_size)
+            return None
+        return AmmosAudioDataHeader.from_bytes(bytes)
+
+    def read_next_global_frame_body_extended_data_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame body extended data header from current position in file.
+
+        :return: the next Ammos Audio Extended Data header or None if incomplete
+        :rtype: AmmosExtendedAudioDataHeader
+        &#34;&#34;&#34;
+        header_size = AmmosExtendedAudioDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame extended data header&#34;, header_size)
+            return None
+        return AmmosExtendedAudioDataHeader.from_bytes(bytes)
+
+    def read_next_audio_data_body(self, number_of_samples, number_of_channels, sample_size):
+        &#34;&#34;&#34;
+        I return the next audio data read from current position in file.
+
+        :param number_of_samples: the number of samples per channel inside data body
+        :type number_of_samples: int
+
+        :param number_of_channels: number of channels (e.g. mono, stereo or even more)
+        :type number_of_channels: int
+
+        :param sample_size: sample size in bytes (1, 2 or 4 bytes)
+        :type sample_size: int
+
+        :return: the next audio data or None if incomplete
+        :rtype: bytes
+        &#34;&#34;&#34;
+        total = number_of_samples*number_of_channels*sample_size
+
+        byte_string = self.ammos_file.read(total)
+
+        if len(byte_string) != total:
+            logging.debug(&#34;Can not read all %s bytes of data body&#34;, total)
+            return None
+        return AmmosAudioDataBody(byte_string, number_of_channels, number_of_samples, sample_size)
+
+    def read_next_global_frame_body(self, data_header_length):
+        &#34;&#34;&#34;
+        I return the next global frame body read from current position in file.
+
+        :param data_header_length: the length of the data header
+        :type data_header_length: int
+        &#34;&#34;&#34;
+        audio_data_header = None
+
+        if data_header_length == AmmosAudioDataHeader.HEADER_SIZE:
+            logging.info(&#34;Read standard data header&#34;)
+            audio_data_header = self.read_next_global_frame_body_data_header()
+
+        logging.info(&#34;Data header length %s&#34;, data_header_length)
+        if data_header_length == AmmosExtendedAudioDataHeader.HEADER_SIZE:
+            logging.info(&#34;Read extended data header&#34;)
+            audio_data_header = self.read_next_global_frame_body_extended_data_header()
+
+        if audio_data_header is None:
+            logging.debug(&#34;Data header missing or format unknown&#34;)
+            return None
+
+        audio_data_body = self.read_next_audio_data_body(audio_data_header.number_of_samples,
+                                                         audio_data_header.number_of_channels,
+                                                         audio_data_header.sample_size)
+
+        if audio_data_body is None:
+            logging.debug(&#34;Data body missing&#34;)
+            return None
+
+        return AmmosGlobalFrameBody(audio_data_header, audio_data_body)
+
+    def pcm_for_channel(self, a_channel):
+        &#34;&#34;&#34;
+        I return the raw pcm audio data for a given channel.
+
+        :param a_channel: the channel I have to extract
+        :type a_channel: int
+
+        :rtype: bytes
+        &#34;&#34;&#34;
+        return b&#34;&#34;.join([each.global_frame_body.data_body.pcm_for_channel(a_channel) for each in self.container.global_frames])</code></pre>
+</details>
+<h3>Ancestors</h3>
+<ul class="hlist">
+<li><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader">AbstractAmmosReader</a></li>
+<li>abc.ABC</li>
+</ul>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosAudioReader.AmmosAudioReader.pcm_for_channel"><code class="name flex">
+<span>def <span class="ident">pcm_for_channel</span></span>(<span>self, a_channel)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the raw pcm audio data for a given channel.</p>
+<p>:param a_channel: the channel I have to extract
+:type a_channel: int</p>
+<p>:rtype: bytes</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def pcm_for_channel(self, a_channel):
+    &#34;&#34;&#34;
+    I return the raw pcm audio data for a given channel.
+
+    :param a_channel: the channel I have to extract
+    :type a_channel: int
+
+    :rtype: bytes
+    &#34;&#34;&#34;
+    return b&#34;&#34;.join([each.global_frame_body.data_body.pcm_for_channel(a_channel) for each in self.container.global_frames])</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_audio_data_body"><code class="name flex">
+<span>def <span class="ident">read_next_audio_data_body</span></span>(<span>self, number_of_samples, number_of_channels, sample_size)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next audio data read from current position in file.</p>
+<p>:param number_of_samples: the number of samples per channel inside data body
+:type number_of_samples: int</p>
+<p>:param number_of_channels: number of channels (e.g. mono, stereo or even more)
+:type number_of_channels: int</p>
+<p>:param sample_size: sample size in bytes (1, 2 or 4 bytes)
+:type sample_size: int</p>
+<p>:return: the next audio data or None if incomplete
+:rtype: bytes</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_audio_data_body(self, number_of_samples, number_of_channels, sample_size):
+    &#34;&#34;&#34;
+    I return the next audio data read from current position in file.
+
+    :param number_of_samples: the number of samples per channel inside data body
+    :type number_of_samples: int
+
+    :param number_of_channels: number of channels (e.g. mono, stereo or even more)
+    :type number_of_channels: int
+
+    :param sample_size: sample size in bytes (1, 2 or 4 bytes)
+    :type sample_size: int
+
+    :return: the next audio data or None if incomplete
+    :rtype: bytes
+    &#34;&#34;&#34;
+    total = number_of_samples*number_of_channels*sample_size
+
+    byte_string = self.ammos_file.read(total)
+
+    if len(byte_string) != total:
+        logging.debug(&#34;Can not read all %s bytes of data body&#34;, total)
+        return None
+    return AmmosAudioDataBody(byte_string, number_of_channels, number_of_samples, sample_size)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body</span></span>(<span>self, data_header_length)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next global frame body read from current position in file.</p>
+<p>:param data_header_length: the length of the data header
+:type data_header_length: int</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_body(self, data_header_length):
+    &#34;&#34;&#34;
+    I return the next global frame body read from current position in file.
+
+    :param data_header_length: the length of the data header
+    :type data_header_length: int
+    &#34;&#34;&#34;
+    audio_data_header = None
+
+    if data_header_length == AmmosAudioDataHeader.HEADER_SIZE:
+        logging.info(&#34;Read standard data header&#34;)
+        audio_data_header = self.read_next_global_frame_body_data_header()
+
+    logging.info(&#34;Data header length %s&#34;, data_header_length)
+    if data_header_length == AmmosExtendedAudioDataHeader.HEADER_SIZE:
+        logging.info(&#34;Read extended data header&#34;)
+        audio_data_header = self.read_next_global_frame_body_extended_data_header()
+
+    if audio_data_header is None:
+        logging.debug(&#34;Data header missing or format unknown&#34;)
+        return None
+
+    audio_data_body = self.read_next_audio_data_body(audio_data_header.number_of_samples,
+                                                     audio_data_header.number_of_channels,
+                                                     audio_data_header.sample_size)
+
+    if audio_data_body is None:
+        logging.debug(&#34;Data body missing&#34;)
+        return None
+
+    return AmmosGlobalFrameBody(audio_data_header, audio_data_body)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body_data_header"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body_data_header</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next global frame body data header from current position in file.</p>
+<p>:param data_header_size: the number of bytes to read
+:type data_header_size: int
+:return: the next Ammos Audio Data header or None if incomplete
+:rtype: AmmosAudioDataHeader</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_body_data_header(self):
+    &#34;&#34;&#34;
+    I return the next global frame body data header from current position in file.
+
+    :param data_header_size: the number of bytes to read
+    :type data_header_size: int
+    :return: the next Ammos Audio Data header or None if incomplete
+    :rtype: AmmosAudioDataHeader
+    &#34;&#34;&#34;
+    header_size = AmmosAudioDataHeader.HEADER_SIZE
+
+    bytes = self.ammos_file.read(header_size)
+
+    logging.info(&#34;\nReading global frame body standard data header\n&#34;)
+    if ((not bytes) or (len(bytes) &lt; header_size)):
+        logging.debug(&#34;Can not read all %s bytes of global frame body data header&#34;, header_size)
+        return None
+    return AmmosAudioDataHeader.from_bytes(bytes)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body_extended_data_header"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body_extended_data_header</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next global frame body extended data header from current position in file.</p>
+<p>:return: the next Ammos Audio Extended Data header or None if incomplete
+:rtype: AmmosExtendedAudioDataHeader</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_body_extended_data_header(self):
+    &#34;&#34;&#34;
+    I return the next global frame body extended data header from current position in file.
+
+    :return: the next Ammos Audio Extended Data header or None if incomplete
+    :rtype: AmmosExtendedAudioDataHeader
+    &#34;&#34;&#34;
+    header_size = AmmosExtendedAudioDataHeader.HEADER_SIZE
+
+    bytes = self.ammos_file.read(header_size)
+
+    if ((not bytes) or (len(bytes) &lt; header_size)):
+        logging.debug(&#34;Can not read all %s bytes of global frame extended data header&#34;, header_size)
+        return None
+    return AmmosExtendedAudioDataHeader.from_bytes(bytes)</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Inherited members</h3>
+<ul class="hlist">
+<li><code><b><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader">AbstractAmmosReader</a></b></code>:
+<ul class="hlist">
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag">add_tag</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file">ammos_file</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.container" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.container">container</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name">file_name</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left">read_all_frames_left</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header">read_next_global_frame_header</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame">read_next_single_frame</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start">rewind_to_start</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags">tags</a></code></li>
+</ul>
+</li>
+</ul>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosAudioReader.AmmosAudioReader" href="#ammosreader.AmmosAudioReader.AmmosAudioReader">AmmosAudioReader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosAudioReader.AmmosAudioReader.pcm_for_channel" href="#ammosreader.AmmosAudioReader.AmmosAudioReader.pcm_for_channel">pcm_for_channel</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_audio_data_body" href="#ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_audio_data_body">read_next_audio_data_body</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body" href="#ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body">read_next_global_frame_body</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body_data_header" href="#ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body_data_header">read_next_global_frame_body_data_header</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body_extended_data_header" href="#ammosreader.AmmosAudioReader.AmmosAudioReader.read_next_global_frame_body_extended_data_header">read_next_global_frame_body_extended_data_header</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosAudioSocketReader.html
===================================================================
--- doc/ammosreader/AmmosAudioSocketReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosAudioSocketReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,497 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosAudioSocketReader API documentation</title>
+<meta name="description" content="I read a Ammos datastream from a socket." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosAudioSocketReader</code></h1>
+</header>
+<section id="section-intro">
+<p>I read a Ammos datastream from a socket.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I read a Ammos datastream from a socket.&#34;&#34;&#34;
+
+import select
+import socket
+from collections import deque
+import numpy as np
+from ammosreader.AmmosAudioDataHeader import AmmosAudioDataHeader
+from ammosreader.AmmosExtendedAudioDataHeader import AmmosExtendedAudioDataHeader
+from ammosreader.AmmosGlobalFrameHeader import AmmosGlobalFrameHeader
+
+
+class AmmosAudioSocketReader:
+    def __init__(self, socket:socket.socket, debug=True):
+        &#34;&#34;&#34;
+        Initializes the AmmosAudioSocketReader
+
+        Args:
+            socket (socket.socket): socket to read from
+            debug (bool): if true, prints debug information
+        &#34;&#34;&#34;
+
+        #buffer for reading socket bytewise und check for the magic word
+        self.__magic_word_buffer = deque(maxlen=4)
+
+        #input socket to read from
+        self.__socket = socket
+
+        #
+        self.DEBUG_MODE = debug
+
+    def __get_next_data(self, byte_count: int) -&gt; bytearray:
+        &#34;&#34;&#34;
+        Gets the next bytes from the socket, for example headers and body data.
+
+        Args:
+            byte_count (int): number of bytes to read
+
+        Raises:
+            TimeoutError: Raises TimeoutError if the socket does not serve data anymore
+
+        Returns:
+            bytearray: data from socket as bytearray
+        &#34;&#34;&#34;
+
+        byte_array = []
+        
+        while len(b&#39;&#39;.join(byte_array)) &lt; byte_count:
+            if self.DEBUG_MODE:
+                print(f&#34;Remaining Bytes: {byte_count - len(b&#39;&#39;.join(byte_array))}&#34;)
+            self.__socket.settimeout(5)
+            new_bytes = self.__socket.recv(byte_count - len(b&#39;&#39;.join(byte_array)), socket.MSG_WAITALL)
+
+            if not new_bytes:
+                raise TimeoutError(&#34;Socket timed out while reading data&#34;)
+
+            if self.DEBUG_MODE:
+                print(f&#34;Got {len(new_bytes)} bytes of {byte_count - len(b&#39;&#39;.join(byte_array))} ramining&#34;)
+
+            byte_array.append(new_bytes)
+
+        return b&#39;&#39;.join(byte_array)
+
+    def __audio_data_body_to_numpy(self, audio_data_body:bytearray) -&gt; np.ndarray:
+        &#34;&#34;&#34;
+        converts the audio data body to a numpy array
+
+        Args:
+            audio_data_body (bytearray): audio data from audio data body
+
+        Returns:
+            np.ndarray: audio data as numpy array
+        &#34;&#34;&#34;
+
+        return np.frombuffer(audio_data_body, dtype=np.int16)
+
+    def read_next_frame(self) -&gt; tuple[np.ndarray, int]:
+        &#34;&#34;&#34;Reads the next ammos audio frame from socket
+
+        Raises:
+            TimeoutError: Raisees TimeoutError if the socket does not serve data anymore
+
+        Returns:
+            tuple[np.ndarray, int]: Contains the audio data and the sample rate
+        &#34;&#34;&#34;
+
+        # get first byte of the day
+        self.__socket.settimeout(5)
+
+        new_byte = self.__socket.recv(1, socket.MSG_WAITALL)
+        # raise Exception if socket does not return anything
+        if len(new_byte) &lt; 1:
+            raise TimeoutError      
+
+        #read loop
+        while new_byte:
+            #
+            self.__magic_word_buffer.append(new_byte)
+            byte_array = b&#39;&#39;.join(self.__magic_word_buffer)
+
+            if byte_array.hex() == &#39;726574fb&#39;:
+                #print(byte_array.hex())
+
+                ammos_global_header_buffer = list(self.__magic_word_buffer)
+                ammos_global_header_buffer.append(self.__get_next_data(20))
+                #while len(b&#39;&#39;.join(ammos_global_header_buffer)) &lt; 24:
+                #    ammos_global_header_buffer.append(self.__socket.recv(24 - len(b&#39;&#39;.join(ammos_global_header_buffer))))
+                    
+                ammos_global_header = AmmosGlobalFrameHeader.from_bytes(b&#39;&#39;.join(ammos_global_header_buffer))
+                if self.DEBUG_MODE:
+                    print(ammos_global_header)
+
+                if ammos_global_header.data_header_length == 44 and ammos_global_header.frame_type == 256:
+                    byte_array_header = self.__get_next_data(44)
+                    #while len(b&#39;&#39;.join(byte_array_header)) &lt; 44:
+                    #    byte_array_header.append(self.__socket.recv(44 - len(b&#39;&#39;.join(byte_array_header))))
+
+                    ammos_extended_audio_data_header = AmmosExtendedAudioDataHeader.from_bytes(byte_array_header)
+                    if self.DEBUG_MODE:
+                        print(ammos_extended_audio_data_header.number_of_samples, ammos_extended_audio_data_header.number_of_channels, ammos_extended_audio_data_header.sample_size)
+                    audio_body = self.__get_next_data(ammos_extended_audio_data_header.number_of_samples* 
+                                                      ammos_extended_audio_data_header.number_of_channels* 
+                                                      ammos_extended_audio_data_header.sample_size)
+
+                    audio_array = self.__audio_data_body_to_numpy(audio_body)
+                    if self.DEBUG_MODE:
+                        print(len(audio_array), len(audio_array)/ammos_extended_audio_data_header.sample_rate)
+
+                    return [audio_array, ammos_extended_audio_data_header.sample_rate]
+
+                elif ammos_global_header.data_header_length == 36 and ammos_global_header.frame_type == 256:
+                    byte_array_header = self.__get_next_data(36)
+                    #while len(b&#39;&#39;.join(byte_array_header)) &lt; 36:
+                    #    byte_array_header.append(self.__socket.recv(36 - len(b&#39;&#39;.join(byte_array_header))))
+
+                    ammos_audio_data_header = AmmosAudioDataHeader.from_bytes(byte_array_header)
+                    if self.DEBUG_MODE:
+                        print(ammos_audio_data_header.number_of_samples, ammos_audio_data_header.number_of_channels, ammos_audio_data_header.sample_size)
+                    audio_body = self.__get_next_data(ammos_extended_audio_data_header.number_of_samples* 
+                                                      ammos_extended_audio_data_header.number_of_channels* 
+                                                      ammos_extended_audio_data_header.sample_size)
+
+                    audio_array = self.__audio_data_body_to_numpy(audio_body)
+                    if self.DEBUG_MODE:
+                        print(len(audio_array), len(audio_array)/ammos_audio_data_header.sample_rate)
+
+                    return [audio_array, ammos_audio_data_header.sample_rate]
+
+            # get the next byte
+            self.__socket.settimeout(5)
+
+            new_byte = self.__socket.recv(1, socket.MSG_WAITALL)
+            # raise Exception if socket does not return anything
+            if len(new_byte) &lt; 1:
+                raise TimeoutError   
+
+        return None</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosAudioSocketReader.AmmosAudioSocketReader"><code class="flex name class">
+<span>class <span class="ident">AmmosAudioSocketReader</span></span>
+<span>(</span><span>socket: socket.socket, debug=True)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Initializes the AmmosAudioSocketReader</p>
+<h2 id="args">Args</h2>
+<dl>
+<dt><strong><code>socket</code></strong> :&ensp;<code>socket.socket</code></dt>
+<dd>socket to read from</dd>
+<dt><strong><code>debug</code></strong> :&ensp;<code>bool</code></dt>
+<dd>if true, prints debug information</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosAudioSocketReader:
+    def __init__(self, socket:socket.socket, debug=True):
+        &#34;&#34;&#34;
+        Initializes the AmmosAudioSocketReader
+
+        Args:
+            socket (socket.socket): socket to read from
+            debug (bool): if true, prints debug information
+        &#34;&#34;&#34;
+
+        #buffer for reading socket bytewise und check for the magic word
+        self.__magic_word_buffer = deque(maxlen=4)
+
+        #input socket to read from
+        self.__socket = socket
+
+        #
+        self.DEBUG_MODE = debug
+
+    def __get_next_data(self, byte_count: int) -&gt; bytearray:
+        &#34;&#34;&#34;
+        Gets the next bytes from the socket, for example headers and body data.
+
+        Args:
+            byte_count (int): number of bytes to read
+
+        Raises:
+            TimeoutError: Raises TimeoutError if the socket does not serve data anymore
+
+        Returns:
+            bytearray: data from socket as bytearray
+        &#34;&#34;&#34;
+
+        byte_array = []
+        
+        while len(b&#39;&#39;.join(byte_array)) &lt; byte_count:
+            if self.DEBUG_MODE:
+                print(f&#34;Remaining Bytes: {byte_count - len(b&#39;&#39;.join(byte_array))}&#34;)
+            self.__socket.settimeout(5)
+            new_bytes = self.__socket.recv(byte_count - len(b&#39;&#39;.join(byte_array)), socket.MSG_WAITALL)
+
+            if not new_bytes:
+                raise TimeoutError(&#34;Socket timed out while reading data&#34;)
+
+            if self.DEBUG_MODE:
+                print(f&#34;Got {len(new_bytes)} bytes of {byte_count - len(b&#39;&#39;.join(byte_array))} ramining&#34;)
+
+            byte_array.append(new_bytes)
+
+        return b&#39;&#39;.join(byte_array)
+
+    def __audio_data_body_to_numpy(self, audio_data_body:bytearray) -&gt; np.ndarray:
+        &#34;&#34;&#34;
+        converts the audio data body to a numpy array
+
+        Args:
+            audio_data_body (bytearray): audio data from audio data body
+
+        Returns:
+            np.ndarray: audio data as numpy array
+        &#34;&#34;&#34;
+
+        return np.frombuffer(audio_data_body, dtype=np.int16)
+
+    def read_next_frame(self) -&gt; tuple[np.ndarray, int]:
+        &#34;&#34;&#34;Reads the next ammos audio frame from socket
+
+        Raises:
+            TimeoutError: Raisees TimeoutError if the socket does not serve data anymore
+
+        Returns:
+            tuple[np.ndarray, int]: Contains the audio data and the sample rate
+        &#34;&#34;&#34;
+
+        # get first byte of the day
+        self.__socket.settimeout(5)
+
+        new_byte = self.__socket.recv(1, socket.MSG_WAITALL)
+        # raise Exception if socket does not return anything
+        if len(new_byte) &lt; 1:
+            raise TimeoutError      
+
+        #read loop
+        while new_byte:
+            #
+            self.__magic_word_buffer.append(new_byte)
+            byte_array = b&#39;&#39;.join(self.__magic_word_buffer)
+
+            if byte_array.hex() == &#39;726574fb&#39;:
+                #print(byte_array.hex())
+
+                ammos_global_header_buffer = list(self.__magic_word_buffer)
+                ammos_global_header_buffer.append(self.__get_next_data(20))
+                #while len(b&#39;&#39;.join(ammos_global_header_buffer)) &lt; 24:
+                #    ammos_global_header_buffer.append(self.__socket.recv(24 - len(b&#39;&#39;.join(ammos_global_header_buffer))))
+                    
+                ammos_global_header = AmmosGlobalFrameHeader.from_bytes(b&#39;&#39;.join(ammos_global_header_buffer))
+                if self.DEBUG_MODE:
+                    print(ammos_global_header)
+
+                if ammos_global_header.data_header_length == 44 and ammos_global_header.frame_type == 256:
+                    byte_array_header = self.__get_next_data(44)
+                    #while len(b&#39;&#39;.join(byte_array_header)) &lt; 44:
+                    #    byte_array_header.append(self.__socket.recv(44 - len(b&#39;&#39;.join(byte_array_header))))
+
+                    ammos_extended_audio_data_header = AmmosExtendedAudioDataHeader.from_bytes(byte_array_header)
+                    if self.DEBUG_MODE:
+                        print(ammos_extended_audio_data_header.number_of_samples, ammos_extended_audio_data_header.number_of_channels, ammos_extended_audio_data_header.sample_size)
+                    audio_body = self.__get_next_data(ammos_extended_audio_data_header.number_of_samples* 
+                                                      ammos_extended_audio_data_header.number_of_channels* 
+                                                      ammos_extended_audio_data_header.sample_size)
+
+                    audio_array = self.__audio_data_body_to_numpy(audio_body)
+                    if self.DEBUG_MODE:
+                        print(len(audio_array), len(audio_array)/ammos_extended_audio_data_header.sample_rate)
+
+                    return [audio_array, ammos_extended_audio_data_header.sample_rate]
+
+                elif ammos_global_header.data_header_length == 36 and ammos_global_header.frame_type == 256:
+                    byte_array_header = self.__get_next_data(36)
+                    #while len(b&#39;&#39;.join(byte_array_header)) &lt; 36:
+                    #    byte_array_header.append(self.__socket.recv(36 - len(b&#39;&#39;.join(byte_array_header))))
+
+                    ammos_audio_data_header = AmmosAudioDataHeader.from_bytes(byte_array_header)
+                    if self.DEBUG_MODE:
+                        print(ammos_audio_data_header.number_of_samples, ammos_audio_data_header.number_of_channels, ammos_audio_data_header.sample_size)
+                    audio_body = self.__get_next_data(ammos_extended_audio_data_header.number_of_samples* 
+                                                      ammos_extended_audio_data_header.number_of_channels* 
+                                                      ammos_extended_audio_data_header.sample_size)
+
+                    audio_array = self.__audio_data_body_to_numpy(audio_body)
+                    if self.DEBUG_MODE:
+                        print(len(audio_array), len(audio_array)/ammos_audio_data_header.sample_rate)
+
+                    return [audio_array, ammos_audio_data_header.sample_rate]
+
+            # get the next byte
+            self.__socket.settimeout(5)
+
+            new_byte = self.__socket.recv(1, socket.MSG_WAITALL)
+            # raise Exception if socket does not return anything
+            if len(new_byte) &lt; 1:
+                raise TimeoutError   
+
+        return None</code></pre>
+</details>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosAudioSocketReader.AmmosAudioSocketReader.read_next_frame"><code class="name flex">
+<span>def <span class="ident">read_next_frame</span></span>(<span>self) ‑> tuple[numpy.ndarray, int]</span>
+</code></dt>
+<dd>
+<div class="desc"><p>Reads the next ammos audio frame from socket</p>
+<h2 id="raises">Raises</h2>
+<dl>
+<dt><code>TimeoutError</code></dt>
+<dd>Raisees TimeoutError if the socket does not serve data anymore</dd>
+</dl>
+<h2 id="returns">Returns</h2>
+<dl>
+<dt><code>tuple[np.ndarray, int]</code></dt>
+<dd>Contains the audio data and the sample rate</dd>
+</dl></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_frame(self) -&gt; tuple[np.ndarray, int]:
+    &#34;&#34;&#34;Reads the next ammos audio frame from socket
+
+    Raises:
+        TimeoutError: Raisees TimeoutError if the socket does not serve data anymore
+
+    Returns:
+        tuple[np.ndarray, int]: Contains the audio data and the sample rate
+    &#34;&#34;&#34;
+
+    # get first byte of the day
+    self.__socket.settimeout(5)
+
+    new_byte = self.__socket.recv(1, socket.MSG_WAITALL)
+    # raise Exception if socket does not return anything
+    if len(new_byte) &lt; 1:
+        raise TimeoutError      
+
+    #read loop
+    while new_byte:
+        #
+        self.__magic_word_buffer.append(new_byte)
+        byte_array = b&#39;&#39;.join(self.__magic_word_buffer)
+
+        if byte_array.hex() == &#39;726574fb&#39;:
+            #print(byte_array.hex())
+
+            ammos_global_header_buffer = list(self.__magic_word_buffer)
+            ammos_global_header_buffer.append(self.__get_next_data(20))
+            #while len(b&#39;&#39;.join(ammos_global_header_buffer)) &lt; 24:
+            #    ammos_global_header_buffer.append(self.__socket.recv(24 - len(b&#39;&#39;.join(ammos_global_header_buffer))))
+                
+            ammos_global_header = AmmosGlobalFrameHeader.from_bytes(b&#39;&#39;.join(ammos_global_header_buffer))
+            if self.DEBUG_MODE:
+                print(ammos_global_header)
+
+            if ammos_global_header.data_header_length == 44 and ammos_global_header.frame_type == 256:
+                byte_array_header = self.__get_next_data(44)
+                #while len(b&#39;&#39;.join(byte_array_header)) &lt; 44:
+                #    byte_array_header.append(self.__socket.recv(44 - len(b&#39;&#39;.join(byte_array_header))))
+
+                ammos_extended_audio_data_header = AmmosExtendedAudioDataHeader.from_bytes(byte_array_header)
+                if self.DEBUG_MODE:
+                    print(ammos_extended_audio_data_header.number_of_samples, ammos_extended_audio_data_header.number_of_channels, ammos_extended_audio_data_header.sample_size)
+                audio_body = self.__get_next_data(ammos_extended_audio_data_header.number_of_samples* 
+                                                  ammos_extended_audio_data_header.number_of_channels* 
+                                                  ammos_extended_audio_data_header.sample_size)
+
+                audio_array = self.__audio_data_body_to_numpy(audio_body)
+                if self.DEBUG_MODE:
+                    print(len(audio_array), len(audio_array)/ammos_extended_audio_data_header.sample_rate)
+
+                return [audio_array, ammos_extended_audio_data_header.sample_rate]
+
+            elif ammos_global_header.data_header_length == 36 and ammos_global_header.frame_type == 256:
+                byte_array_header = self.__get_next_data(36)
+                #while len(b&#39;&#39;.join(byte_array_header)) &lt; 36:
+                #    byte_array_header.append(self.__socket.recv(36 - len(b&#39;&#39;.join(byte_array_header))))
+
+                ammos_audio_data_header = AmmosAudioDataHeader.from_bytes(byte_array_header)
+                if self.DEBUG_MODE:
+                    print(ammos_audio_data_header.number_of_samples, ammos_audio_data_header.number_of_channels, ammos_audio_data_header.sample_size)
+                audio_body = self.__get_next_data(ammos_extended_audio_data_header.number_of_samples* 
+                                                  ammos_extended_audio_data_header.number_of_channels* 
+                                                  ammos_extended_audio_data_header.sample_size)
+
+                audio_array = self.__audio_data_body_to_numpy(audio_body)
+                if self.DEBUG_MODE:
+                    print(len(audio_array), len(audio_array)/ammos_audio_data_header.sample_rate)
+
+                return [audio_array, ammos_audio_data_header.sample_rate]
+
+        # get the next byte
+        self.__socket.settimeout(5)
+
+        new_byte = self.__socket.recv(1, socket.MSG_WAITALL)
+        # raise Exception if socket does not return anything
+        if len(new_byte) &lt; 1:
+            raise TimeoutError   
+
+    return None</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosAudioSocketReader.AmmosAudioSocketReader" href="#ammosreader.AmmosAudioSocketReader.AmmosAudioSocketReader">AmmosAudioSocketReader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosAudioSocketReader.AmmosAudioSocketReader.read_next_frame" href="#ammosreader.AmmosAudioSocketReader.AmmosAudioSocketReader.read_next_frame">read_next_frame</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosConstants.html
===================================================================
--- doc/ammosreader/AmmosConstants.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosConstants.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,436 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosConstants API documentation</title>
+<meta name="description" content="I provide several constants used in R&amp;S software." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosConstants</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide several constants used in R&amp;S software.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide several constants used in R&amp;S software.&#34;&#34;&#34;
+
+from enum import Enum
+
+
+class FrameType(int, Enum):
+    &#34;&#34;&#34;I map numbers to human readable format specifiers.&#34;&#34;&#34;
+
+    TEST_DATA = 0x00
+    IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT = 0x01
+    IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT = 0x02
+    IF_DATA_16BIT_REAL_REAL = 0x03
+    IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED = 0x04
+    IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED = 0x05
+    SPECTRUM_DATA_8BIT = 0x10
+    SPECTRUM_DATA_16BIT = 0x11
+    SPECTRUM_DATA_32BIT = 0x12
+    SPECTRUM_DATA_32BIT_FLOATINGPOINT = 0x13
+    SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT = 0x14
+    HF_TUNING_INDICATOR_DATA = 0x20
+    HF_SCAN_CHANNEL_FOUND_DATA = 0x22
+    HF_SCAN_FREQUENCY_FOUND_DATA = 0x23
+    HF_SCAN_SWEEP_RESTARTED_DATA = 0x24
+    HF_DEMODULATION_SYMBOL_STREAM_DATA = 0x30
+    HF_DECODER_TEXT_DATA = 0x40
+    HF_SPECTRUM_VISUALIZATION_DATA = 0x50
+    HF_TIMEDOMAIN_VISUALIZATION_DATA = 0x51
+    AUDIO_DATA = 0x100
+    EMISSION_LIST_DATA = 0x110
+    LEVEL_DATA = 0x120
+    SYMBOL_DATA = 0x130
+    INSTANTANEOUS_DATA = 0x140
+    BURST_EMMISION_LIST = 0x150
+    IMAGE_DATA = 0x160
+    TRANSMISSION_SYSTEM_RESULT_DATA = 0x170
+    PULSE_DESCRIPTION_WORD_DATA = 0x200
+    PULSE_REPETITION_WORD_DATA = 0x210
+    EM050_SCAN_DATA = 0x4000
+    SCAN_LEVEL = 0x4001
+    SCAN_TUNING = 0x4002
+    SCAN_LEVEL_TUNING = 0x4003
+    DDF_RESERVED_START = 0x5000
+    DDF_RESERVED_END = 0x50FF
+
+
+class AmmosAudioDemodType(int, Enum):
+    &#34;&#34;&#34;I map numbers to human readable demodulation types.&#34;&#34;&#34;
+
+    FM = 0
+    AM = 1
+    ISB = 5
+    CW = 6
+    USB = 7
+    LSB = 8
+    DIGITAL = 256
+    UNKNOWN = 0xFFFFFFFF</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType"><code class="flex name class">
+<span>class <span class="ident">AmmosAudioDemodType</span></span>
+<span>(</span><span>value, names=None, *, module=None, qualname=None, type=None, start=1)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I map numbers to human readable demodulation types.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosAudioDemodType(int, Enum):
+    &#34;&#34;&#34;I map numbers to human readable demodulation types.&#34;&#34;&#34;
+
+    FM = 0
+    AM = 1
+    ISB = 5
+    CW = 6
+    USB = 7
+    LSB = 8
+    DIGITAL = 256
+    UNKNOWN = 0xFFFFFFFF</code></pre>
+</details>
+<h3>Ancestors</h3>
+<ul class="hlist">
+<li>builtins.int</li>
+<li>enum.Enum</li>
+</ul>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.AM"><code class="name">var <span class="ident">AM</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.CW"><code class="name">var <span class="ident">CW</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.DIGITAL"><code class="name">var <span class="ident">DIGITAL</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.FM"><code class="name">var <span class="ident">FM</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.ISB"><code class="name">var <span class="ident">ISB</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.LSB"><code class="name">var <span class="ident">LSB</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.UNKNOWN"><code class="name">var <span class="ident">UNKNOWN</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.AmmosAudioDemodType.USB"><code class="name">var <span class="ident">USB</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType"><code class="flex name class">
+<span>class <span class="ident">FrameType</span></span>
+<span>(</span><span>value, names=None, *, module=None, qualname=None, type=None, start=1)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I map numbers to human readable format specifiers.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class FrameType(int, Enum):
+    &#34;&#34;&#34;I map numbers to human readable format specifiers.&#34;&#34;&#34;
+
+    TEST_DATA = 0x00
+    IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT = 0x01
+    IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT = 0x02
+    IF_DATA_16BIT_REAL_REAL = 0x03
+    IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED = 0x04
+    IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED = 0x05
+    SPECTRUM_DATA_8BIT = 0x10
+    SPECTRUM_DATA_16BIT = 0x11
+    SPECTRUM_DATA_32BIT = 0x12
+    SPECTRUM_DATA_32BIT_FLOATINGPOINT = 0x13
+    SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT = 0x14
+    HF_TUNING_INDICATOR_DATA = 0x20
+    HF_SCAN_CHANNEL_FOUND_DATA = 0x22
+    HF_SCAN_FREQUENCY_FOUND_DATA = 0x23
+    HF_SCAN_SWEEP_RESTARTED_DATA = 0x24
+    HF_DEMODULATION_SYMBOL_STREAM_DATA = 0x30
+    HF_DECODER_TEXT_DATA = 0x40
+    HF_SPECTRUM_VISUALIZATION_DATA = 0x50
+    HF_TIMEDOMAIN_VISUALIZATION_DATA = 0x51
+    AUDIO_DATA = 0x100
+    EMISSION_LIST_DATA = 0x110
+    LEVEL_DATA = 0x120
+    SYMBOL_DATA = 0x130
+    INSTANTANEOUS_DATA = 0x140
+    BURST_EMMISION_LIST = 0x150
+    IMAGE_DATA = 0x160
+    TRANSMISSION_SYSTEM_RESULT_DATA = 0x170
+    PULSE_DESCRIPTION_WORD_DATA = 0x200
+    PULSE_REPETITION_WORD_DATA = 0x210
+    EM050_SCAN_DATA = 0x4000
+    SCAN_LEVEL = 0x4001
+    SCAN_TUNING = 0x4002
+    SCAN_LEVEL_TUNING = 0x4003
+    DDF_RESERVED_START = 0x5000
+    DDF_RESERVED_END = 0x50FF</code></pre>
+</details>
+<h3>Ancestors</h3>
+<ul class="hlist">
+<li>builtins.int</li>
+<li>enum.Enum</li>
+</ul>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosConstants.FrameType.AUDIO_DATA"><code class="name">var <span class="ident">AUDIO_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.BURST_EMMISION_LIST"><code class="name">var <span class="ident">BURST_EMMISION_LIST</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.DDF_RESERVED_END"><code class="name">var <span class="ident">DDF_RESERVED_END</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.DDF_RESERVED_START"><code class="name">var <span class="ident">DDF_RESERVED_START</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.EM050_SCAN_DATA"><code class="name">var <span class="ident">EM050_SCAN_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.EMISSION_LIST_DATA"><code class="name">var <span class="ident">EMISSION_LIST_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_DECODER_TEXT_DATA"><code class="name">var <span class="ident">HF_DECODER_TEXT_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_DEMODULATION_SYMBOL_STREAM_DATA"><code class="name">var <span class="ident">HF_DEMODULATION_SYMBOL_STREAM_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_SCAN_CHANNEL_FOUND_DATA"><code class="name">var <span class="ident">HF_SCAN_CHANNEL_FOUND_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_SCAN_FREQUENCY_FOUND_DATA"><code class="name">var <span class="ident">HF_SCAN_FREQUENCY_FOUND_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_SCAN_SWEEP_RESTARTED_DATA"><code class="name">var <span class="ident">HF_SCAN_SWEEP_RESTARTED_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_SPECTRUM_VISUALIZATION_DATA"><code class="name">var <span class="ident">HF_SPECTRUM_VISUALIZATION_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_TIMEDOMAIN_VISUALIZATION_DATA"><code class="name">var <span class="ident">HF_TIMEDOMAIN_VISUALIZATION_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.HF_TUNING_INDICATOR_DATA"><code class="name">var <span class="ident">HF_TUNING_INDICATOR_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT"><code class="name">var <span class="ident">IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.IF_DATA_16BIT_REAL_REAL"><code class="name">var <span class="ident">IF_DATA_16BIT_REAL_REAL</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT"><code class="name">var <span class="ident">IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED"><code class="name">var <span class="ident">IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED"><code class="name">var <span class="ident">IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.IMAGE_DATA"><code class="name">var <span class="ident">IMAGE_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.INSTANTANEOUS_DATA"><code class="name">var <span class="ident">INSTANTANEOUS_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.LEVEL_DATA"><code class="name">var <span class="ident">LEVEL_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.PULSE_DESCRIPTION_WORD_DATA"><code class="name">var <span class="ident">PULSE_DESCRIPTION_WORD_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.PULSE_REPETITION_WORD_DATA"><code class="name">var <span class="ident">PULSE_REPETITION_WORD_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SCAN_LEVEL"><code class="name">var <span class="ident">SCAN_LEVEL</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SCAN_LEVEL_TUNING"><code class="name">var <span class="ident">SCAN_LEVEL_TUNING</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SCAN_TUNING"><code class="name">var <span class="ident">SCAN_TUNING</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT"><code class="name">var <span class="ident">SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_16BIT"><code class="name">var <span class="ident">SPECTRUM_DATA_16BIT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_32BIT"><code class="name">var <span class="ident">SPECTRUM_DATA_32BIT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_32BIT_FLOATINGPOINT"><code class="name">var <span class="ident">SPECTRUM_DATA_32BIT_FLOATINGPOINT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_8BIT"><code class="name">var <span class="ident">SPECTRUM_DATA_8BIT</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.SYMBOL_DATA"><code class="name">var <span class="ident">SYMBOL_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.TEST_DATA"><code class="name">var <span class="ident">TEST_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosConstants.FrameType.TRANSMISSION_SYSTEM_RESULT_DATA"><code class="name">var <span class="ident">TRANSMISSION_SYSTEM_RESULT_DATA</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType" href="#ammosreader.AmmosConstants.AmmosAudioDemodType">AmmosAudioDemodType</a></code></h4>
+<ul class="two-column">
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.AM" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.AM">AM</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.CW" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.CW">CW</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.DIGITAL" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.DIGITAL">DIGITAL</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.FM" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.FM">FM</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.ISB" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.ISB">ISB</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.LSB" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.LSB">LSB</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.UNKNOWN" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.UNKNOWN">UNKNOWN</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.AmmosAudioDemodType.USB" href="#ammosreader.AmmosConstants.AmmosAudioDemodType.USB">USB</a></code></li>
+</ul>
+</li>
+<li>
+<h4><code><a title="ammosreader.AmmosConstants.FrameType" href="#ammosreader.AmmosConstants.FrameType">FrameType</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosConstants.FrameType.AUDIO_DATA" href="#ammosreader.AmmosConstants.FrameType.AUDIO_DATA">AUDIO_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.BURST_EMMISION_LIST" href="#ammosreader.AmmosConstants.FrameType.BURST_EMMISION_LIST">BURST_EMMISION_LIST</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.DDF_RESERVED_END" href="#ammosreader.AmmosConstants.FrameType.DDF_RESERVED_END">DDF_RESERVED_END</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.DDF_RESERVED_START" href="#ammosreader.AmmosConstants.FrameType.DDF_RESERVED_START">DDF_RESERVED_START</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.EM050_SCAN_DATA" href="#ammosreader.AmmosConstants.FrameType.EM050_SCAN_DATA">EM050_SCAN_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.EMISSION_LIST_DATA" href="#ammosreader.AmmosConstants.FrameType.EMISSION_LIST_DATA">EMISSION_LIST_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_DECODER_TEXT_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_DECODER_TEXT_DATA">HF_DECODER_TEXT_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_DEMODULATION_SYMBOL_STREAM_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_DEMODULATION_SYMBOL_STREAM_DATA">HF_DEMODULATION_SYMBOL_STREAM_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_SCAN_CHANNEL_FOUND_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_SCAN_CHANNEL_FOUND_DATA">HF_SCAN_CHANNEL_FOUND_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_SCAN_FREQUENCY_FOUND_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_SCAN_FREQUENCY_FOUND_DATA">HF_SCAN_FREQUENCY_FOUND_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_SCAN_SWEEP_RESTARTED_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_SCAN_SWEEP_RESTARTED_DATA">HF_SCAN_SWEEP_RESTARTED_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_SPECTRUM_VISUALIZATION_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_SPECTRUM_VISUALIZATION_DATA">HF_SPECTRUM_VISUALIZATION_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_TIMEDOMAIN_VISUALIZATION_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_TIMEDOMAIN_VISUALIZATION_DATA">HF_TIMEDOMAIN_VISUALIZATION_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.HF_TUNING_INDICATOR_DATA" href="#ammosreader.AmmosConstants.FrameType.HF_TUNING_INDICATOR_DATA">HF_TUNING_INDICATOR_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT" href="#ammosreader.AmmosConstants.FrameType.IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT">IF_DATA_16BIT_REAL_IMAGINARY_FIXEDPOINT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.IF_DATA_16BIT_REAL_REAL" href="#ammosreader.AmmosConstants.FrameType.IF_DATA_16BIT_REAL_REAL">IF_DATA_16BIT_REAL_REAL</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT" href="#ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT">IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED" href="#ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED">IF_DATA_32BIT_REAL_IMAGINARY_FIXEDPOINT_RESCALED</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED" href="#ammosreader.AmmosConstants.FrameType.IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED">IF_DATA_32BIT_REAL_IMAGINARY_FLOATINGPOINT_RESCALED</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.IMAGE_DATA" href="#ammosreader.AmmosConstants.FrameType.IMAGE_DATA">IMAGE_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.INSTANTANEOUS_DATA" href="#ammosreader.AmmosConstants.FrameType.INSTANTANEOUS_DATA">INSTANTANEOUS_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.LEVEL_DATA" href="#ammosreader.AmmosConstants.FrameType.LEVEL_DATA">LEVEL_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.PULSE_DESCRIPTION_WORD_DATA" href="#ammosreader.AmmosConstants.FrameType.PULSE_DESCRIPTION_WORD_DATA">PULSE_DESCRIPTION_WORD_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.PULSE_REPETITION_WORD_DATA" href="#ammosreader.AmmosConstants.FrameType.PULSE_REPETITION_WORD_DATA">PULSE_REPETITION_WORD_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SCAN_LEVEL" href="#ammosreader.AmmosConstants.FrameType.SCAN_LEVEL">SCAN_LEVEL</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SCAN_LEVEL_TUNING" href="#ammosreader.AmmosConstants.FrameType.SCAN_LEVEL_TUNING">SCAN_LEVEL_TUNING</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SCAN_TUNING" href="#ammosreader.AmmosConstants.FrameType.SCAN_TUNING">SCAN_TUNING</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT" href="#ammosreader.AmmosConstants.FrameType.SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT">SEGMENTATION_SPECTRUM_DATA_32BIT_FLOATINGPOINT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_16BIT" href="#ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_16BIT">SPECTRUM_DATA_16BIT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_32BIT" href="#ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_32BIT">SPECTRUM_DATA_32BIT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_32BIT_FLOATINGPOINT" href="#ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_32BIT_FLOATINGPOINT">SPECTRUM_DATA_32BIT_FLOATINGPOINT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_8BIT" href="#ammosreader.AmmosConstants.FrameType.SPECTRUM_DATA_8BIT">SPECTRUM_DATA_8BIT</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.SYMBOL_DATA" href="#ammosreader.AmmosConstants.FrameType.SYMBOL_DATA">SYMBOL_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.TEST_DATA" href="#ammosreader.AmmosConstants.FrameType.TEST_DATA">TEST_DATA</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants.FrameType.TRANSMISSION_SYSTEM_RESULT_DATA" href="#ammosreader.AmmosConstants.FrameType.TRANSMISSION_SYSTEM_RESULT_DATA">TRANSMISSION_SYSTEM_RESULT_DATA</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosContainer.html
===================================================================
--- doc/ammosreader/AmmosContainer.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosContainer.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,354 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosContainer API documentation</title>
+<meta name="description" content="I store the content of an R&amp;S Ammos file in a more accessible way." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosContainer</code></h1>
+</header>
+<section id="section-intro">
+<p>I store the content of an R&amp;S Ammos file in a more accessible way.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I store the content of an R&amp;S Ammos file in a more accessible way.&#34;&#34;&#34;
+
+class AmmosContainer():
+
+    def __init__(self, name, frames):
+        self.__name = name
+        self.__global_frames = frames
+        self.__tags = []
+
+    @property
+    def name(self):
+        return self.__name
+
+    @name.setter
+    def name(self, a_name):
+        self.__name = a_name
+
+    @property
+    def global_frames(self):
+        return self.__global_frames
+
+    def add_tag(self, tag):
+        self.__tags.append(tag)
+
+    def add_frame(self, frame):
+        self.__global_frames.append(frame)
+
+    def size(self):
+        return sum([each.global_frame_header.frame_length for each in self.__global_frames])
+
+    def frequencies(self):
+        &#34;&#34;&#34;I return a list of unique frequencies inside this container.&#34;&#34;&#34;
+        return list({each.global_frame_body.data_header.frequency for each in self.__global_frames})
+
+    def frame_types(self):
+        return list({each.global_frame_header.frame_type for each in self.__global_frames})
+
+    def frame_sizes(self):
+        return [each.global_frame_header.frame_length for each in self.__global_frames]
+
+    def unique_frame_sizes(self):
+        return list({each.global_frame_header.frame_length for each in self.__global_frames})
+
+    def is_homogenic(self):
+        return (len(self.unique_frame_sizes()) == 1) and (len(self.frame_types()) == 1)
+
+    def __str__(self):
+        start_time = self.__global_frames[0].global_frame_body.data_header.timestamp
+        end_time = self.__global_frames[-1].global_frame_body.data_header.timestamp
+
+        frq = str(self.__global_frames[0].global_frame_body.data_header.frequency)
+
+        return (&#34;Start time: &#34; + str(start_time) +
+                &#34;\nEnd time  : &#34; + str(end_time) + &#34;\nFrequencies: &#34; + frq)
+
+    def data_only(self):
+        return [each.global_frame_body.data_body.data for each in self.__global_frames]</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosContainer.AmmosContainer"><code class="flex name class">
+<span>class <span class="ident">AmmosContainer</span></span>
+<span>(</span><span>name, frames)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosContainer():
+
+    def __init__(self, name, frames):
+        self.__name = name
+        self.__global_frames = frames
+        self.__tags = []
+
+    @property
+    def name(self):
+        return self.__name
+
+    @name.setter
+    def name(self, a_name):
+        self.__name = a_name
+
+    @property
+    def global_frames(self):
+        return self.__global_frames
+
+    def add_tag(self, tag):
+        self.__tags.append(tag)
+
+    def add_frame(self, frame):
+        self.__global_frames.append(frame)
+
+    def size(self):
+        return sum([each.global_frame_header.frame_length for each in self.__global_frames])
+
+    def frequencies(self):
+        &#34;&#34;&#34;I return a list of unique frequencies inside this container.&#34;&#34;&#34;
+        return list({each.global_frame_body.data_header.frequency for each in self.__global_frames})
+
+    def frame_types(self):
+        return list({each.global_frame_header.frame_type for each in self.__global_frames})
+
+    def frame_sizes(self):
+        return [each.global_frame_header.frame_length for each in self.__global_frames]
+
+    def unique_frame_sizes(self):
+        return list({each.global_frame_header.frame_length for each in self.__global_frames})
+
+    def is_homogenic(self):
+        return (len(self.unique_frame_sizes()) == 1) and (len(self.frame_types()) == 1)
+
+    def __str__(self):
+        start_time = self.__global_frames[0].global_frame_body.data_header.timestamp
+        end_time = self.__global_frames[-1].global_frame_body.data_header.timestamp
+
+        frq = str(self.__global_frames[0].global_frame_body.data_header.frequency)
+
+        return (&#34;Start time: &#34; + str(start_time) +
+                &#34;\nEnd time  : &#34; + str(end_time) + &#34;\nFrequencies: &#34; + frq)
+
+    def data_only(self):
+        return [each.global_frame_body.data_body.data for each in self.__global_frames]</code></pre>
+</details>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.global_frames"><code class="name">var <span class="ident">global_frames</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def global_frames(self):
+    return self.__global_frames</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.name"><code class="name">var <span class="ident">name</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def name(self):
+    return self.__name</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.add_frame"><code class="name flex">
+<span>def <span class="ident">add_frame</span></span>(<span>self, frame)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def add_frame(self, frame):
+    self.__global_frames.append(frame)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.add_tag"><code class="name flex">
+<span>def <span class="ident">add_tag</span></span>(<span>self, tag)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def add_tag(self, tag):
+    self.__tags.append(tag)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.data_only"><code class="name flex">
+<span>def <span class="ident">data_only</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def data_only(self):
+    return [each.global_frame_body.data_body.data for each in self.__global_frames]</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.frame_sizes"><code class="name flex">
+<span>def <span class="ident">frame_sizes</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def frame_sizes(self):
+    return [each.global_frame_header.frame_length for each in self.__global_frames]</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.frame_types"><code class="name flex">
+<span>def <span class="ident">frame_types</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def frame_types(self):
+    return list({each.global_frame_header.frame_type for each in self.__global_frames})</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.frequencies"><code class="name flex">
+<span>def <span class="ident">frequencies</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return a list of unique frequencies inside this container.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def frequencies(self):
+    &#34;&#34;&#34;I return a list of unique frequencies inside this container.&#34;&#34;&#34;
+    return list({each.global_frame_body.data_header.frequency for each in self.__global_frames})</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.is_homogenic"><code class="name flex">
+<span>def <span class="ident">is_homogenic</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def is_homogenic(self):
+    return (len(self.unique_frame_sizes()) == 1) and (len(self.frame_types()) == 1)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.size"><code class="name flex">
+<span>def <span class="ident">size</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def size(self):
+    return sum([each.global_frame_header.frame_length for each in self.__global_frames])</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosContainer.AmmosContainer.unique_frame_sizes"><code class="name flex">
+<span>def <span class="ident">unique_frame_sizes</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def unique_frame_sizes(self):
+    return list({each.global_frame_header.frame_length for each in self.__global_frames})</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosContainer.AmmosContainer" href="#ammosreader.AmmosContainer.AmmosContainer">AmmosContainer</a></code></h4>
+<ul class="two-column">
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.add_frame" href="#ammosreader.AmmosContainer.AmmosContainer.add_frame">add_frame</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.add_tag" href="#ammosreader.AmmosContainer.AmmosContainer.add_tag">add_tag</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.data_only" href="#ammosreader.AmmosContainer.AmmosContainer.data_only">data_only</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.frame_sizes" href="#ammosreader.AmmosContainer.AmmosContainer.frame_sizes">frame_sizes</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.frame_types" href="#ammosreader.AmmosContainer.AmmosContainer.frame_types">frame_types</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.frequencies" href="#ammosreader.AmmosContainer.AmmosContainer.frequencies">frequencies</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.global_frames" href="#ammosreader.AmmosContainer.AmmosContainer.global_frames">global_frames</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.is_homogenic" href="#ammosreader.AmmosContainer.AmmosContainer.is_homogenic">is_homogenic</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.name" href="#ammosreader.AmmosContainer.AmmosContainer.name">name</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.size" href="#ammosreader.AmmosContainer.AmmosContainer.size">size</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer.AmmosContainer.unique_frame_sizes" href="#ammosreader.AmmosContainer.AmmosContainer.unique_frame_sizes">unique_frame_sizes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosExtendedAudioDataHeader.html
===================================================================
--- doc/ammosreader/AmmosExtendedAudioDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosExtendedAudioDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,197 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosExtendedAudioDataHeader API documentation</title>
+<meta name="description" content="I provide an Ammos extended data header for audio data frames." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosExtendedAudioDataHeader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide an Ammos extended data header for audio data frames.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide an Ammos extended data header for audio data frames.&#34;&#34;&#34;
+
+import struct
+from ammosreader.AmmosAudioDataHeader import AmmosAudioDataHeader
+
+
+class AmmosExtendedAudioDataHeader:
+
+    HEADER_SIZE = 44  # 11 words
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return a new AMMOS extended data header for audio frames built from given bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        standard_header = AmmosAudioDataHeader.from_bytes(bytes[0:AmmosAudioDataHeader.HEADER_SIZE])
+        extended_header_elements = struct.unpack(&#39;&lt;Q&#39;, bytes[AmmosAudioDataHeader.HEADER_SIZE:])
+        timestamp = extended_header_elements[0]
+        sample_rate = standard_header.sample_rate
+        status = standard_header.status
+        frequency = standard_header.frequency
+        demod_bandwidth = standard_header.demod_bandwidth
+        demod_type = standard_header.demod_type
+        number_of_samples = standard_header.number_of_samples
+        number_of_channels = standard_header.number_of_channels
+        sample_size = standard_header.sample_size
+        return AmmosExtendedAudioDataHeader(sample_rate, status, frequency, demod_bandwidth, demod_type,
+                                            number_of_samples, number_of_channels, sample_size, timestamp)
+
+    def __init__(self, sample_rate, status, frequency, demod_bandwidth, demod_type,
+                 number_of_samples, number_of_channels, sample_size, timestamp):
+        &#34;&#34;&#34;I return a new AMMOS extended data header for audio frames built from given parameters.&#34;&#34;&#34;
+        self.sample_rate = sample_rate
+        self.status = status
+        self.frequency = frequency
+        self.demod_bandwidth = demod_bandwidth
+        self.demod_type = demod_type
+        self.number_of_samples = number_of_samples
+        self.number_of_channels = number_of_channels
+        self.sample_size = sample_size
+        self.timestamp = timestamp</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader"><code class="flex name class">
+<span>class <span class="ident">AmmosExtendedAudioDataHeader</span></span>
+<span>(</span><span>sample_rate, status, frequency, demod_bandwidth, demod_type, number_of_samples, number_of_channels, sample_size, timestamp)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return a new AMMOS extended data header for audio frames built from given parameters.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosExtendedAudioDataHeader:
+
+    HEADER_SIZE = 44  # 11 words
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return a new AMMOS extended data header for audio frames built from given bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        standard_header = AmmosAudioDataHeader.from_bytes(bytes[0:AmmosAudioDataHeader.HEADER_SIZE])
+        extended_header_elements = struct.unpack(&#39;&lt;Q&#39;, bytes[AmmosAudioDataHeader.HEADER_SIZE:])
+        timestamp = extended_header_elements[0]
+        sample_rate = standard_header.sample_rate
+        status = standard_header.status
+        frequency = standard_header.frequency
+        demod_bandwidth = standard_header.demod_bandwidth
+        demod_type = standard_header.demod_type
+        number_of_samples = standard_header.number_of_samples
+        number_of_channels = standard_header.number_of_channels
+        sample_size = standard_header.sample_size
+        return AmmosExtendedAudioDataHeader(sample_rate, status, frequency, demod_bandwidth, demod_type,
+                                            number_of_samples, number_of_channels, sample_size, timestamp)
+
+    def __init__(self, sample_rate, status, frequency, demod_bandwidth, demod_type,
+                 number_of_samples, number_of_channels, sample_size, timestamp):
+        &#34;&#34;&#34;I return a new AMMOS extended data header for audio frames built from given parameters.&#34;&#34;&#34;
+        self.sample_rate = sample_rate
+        self.status = status
+        self.frequency = frequency
+        self.demod_bandwidth = demod_bandwidth
+        self.demod_type = demod_type
+        self.number_of_samples = number_of_samples
+        self.number_of_channels = number_of_channels
+        self.sample_size = sample_size
+        self.timestamp = timestamp</code></pre>
+</details>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader.HEADER_SIZE"><code class="name">var <span class="ident">HEADER_SIZE</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>bytes)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return a new AMMOS extended data header for audio frames built from given bytes.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, bytes):
+    &#34;&#34;&#34;I return a new AMMOS extended data header for audio frames built from given bytes.&#34;&#34;&#34;
+    assert len(bytes) == cls.HEADER_SIZE
+    standard_header = AmmosAudioDataHeader.from_bytes(bytes[0:AmmosAudioDataHeader.HEADER_SIZE])
+    extended_header_elements = struct.unpack(&#39;&lt;Q&#39;, bytes[AmmosAudioDataHeader.HEADER_SIZE:])
+    timestamp = extended_header_elements[0]
+    sample_rate = standard_header.sample_rate
+    status = standard_header.status
+    frequency = standard_header.frequency
+    demod_bandwidth = standard_header.demod_bandwidth
+    demod_type = standard_header.demod_type
+    number_of_samples = standard_header.number_of_samples
+    number_of_channels = standard_header.number_of_channels
+    sample_size = standard_header.sample_size
+    return AmmosExtendedAudioDataHeader(sample_rate, status, frequency, demod_bandwidth, demod_type,
+                                        number_of_samples, number_of_channels, sample_size, timestamp)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader" href="#ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader">AmmosExtendedAudioDataHeader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader.HEADER_SIZE" href="#ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader.HEADER_SIZE">HEADER_SIZE</a></code></li>
+<li><code><a title="ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader.from_bytes" href="#ammosreader.AmmosExtendedAudioDataHeader.AmmosExtendedAudioDataHeader.from_bytes">from_bytes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosExtendedIFDataHeader.html
===================================================================
--- doc/ammosreader/AmmosExtendedIFDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosExtendedIFDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,268 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosExtendedIFDataHeader API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosExtendedIFDataHeader</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">import struct
+import numpy as np
+from ammosreader.AmmosIFDataHeader import AmmosIFDataHeader
+
+
+class AmmosExtendedIFDataHeader():
+    &#34;&#34;&#34;I implement an Ammos extended data header for IF data frames.&#34;&#34;&#34;
+
+    HEADER_SIZE = 76
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS extended data header from given bytes.&#34;&#34;&#34;
+        standard_header = AmmosIFDataHeader.from_bytes(bytes[0:AmmosIFDataHeader.HEADER_SIZE])
+        extended_header_elements = struct.unpack(&#39;&lt;QQI&#39;, bytes[AmmosIFDataHeader.HEADER_SIZE:cls.HEADER_SIZE])
+        block_count = standard_header.block_count
+        block_length = standard_header.block_length
+        timestamp = standard_header.timestamp
+        status = standard_header.status
+        source_id = standard_header.source_id
+        source_state = standard_header.source_state
+        frequency = standard_header.frequency
+        bandwidth = standard_header.bandwidth
+        sample_rate = standard_header.sample_rate
+        interpolation = standard_header.interpolation
+        decimation = standard_header.decimation
+        voltage_ref = standard_header.voltage_ref
+        stream_start = np.datetime64(int(extended_header_elements[0]), &#39;ns&#39;)
+        sample_counter = extended_header_elements[1]
+        antenna_correction = extended_header_elements[2]
+        size = len(bytes)
+        return AmmosExtendedIFDataHeader(size, block_count, block_length, timestamp, status, source_id,
+                                         source_state, frequency, bandwidth, sample_rate, interpolation,
+                                         decimation, voltage_ref, stream_start, sample_counter,
+                                         antenna_correction)
+
+    def __init__(self, size, block_count, block_length, timestamp, status, source_id, source_state, frequency,
+                 bandwidth, sample_rate, interpolation, decimation, voltage_ref, stream_start, sample_counter,
+                 antenna_correction):
+        &#34;&#34;&#34;I create a new instance of myself using the above parameters.&#34;&#34;&#34;
+        self.size = size
+        self.block_count = block_count
+        self.block_length = block_length
+        self.timestamp = timestamp
+        self.status = status
+        self.source_id = source_id
+        self.source_state = source_state
+        self.frequency = frequency
+        self.bandwidth = bandwidth
+        self.sample_rate = sample_rate
+        self.interpolation = interpolation
+        self.decimation = decimation
+        self.voltage_ref = voltage_ref
+        self.stream_start = stream_start
+        self.sample_counter = sample_counter
+        self.antenna_correction = antenna_correction
+
+    def __str__(self):
+        output = (
+            &#34;\nGlobal frame body data header\n&#34; +
+            &#34;-----------------------------\n&#34; +
+            &#34;Block count:&#34; + str(self.block_count) + &#34;\n&#34; +
+            &#34;Block length:&#34; + str(self.block_length) + &#34;\n&#34; +
+            &#34;Time stamp:&#34; + str(self.timestamp) + &#34;\n&#34; +
+            &#34;Frequency:&#34; + str(self.frequency) + &#34;\n&#34; +
+            &#34;Bandwidth:&#34; + str(self.bandwidth) + &#34;\n&#34; +
+            &#34;Sample rate:&#34; + str(self.sample_rate) + &#34;\n&#34; +
+            &#34;Stream start:&#34; + str(self.stream_start) + &#34;\n&#34; +
+            &#34;Sample counter:&#34; + str(self.sample_counter) + &#34;\n&#34; +
+            &#34;Antenna correction:&#34; + str(self.antenna_correction) + &#34;\n&#34;)
+        return output</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader"><code class="flex name class">
+<span>class <span class="ident">AmmosExtendedIFDataHeader</span></span>
+<span>(</span><span>size, block_count, block_length, timestamp, status, source_id, source_state, frequency, bandwidth, sample_rate, interpolation, decimation, voltage_ref, stream_start, sample_counter, antenna_correction)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an Ammos extended data header for IF data frames.</p>
+<p>I create a new instance of myself using the above parameters.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosExtendedIFDataHeader():
+    &#34;&#34;&#34;I implement an Ammos extended data header for IF data frames.&#34;&#34;&#34;
+
+    HEADER_SIZE = 76
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS extended data header from given bytes.&#34;&#34;&#34;
+        standard_header = AmmosIFDataHeader.from_bytes(bytes[0:AmmosIFDataHeader.HEADER_SIZE])
+        extended_header_elements = struct.unpack(&#39;&lt;QQI&#39;, bytes[AmmosIFDataHeader.HEADER_SIZE:cls.HEADER_SIZE])
+        block_count = standard_header.block_count
+        block_length = standard_header.block_length
+        timestamp = standard_header.timestamp
+        status = standard_header.status
+        source_id = standard_header.source_id
+        source_state = standard_header.source_state
+        frequency = standard_header.frequency
+        bandwidth = standard_header.bandwidth
+        sample_rate = standard_header.sample_rate
+        interpolation = standard_header.interpolation
+        decimation = standard_header.decimation
+        voltage_ref = standard_header.voltage_ref
+        stream_start = np.datetime64(int(extended_header_elements[0]), &#39;ns&#39;)
+        sample_counter = extended_header_elements[1]
+        antenna_correction = extended_header_elements[2]
+        size = len(bytes)
+        return AmmosExtendedIFDataHeader(size, block_count, block_length, timestamp, status, source_id,
+                                         source_state, frequency, bandwidth, sample_rate, interpolation,
+                                         decimation, voltage_ref, stream_start, sample_counter,
+                                         antenna_correction)
+
+    def __init__(self, size, block_count, block_length, timestamp, status, source_id, source_state, frequency,
+                 bandwidth, sample_rate, interpolation, decimation, voltage_ref, stream_start, sample_counter,
+                 antenna_correction):
+        &#34;&#34;&#34;I create a new instance of myself using the above parameters.&#34;&#34;&#34;
+        self.size = size
+        self.block_count = block_count
+        self.block_length = block_length
+        self.timestamp = timestamp
+        self.status = status
+        self.source_id = source_id
+        self.source_state = source_state
+        self.frequency = frequency
+        self.bandwidth = bandwidth
+        self.sample_rate = sample_rate
+        self.interpolation = interpolation
+        self.decimation = decimation
+        self.voltage_ref = voltage_ref
+        self.stream_start = stream_start
+        self.sample_counter = sample_counter
+        self.antenna_correction = antenna_correction
+
+    def __str__(self):
+        output = (
+            &#34;\nGlobal frame body data header\n&#34; +
+            &#34;-----------------------------\n&#34; +
+            &#34;Block count:&#34; + str(self.block_count) + &#34;\n&#34; +
+            &#34;Block length:&#34; + str(self.block_length) + &#34;\n&#34; +
+            &#34;Time stamp:&#34; + str(self.timestamp) + &#34;\n&#34; +
+            &#34;Frequency:&#34; + str(self.frequency) + &#34;\n&#34; +
+            &#34;Bandwidth:&#34; + str(self.bandwidth) + &#34;\n&#34; +
+            &#34;Sample rate:&#34; + str(self.sample_rate) + &#34;\n&#34; +
+            &#34;Stream start:&#34; + str(self.stream_start) + &#34;\n&#34; +
+            &#34;Sample counter:&#34; + str(self.sample_counter) + &#34;\n&#34; +
+            &#34;Antenna correction:&#34; + str(self.antenna_correction) + &#34;\n&#34;)
+        return output</code></pre>
+</details>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader.HEADER_SIZE"><code class="name">var <span class="ident">HEADER_SIZE</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>bytes)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return an AMMOS extended data header from given bytes.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, bytes):
+    &#34;&#34;&#34;I return an AMMOS extended data header from given bytes.&#34;&#34;&#34;
+    standard_header = AmmosIFDataHeader.from_bytes(bytes[0:AmmosIFDataHeader.HEADER_SIZE])
+    extended_header_elements = struct.unpack(&#39;&lt;QQI&#39;, bytes[AmmosIFDataHeader.HEADER_SIZE:cls.HEADER_SIZE])
+    block_count = standard_header.block_count
+    block_length = standard_header.block_length
+    timestamp = standard_header.timestamp
+    status = standard_header.status
+    source_id = standard_header.source_id
+    source_state = standard_header.source_state
+    frequency = standard_header.frequency
+    bandwidth = standard_header.bandwidth
+    sample_rate = standard_header.sample_rate
+    interpolation = standard_header.interpolation
+    decimation = standard_header.decimation
+    voltage_ref = standard_header.voltage_ref
+    stream_start = np.datetime64(int(extended_header_elements[0]), &#39;ns&#39;)
+    sample_counter = extended_header_elements[1]
+    antenna_correction = extended_header_elements[2]
+    size = len(bytes)
+    return AmmosExtendedIFDataHeader(size, block_count, block_length, timestamp, status, source_id,
+                                     source_state, frequency, bandwidth, sample_rate, interpolation,
+                                     decimation, voltage_ref, stream_start, sample_counter,
+                                     antenna_correction)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader" href="#ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader">AmmosExtendedIFDataHeader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader.HEADER_SIZE" href="#ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader.HEADER_SIZE">HEADER_SIZE</a></code></li>
+<li><code><a title="ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader.from_bytes" href="#ammosreader.AmmosExtendedIFDataHeader.AmmosExtendedIFDataHeader.from_bytes">from_bytes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosGlobalFrameBody.html
===================================================================
--- doc/ammosreader/AmmosGlobalFrameBody.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosGlobalFrameBody.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,197 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosGlobalFrameBody API documentation</title>
+<meta name="description" content="I provide an AMMOS global frame body." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosGlobalFrameBody</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide an AMMOS global frame body.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide an AMMOS global frame body.&#34;&#34;&#34;
+
+class AmmosGlobalFrameBody():
+    &#34;&#34;&#34;
+    I implement an AMMOS global frame body.
+
+    AMMOS frames can store data of various types.
+    The data is described in the data header.
+    The raw data is then stored in the data body.
+    &#34;&#34;&#34;
+    def __init__(self, data_header, data_body):
+        self.__data_header = data_header
+        self.__data_body = data_body
+
+    @property
+    def data_header(self):
+        return self.__data_header
+
+    @data_header.setter
+    def data_header(self, a_data_header):
+        self.__data_header = a_data_header
+
+    @property
+    def data_body(self):
+        return self.__data_body
+
+    @data_body.setter
+    def data_body(self, data_bytes):
+        self.__data_body = data_bytes
+
+    def payload(self):
+        &#34;&#34;&#34;I return the payload only.&#34;&#34;&#34;
+        return b&#34;&#34;.join([each_block.data for each_block in self.data_body])</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody"><code class="flex name class">
+<span>class <span class="ident">AmmosGlobalFrameBody</span></span>
+<span>(</span><span>data_header, data_body)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an AMMOS global frame body.</p>
+<p>AMMOS frames can store data of various types.
+The data is described in the data header.
+The raw data is then stored in the data body.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosGlobalFrameBody():
+    &#34;&#34;&#34;
+    I implement an AMMOS global frame body.
+
+    AMMOS frames can store data of various types.
+    The data is described in the data header.
+    The raw data is then stored in the data body.
+    &#34;&#34;&#34;
+    def __init__(self, data_header, data_body):
+        self.__data_header = data_header
+        self.__data_body = data_body
+
+    @property
+    def data_header(self):
+        return self.__data_header
+
+    @data_header.setter
+    def data_header(self, a_data_header):
+        self.__data_header = a_data_header
+
+    @property
+    def data_body(self):
+        return self.__data_body
+
+    @data_body.setter
+    def data_body(self, data_bytes):
+        self.__data_body = data_bytes
+
+    def payload(self):
+        &#34;&#34;&#34;I return the payload only.&#34;&#34;&#34;
+        return b&#34;&#34;.join([each_block.data for each_block in self.data_body])</code></pre>
+</details>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.data_body"><code class="name">var <span class="ident">data_body</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def data_body(self):
+    return self.__data_body</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.data_header"><code class="name">var <span class="ident">data_header</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def data_header(self):
+    return self.__data_header</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.payload"><code class="name flex">
+<span>def <span class="ident">payload</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the payload only.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def payload(self):
+    &#34;&#34;&#34;I return the payload only.&#34;&#34;&#34;
+    return b&#34;&#34;.join([each_block.data for each_block in self.data_body])</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody" href="#ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody">AmmosGlobalFrameBody</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.data_body" href="#ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.data_body">data_body</a></code></li>
+<li><code><a title="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.data_header" href="#ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.data_header">data_header</a></code></li>
+<li><code><a title="ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.payload" href="#ammosreader.AmmosGlobalFrameBody.AmmosGlobalFrameBody.payload">payload</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosGlobalFrameHeader.html
===================================================================
--- doc/ammosreader/AmmosGlobalFrameHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosGlobalFrameHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,251 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosGlobalFrameHeader API documentation</title>
+<meta name="description" content="I provide an AMMOS global frame header." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosGlobalFrameHeader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide an AMMOS global frame header.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide an AMMOS global frame header.&#34;&#34;&#34;
+import struct
+import logging
+
+logging.basicConfig(filename=&#39;ammos.log&#39;, level=logging.DEBUG)
+
+
+class AmmosGlobalFrameHeader:
+    &#34;&#34;&#34;I implement an AMMOS global frame header.&#34;&#34;&#34;
+
+    MAGIC_WORD = &#34;726574fb&#34;
+    HEADER_SIZE = 24
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I create a new AmmosGlobalFrameHeader from bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+
+        elements = struct.unpack(&#39;&lt;4s4s4s4s4s4s&#39;, bytes)
+
+        magic_word = elements[0].hex()
+
+        if magic_word != cls.MAGIC_WORD:
+            return None
+
+        frame_length = (int.from_bytes(elements[1], byteorder=&#39;little&#39;)*4)
+
+        running_frame_number = (int.from_bytes(elements[2], byteorder=&#39;little&#39;))
+
+        frame_type = (int.from_bytes(elements[3], byteorder=&#39;little&#39;))
+
+        data_header_length = 4 * int.from_bytes(elements[4], byteorder=&#39;little&#39;)
+
+        reserved = elements[5]
+
+        return AmmosGlobalFrameHeader(magic_word, frame_length, running_frame_number,
+                                      frame_type, data_header_length, reserved)
+
+    def __init__(self, magic_word, frame_length, running_frame_number, frame_type, data_header_length, reserved):
+        &#34;&#34;&#34;I return a new instance of myself initialized with above parameters.&#34;&#34;&#34;
+        if magic_word != type(self).MAGIC_WORD:
+            logging.error(&#34;Wrong magic word found&#34;)
+            self.magic_word = magic_word
+        else:
+            self.magic_word = magic_word
+            self.frame_length = frame_length
+            self.running_frame_number = running_frame_number
+            self.frame_type = frame_type
+            self.data_header_length = data_header_length
+            self.reserved = reserved
+
+    def __str__(self):
+        &#34;&#34;&#34;I return the string representation of myself.&#34;&#34;&#34;
+        output = (&#34;Global frame header info\n&#34; +
+                  &#34;------------------------\n&#34; +
+                  &#34;Magic word:&#34; + str(self.magic_word) + &#34;\n&#34; +
+                  &#34;Frame length:&#34; + str(self.frame_length) + &#34;\n&#34; +
+                  &#34;Running frame:&#34; + str(self.running_frame_number) + &#34;\n&#34; +
+                  &#34;Frame Type:&#34; + str(self.frame_type) + &#34;\n&#34; +
+                  &#34;Data header length:&#34; + str(self.data_header_length) + &#34;\n&#34;)
+        return output</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader"><code class="flex name class">
+<span>class <span class="ident">AmmosGlobalFrameHeader</span></span>
+<span>(</span><span>magic_word, frame_length, running_frame_number, frame_type, data_header_length, reserved)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an AMMOS global frame header.</p>
+<p>I return a new instance of myself initialized with above parameters.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosGlobalFrameHeader:
+    &#34;&#34;&#34;I implement an AMMOS global frame header.&#34;&#34;&#34;
+
+    MAGIC_WORD = &#34;726574fb&#34;
+    HEADER_SIZE = 24
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I create a new AmmosGlobalFrameHeader from bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+
+        elements = struct.unpack(&#39;&lt;4s4s4s4s4s4s&#39;, bytes)
+
+        magic_word = elements[0].hex()
+
+        if magic_word != cls.MAGIC_WORD:
+            return None
+
+        frame_length = (int.from_bytes(elements[1], byteorder=&#39;little&#39;)*4)
+
+        running_frame_number = (int.from_bytes(elements[2], byteorder=&#39;little&#39;))
+
+        frame_type = (int.from_bytes(elements[3], byteorder=&#39;little&#39;))
+
+        data_header_length = 4 * int.from_bytes(elements[4], byteorder=&#39;little&#39;)
+
+        reserved = elements[5]
+
+        return AmmosGlobalFrameHeader(magic_word, frame_length, running_frame_number,
+                                      frame_type, data_header_length, reserved)
+
+    def __init__(self, magic_word, frame_length, running_frame_number, frame_type, data_header_length, reserved):
+        &#34;&#34;&#34;I return a new instance of myself initialized with above parameters.&#34;&#34;&#34;
+        if magic_word != type(self).MAGIC_WORD:
+            logging.error(&#34;Wrong magic word found&#34;)
+            self.magic_word = magic_word
+        else:
+            self.magic_word = magic_word
+            self.frame_length = frame_length
+            self.running_frame_number = running_frame_number
+            self.frame_type = frame_type
+            self.data_header_length = data_header_length
+            self.reserved = reserved
+
+    def __str__(self):
+        &#34;&#34;&#34;I return the string representation of myself.&#34;&#34;&#34;
+        output = (&#34;Global frame header info\n&#34; +
+                  &#34;------------------------\n&#34; +
+                  &#34;Magic word:&#34; + str(self.magic_word) + &#34;\n&#34; +
+                  &#34;Frame length:&#34; + str(self.frame_length) + &#34;\n&#34; +
+                  &#34;Running frame:&#34; + str(self.running_frame_number) + &#34;\n&#34; +
+                  &#34;Frame Type:&#34; + str(self.frame_type) + &#34;\n&#34; +
+                  &#34;Data header length:&#34; + str(self.data_header_length) + &#34;\n&#34;)
+        return output</code></pre>
+</details>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.HEADER_SIZE"><code class="name">var <span class="ident">HEADER_SIZE</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt id="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.MAGIC_WORD"><code class="name">var <span class="ident">MAGIC_WORD</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>bytes)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I create a new AmmosGlobalFrameHeader from bytes.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, bytes):
+    &#34;&#34;&#34;I create a new AmmosGlobalFrameHeader from bytes.&#34;&#34;&#34;
+    assert len(bytes) == cls.HEADER_SIZE
+
+    elements = struct.unpack(&#39;&lt;4s4s4s4s4s4s&#39;, bytes)
+
+    magic_word = elements[0].hex()
+
+    if magic_word != cls.MAGIC_WORD:
+        return None
+
+    frame_length = (int.from_bytes(elements[1], byteorder=&#39;little&#39;)*4)
+
+    running_frame_number = (int.from_bytes(elements[2], byteorder=&#39;little&#39;))
+
+    frame_type = (int.from_bytes(elements[3], byteorder=&#39;little&#39;))
+
+    data_header_length = 4 * int.from_bytes(elements[4], byteorder=&#39;little&#39;)
+
+    reserved = elements[5]
+
+    return AmmosGlobalFrameHeader(magic_word, frame_length, running_frame_number,
+                                  frame_type, data_header_length, reserved)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader" href="#ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader">AmmosGlobalFrameHeader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.HEADER_SIZE" href="#ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.HEADER_SIZE">HEADER_SIZE</a></code></li>
+<li><code><a title="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.MAGIC_WORD" href="#ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.MAGIC_WORD">MAGIC_WORD</a></code></li>
+<li><code><a title="ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.from_bytes" href="#ammosreader.AmmosGlobalFrameHeader.AmmosGlobalFrameHeader.from_bytes">from_bytes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosIFDataBlock.html
===================================================================
--- doc/ammosreader/AmmosIFDataBlock.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosIFDataBlock.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,137 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosIFDataBlock API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosIFDataBlock</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosIFDataBlock:
+
+    def __init__(self, header, data):
+        self.__header = header
+        self.__data = data
+
+    @property
+    def header(self):
+        return self.__header
+
+    @property
+    def payload(self):
+        return self.__data</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosIFDataBlock.AmmosIFDataBlock"><code class="flex name class">
+<span>class <span class="ident">AmmosIFDataBlock</span></span>
+<span>(</span><span>header, data)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosIFDataBlock:
+
+    def __init__(self, header, data):
+        self.__header = header
+        self.__data = data
+
+    @property
+    def header(self):
+        return self.__header
+
+    @property
+    def payload(self):
+        return self.__data</code></pre>
+</details>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataBlock.AmmosIFDataBlock.header"><code class="name">var <span class="ident">header</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def header(self):
+    return self.__header</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFDataBlock.AmmosIFDataBlock.payload"><code class="name">var <span class="ident">payload</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def payload(self):
+    return self.__data</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosIFDataBlock.AmmosIFDataBlock" href="#ammosreader.AmmosIFDataBlock.AmmosIFDataBlock">AmmosIFDataBlock</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosIFDataBlock.AmmosIFDataBlock.header" href="#ammosreader.AmmosIFDataBlock.AmmosIFDataBlock.header">header</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlock.AmmosIFDataBlock.payload" href="#ammosreader.AmmosIFDataBlock.AmmosIFDataBlock.payload">payload</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosIFDataBlockHeader.html
===================================================================
--- doc/ammosreader/AmmosIFDataBlockHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosIFDataBlockHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,325 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosIFDataBlockHeader API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosIFDataBlockHeader</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">import struct
+
+
+class AmmosIFDataBlockHeader:
+    &#34;&#34;&#34;I implement an AMMOS IF data block header.&#34;&#34;&#34;
+
+    HEADER_SIZE = 4
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS IF data block header built from bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        elements = struct.unpack(&#39;&lt;ccH&#39;, bytes)
+        header = cls()
+        first_entry = int.from_bytes(elements[0], byteorder=&#39;little&#39;)
+        header.invalidity = ((first_entry &amp; 1) == 1)
+        header.blanking = ((first_entry &amp; 2) == 1)
+        header.user_data = ((first_entry &amp; 252))
+        header.reserved = int.from_bytes(elements[1], byteorder=&#39;little&#39;)
+        header.reciprocal_gain = elements[2]
+        return header
+
+    def __init__(self):
+        &#34;&#34;&#34;I return an AMMOS IF data block header initialized with sane default values.&#34;&#34;&#34;
+        self.__invalidity = True
+        self.__blanking = False
+        self.__user_data = 0
+        self.__reserved = 0
+        self.__reciprocal_gain = 0
+
+    @property
+    def invalidity(self):
+        return self.__invalidity
+
+    @invalidity.setter
+    def invalidity(self, a_boolean):
+        self.__invalidity = a_boolean
+
+    @property
+    def blanking(self):
+        return self.__blanking
+
+    @blanking.setter
+    def blanking(self, a_boolean):
+        self.__blanking = a_boolean
+
+    @property
+    def user_data(self):
+        return self.__user_data
+
+    @user_data.setter
+    def user_data(self, some_data):
+        self.__user_data = some_data
+
+    @property
+    def reserved(self):
+        return self.__reserved
+
+    @reserved.setter
+    def reserved(self, some_data):
+        assert some_data == 0
+        self.__reserved = some_data
+
+    @property
+    def reciprocal_gain(self):
+        return self.__reciprocal_gain
+
+    @reciprocal_gain.setter
+    def reciprocal_gain(self, a_gain_value):
+        assert 0 &lt;= a_gain_value &lt; pow(2, 16)
+        self.__reciprocal_gain = a_gain_value</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader"><code class="flex name class">
+<span>class <span class="ident">AmmosIFDataBlockHeader</span></span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an AMMOS IF data block header.</p>
+<p>I return an AMMOS IF data block header initialized with sane default values.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosIFDataBlockHeader:
+    &#34;&#34;&#34;I implement an AMMOS IF data block header.&#34;&#34;&#34;
+
+    HEADER_SIZE = 4
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS IF data block header built from bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        elements = struct.unpack(&#39;&lt;ccH&#39;, bytes)
+        header = cls()
+        first_entry = int.from_bytes(elements[0], byteorder=&#39;little&#39;)
+        header.invalidity = ((first_entry &amp; 1) == 1)
+        header.blanking = ((first_entry &amp; 2) == 1)
+        header.user_data = ((first_entry &amp; 252))
+        header.reserved = int.from_bytes(elements[1], byteorder=&#39;little&#39;)
+        header.reciprocal_gain = elements[2]
+        return header
+
+    def __init__(self):
+        &#34;&#34;&#34;I return an AMMOS IF data block header initialized with sane default values.&#34;&#34;&#34;
+        self.__invalidity = True
+        self.__blanking = False
+        self.__user_data = 0
+        self.__reserved = 0
+        self.__reciprocal_gain = 0
+
+    @property
+    def invalidity(self):
+        return self.__invalidity
+
+    @invalidity.setter
+    def invalidity(self, a_boolean):
+        self.__invalidity = a_boolean
+
+    @property
+    def blanking(self):
+        return self.__blanking
+
+    @blanking.setter
+    def blanking(self, a_boolean):
+        self.__blanking = a_boolean
+
+    @property
+    def user_data(self):
+        return self.__user_data
+
+    @user_data.setter
+    def user_data(self, some_data):
+        self.__user_data = some_data
+
+    @property
+    def reserved(self):
+        return self.__reserved
+
+    @reserved.setter
+    def reserved(self, some_data):
+        assert some_data == 0
+        self.__reserved = some_data
+
+    @property
+    def reciprocal_gain(self):
+        return self.__reciprocal_gain
+
+    @reciprocal_gain.setter
+    def reciprocal_gain(self, a_gain_value):
+        assert 0 &lt;= a_gain_value &lt; pow(2, 16)
+        self.__reciprocal_gain = a_gain_value</code></pre>
+</details>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.HEADER_SIZE"><code class="name">var <span class="ident">HEADER_SIZE</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>bytes)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return an AMMOS IF data block header built from bytes.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, bytes):
+    &#34;&#34;&#34;I return an AMMOS IF data block header built from bytes.&#34;&#34;&#34;
+    assert len(bytes) == cls.HEADER_SIZE
+    elements = struct.unpack(&#39;&lt;ccH&#39;, bytes)
+    header = cls()
+    first_entry = int.from_bytes(elements[0], byteorder=&#39;little&#39;)
+    header.invalidity = ((first_entry &amp; 1) == 1)
+    header.blanking = ((first_entry &amp; 2) == 1)
+    header.user_data = ((first_entry &amp; 252))
+    header.reserved = int.from_bytes(elements[1], byteorder=&#39;little&#39;)
+    header.reciprocal_gain = elements[2]
+    return header</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.blanking"><code class="name">var <span class="ident">blanking</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def blanking(self):
+    return self.__blanking</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.invalidity"><code class="name">var <span class="ident">invalidity</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def invalidity(self):
+    return self.__invalidity</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.reciprocal_gain"><code class="name">var <span class="ident">reciprocal_gain</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def reciprocal_gain(self):
+    return self.__reciprocal_gain</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.reserved"><code class="name">var <span class="ident">reserved</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def reserved(self):
+    return self.__reserved</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.user_data"><code class="name">var <span class="ident">user_data</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def user_data(self):
+    return self.__user_data</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader">AmmosIFDataBlockHeader</a></code></h4>
+<ul class="two-column">
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.HEADER_SIZE" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.HEADER_SIZE">HEADER_SIZE</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.blanking" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.blanking">blanking</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.from_bytes" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.from_bytes">from_bytes</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.invalidity" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.invalidity">invalidity</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.reciprocal_gain" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.reciprocal_gain">reciprocal_gain</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.reserved" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.reserved">reserved</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.user_data" href="#ammosreader.AmmosIFDataBlockHeader.AmmosIFDataBlockHeader.user_data">user_data</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosIFDataBody.html
===================================================================
--- doc/ammosreader/AmmosIFDataBody.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosIFDataBody.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,172 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosIFDataBody API documentation</title>
+<meta name="description" content="I provide an AMMOS data body for IF data …" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosIFDataBody</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide an AMMOS data body for IF data.</p>
+<p>I manage multiple IF data blocks</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;
+I provide an AMMOS data body for IF data.
+
+I manage multiple IF data blocks
+&#34;&#34;&#34;
+
+class AmmosIFDataBody:
+    &#34;&#34;&#34;I implement an AMMOS data body for IF data.&#34;&#34;&#34;
+    def __init__(self, data_blocks=None):
+        if data_blocks is None:
+            self.__data_blocks = []
+        else:
+            self.__data_blocks = data_blocks
+
+    @property
+    def data_blocks(self):
+        return self.__data_blocks
+
+    def add_data_block(self, a_data_block):
+        self.__data_blocks.append(a_data_block)
+
+    @property
+    def payload(self):
+        return b&#34;&#34;.join([each.payload for each in self.data_blocks])</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosIFDataBody.AmmosIFDataBody"><code class="flex name class">
+<span>class <span class="ident">AmmosIFDataBody</span></span>
+<span>(</span><span>data_blocks=None)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an AMMOS data body for IF data.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosIFDataBody:
+    &#34;&#34;&#34;I implement an AMMOS data body for IF data.&#34;&#34;&#34;
+    def __init__(self, data_blocks=None):
+        if data_blocks is None:
+            self.__data_blocks = []
+        else:
+            self.__data_blocks = data_blocks
+
+    @property
+    def data_blocks(self):
+        return self.__data_blocks
+
+    def add_data_block(self, a_data_block):
+        self.__data_blocks.append(a_data_block)
+
+    @property
+    def payload(self):
+        return b&#34;&#34;.join([each.payload for each in self.data_blocks])</code></pre>
+</details>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataBody.AmmosIFDataBody.data_blocks"><code class="name">var <span class="ident">data_blocks</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def data_blocks(self):
+    return self.__data_blocks</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFDataBody.AmmosIFDataBody.payload"><code class="name">var <span class="ident">payload</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def payload(self):
+    return b&#34;&#34;.join([each.payload for each in self.data_blocks])</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataBody.AmmosIFDataBody.add_data_block"><code class="name flex">
+<span>def <span class="ident">add_data_block</span></span>(<span>self, a_data_block)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def add_data_block(self, a_data_block):
+    self.__data_blocks.append(a_data_block)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosIFDataBody.AmmosIFDataBody" href="#ammosreader.AmmosIFDataBody.AmmosIFDataBody">AmmosIFDataBody</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosIFDataBody.AmmosIFDataBody.add_data_block" href="#ammosreader.AmmosIFDataBody.AmmosIFDataBody.add_data_block">add_data_block</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBody.AmmosIFDataBody.data_blocks" href="#ammosreader.AmmosIFDataBody.AmmosIFDataBody.data_blocks">data_blocks</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBody.AmmosIFDataBody.payload" href="#ammosreader.AmmosIFDataBody.AmmosIFDataBody.payload">payload</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosIFDataHeader.html
===================================================================
--- doc/ammosreader/AmmosIFDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosIFDataHeader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,240 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosIFDataHeader API documentation</title>
+<meta name="description" content="I provide a Ammos data header for IF data frames." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosIFDataHeader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide a Ammos data header for IF data frames.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide a Ammos data header for IF data frames.&#34;&#34;&#34;
+
+import struct
+import numpy as np
+
+
+class AmmosIFDataHeader():
+    &#34;&#34;&#34;I implement an Ammos data header for IF data frames.&#34;&#34;&#34;
+
+    HEADER_SIZE = 56
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS data header from given bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        elements = struct.unpack(&#39;&lt;IIQIIIQIIIIi&#39;, bytes)
+        block_count = elements[0]
+        block_length = int(elements[1])*4
+        timestamp = np.datetime64(int(elements[2])*1000, &#39;ns&#39;)
+        status = elements[3]
+        source_id = elements[4]
+        source_state = elements[5]
+        frequency = elements[6]
+        bandwidth = elements[7]
+        sample_rate = elements[8]
+        interpolation = elements[9]
+        decimation = elements[10]
+        voltage_ref = elements[11]
+
+        return AmmosIFDataHeader(block_count, block_length, timestamp, status, source_id,
+                                 source_state, frequency, bandwidth, sample_rate,
+                                 interpolation, decimation, voltage_ref)
+
+    def __init__(self, block_count, block_length, timestamp, status, source_id, source_state, frequency,
+                 bandwidth, sample_rate, interpolation, decimation, voltage_ref):
+        &#34;&#34;&#34;I create a new instance of myself using the above parameters.&#34;&#34;&#34;
+        self.block_count = block_count
+        self.block_length = block_length
+        self.timestamp = timestamp
+        self.status = status
+        self.source_id = source_id
+        self.source_state = source_state
+        self.frequency = frequency
+        self.bandwidth = bandwidth
+        self.sample_rate = sample_rate
+        self.interpolation = interpolation
+        self.decimation = decimation
+        self.voltage_ref = voltage_ref
+
+    def __str_(self):
+        output = (&#34;\nGlobal frame body data header\n&#34; +
+                  &#34;-----------------------------\n&#34; +
+                  &#34;Block count:&#34; + str(self.block_count) + &#34;\n&#34; +
+                  &#34;Block length:&#34; + str(self.block_length) + &#34;\n&#34; +
+                  &#34;Time stamp:&#34; + str(self.timestamp) + &#34;\n&#34; +
+                  &#34;Frequency:&#34; + str(self.frequency) + &#34;\n&#34; +
+                  &#34;Bandwidth:&#34; + str(self.bandwidth) + &#34;\n&#34; +
+                  &#34;Sample rate:&#34; + str(self.sample_rate) + &#34;\n&#34;)
+        return output</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosIFDataHeader.AmmosIFDataHeader"><code class="flex name class">
+<span>class <span class="ident">AmmosIFDataHeader</span></span>
+<span>(</span><span>block_count, block_length, timestamp, status, source_id, source_state, frequency, bandwidth, sample_rate, interpolation, decimation, voltage_ref)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I implement an Ammos data header for IF data frames.</p>
+<p>I create a new instance of myself using the above parameters.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosIFDataHeader():
+    &#34;&#34;&#34;I implement an Ammos data header for IF data frames.&#34;&#34;&#34;
+
+    HEADER_SIZE = 56
+
+    @classmethod
+    def from_bytes(cls, bytes):
+        &#34;&#34;&#34;I return an AMMOS data header from given bytes.&#34;&#34;&#34;
+        assert len(bytes) == cls.HEADER_SIZE
+        elements = struct.unpack(&#39;&lt;IIQIIIQIIIIi&#39;, bytes)
+        block_count = elements[0]
+        block_length = int(elements[1])*4
+        timestamp = np.datetime64(int(elements[2])*1000, &#39;ns&#39;)
+        status = elements[3]
+        source_id = elements[4]
+        source_state = elements[5]
+        frequency = elements[6]
+        bandwidth = elements[7]
+        sample_rate = elements[8]
+        interpolation = elements[9]
+        decimation = elements[10]
+        voltage_ref = elements[11]
+
+        return AmmosIFDataHeader(block_count, block_length, timestamp, status, source_id,
+                                 source_state, frequency, bandwidth, sample_rate,
+                                 interpolation, decimation, voltage_ref)
+
+    def __init__(self, block_count, block_length, timestamp, status, source_id, source_state, frequency,
+                 bandwidth, sample_rate, interpolation, decimation, voltage_ref):
+        &#34;&#34;&#34;I create a new instance of myself using the above parameters.&#34;&#34;&#34;
+        self.block_count = block_count
+        self.block_length = block_length
+        self.timestamp = timestamp
+        self.status = status
+        self.source_id = source_id
+        self.source_state = source_state
+        self.frequency = frequency
+        self.bandwidth = bandwidth
+        self.sample_rate = sample_rate
+        self.interpolation = interpolation
+        self.decimation = decimation
+        self.voltage_ref = voltage_ref
+
+    def __str_(self):
+        output = (&#34;\nGlobal frame body data header\n&#34; +
+                  &#34;-----------------------------\n&#34; +
+                  &#34;Block count:&#34; + str(self.block_count) + &#34;\n&#34; +
+                  &#34;Block length:&#34; + str(self.block_length) + &#34;\n&#34; +
+                  &#34;Time stamp:&#34; + str(self.timestamp) + &#34;\n&#34; +
+                  &#34;Frequency:&#34; + str(self.frequency) + &#34;\n&#34; +
+                  &#34;Bandwidth:&#34; + str(self.bandwidth) + &#34;\n&#34; +
+                  &#34;Sample rate:&#34; + str(self.sample_rate) + &#34;\n&#34;)
+        return output</code></pre>
+</details>
+<h3>Class variables</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataHeader.AmmosIFDataHeader.HEADER_SIZE"><code class="name">var <span class="ident">HEADER_SIZE</span></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.AmmosIFDataHeader.AmmosIFDataHeader.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>bytes)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return an AMMOS data header from given bytes.</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, bytes):
+    &#34;&#34;&#34;I return an AMMOS data header from given bytes.&#34;&#34;&#34;
+    assert len(bytes) == cls.HEADER_SIZE
+    elements = struct.unpack(&#39;&lt;IIQIIIQIIIIi&#39;, bytes)
+    block_count = elements[0]
+    block_length = int(elements[1])*4
+    timestamp = np.datetime64(int(elements[2])*1000, &#39;ns&#39;)
+    status = elements[3]
+    source_id = elements[4]
+    source_state = elements[5]
+    frequency = elements[6]
+    bandwidth = elements[7]
+    sample_rate = elements[8]
+    interpolation = elements[9]
+    decimation = elements[10]
+    voltage_ref = elements[11]
+
+    return AmmosIFDataHeader(block_count, block_length, timestamp, status, source_id,
+                             source_state, frequency, bandwidth, sample_rate,
+                             interpolation, decimation, voltage_ref)</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosIFDataHeader.AmmosIFDataHeader" href="#ammosreader.AmmosIFDataHeader.AmmosIFDataHeader">AmmosIFDataHeader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosIFDataHeader.AmmosIFDataHeader.HEADER_SIZE" href="#ammosreader.AmmosIFDataHeader.AmmosIFDataHeader.HEADER_SIZE">HEADER_SIZE</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataHeader.AmmosIFDataHeader.from_bytes" href="#ammosreader.AmmosIFDataHeader.AmmosIFDataHeader.from_bytes">from_bytes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosIFReader.html
===================================================================
--- doc/ammosreader/AmmosIFReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosIFReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,463 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosIFReader API documentation</title>
+<meta name="description" content="I provide a specialized Ammos Reader for IF data." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosIFReader</code></h1>
+</header>
+<section id="section-intro">
+<p>I provide a specialized Ammos Reader for IF data.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I provide a specialized Ammos Reader for IF data.&#34;&#34;&#34;
+import logging
+
+from ammosreader.AbstractAmmosReader import AbstractAmmosReader
+from ammosreader.AmmosGlobalFrameBody import AmmosGlobalFrameBody
+from ammosreader.AmmosIFDataHeader import AmmosIFDataHeader
+from ammosreader.AmmosExtendedIFDataHeader import AmmosExtendedIFDataHeader
+from ammosreader.AmmosIFDataBody import AmmosIFDataBody
+from ammosreader.AmmosIFDataBlock import AmmosIFDataBlock
+from ammosreader.AmmosIFDataBlockHeader import AmmosIFDataBlockHeader
+
+
+class AmmosIFReader(AbstractAmmosReader):
+    &#34;&#34;&#34;I read the IF data embedded in an R&amp;S AMMOS recording.&#34;&#34;&#34;
+
+    def __init__(self, file_name):
+        super().__init__(file_name)
+
+    def read_next_global_frame_body_data_header(self):
+
+        header_size = AmmosIFDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        logging.info(&#34;\nReading global frame body standard data header\n&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame body data header&#34;, header_size)
+            return None
+        return AmmosIFDataHeader.from_bytes(bytes)
+
+    def read_next_global_frame_body_extended_data_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame body extended data header from current position in file.
+
+        :return: the next Ammos Extended IF data header or None if incomplete
+        :rtype: AmmosExtendedIFDataHeader
+        &#34;&#34;&#34;
+        header_size = AmmosExtendedIFDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        logging.info(&#34;\nReading global frame body extended data header\n&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame extended data header&#34;, header_size)
+            return None
+        return AmmosExtendedIFDataHeader.from_bytes(bytes)
+
+    def read_next_if_data_body(self, number_of_data_blocks, data_length):
+        &#34;&#34;&#34;
+        I return the next data body read from current position in file.
+
+        :param number_of_data_blocks: the number of data blocks inside the body
+        :type number_of_data_blocks: int
+
+        :param data_length: the length of the raw data inside a single block
+        :type data_length: int
+        &#34;&#34;&#34;
+        header_size = AmmosIFDataBlockHeader.HEADER_SIZE
+
+        data_body = AmmosIFDataBody()
+
+        block_length = header_size + data_length
+
+        total = number_of_data_blocks*block_length
+
+        byte_string = self.ammos_file.read(block_length)
+
+        if len(byte_string) != total:
+            logging.debug(&#34;Can not read all %s bytes of data body&#34;, total)
+            return None
+
+        for i in range(0, number_of_data_blocks):
+            result = byte_string[i*block_length:(i*block_length+block_length)]
+            data_body.add_data_block(AmmosIFDataBlock(AmmosIFDataBlockHeader.from_bytes(result[0:header_size]),
+                                                      result[header_size:]))
+
+        return data_body
+
+    def read_next_global_frame_body(self, data_header_length):
+        &#34;&#34;&#34;
+        I return the next global frame body read from current position in file.
+
+        :param data_header_length: the length of the data header
+        :type data_header_length: int
+        &#34;&#34;&#34;
+        if_data_header = None
+
+        if data_header_length == AmmosIFDataHeader.HEADER_SIZE:
+            if_data_header = self.read_next_global_frame_body_data_header()
+        if data_header_length == AmmosExtendedIFDataHeader.HEADER_SIZE:
+            if_data_header = self.read_next_global_frame_body_extended_data_header()
+
+        if if_data_header is None:
+            logging.debug(&#34;Data header missing&#34;)
+            return None
+
+        if_data_body = self.read_next_if_data_body(if_data_header.block_count, if_data_header.block_length)
+
+        if if_data_body is None:
+            logging.debug(&#34;Data body missing&#34;)
+            return None
+
+        return AmmosGlobalFrameBody(if_data_header, if_data_body)
+
+    def payload(self):
+        return b&#34;&#34;.join([each.global_frame_body.data_body.payload for each in self.container.global_frames])</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosIFReader.AmmosIFReader"><code class="flex name class">
+<span>class <span class="ident">AmmosIFReader</span></span>
+<span>(</span><span>file_name)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I read the IF data embedded in an R&amp;S AMMOS recording.</p>
+<p>I am the standard constructor for Ammos Readers.</p>
+<p>Additional information about the file can be added as key/value pairs in tags</p>
+<p>:param file_name: The file to read Ammos data from
+:type file_name: str</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosIFReader(AbstractAmmosReader):
+    &#34;&#34;&#34;I read the IF data embedded in an R&amp;S AMMOS recording.&#34;&#34;&#34;
+
+    def __init__(self, file_name):
+        super().__init__(file_name)
+
+    def read_next_global_frame_body_data_header(self):
+
+        header_size = AmmosIFDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        logging.info(&#34;\nReading global frame body standard data header\n&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame body data header&#34;, header_size)
+            return None
+        return AmmosIFDataHeader.from_bytes(bytes)
+
+    def read_next_global_frame_body_extended_data_header(self):
+        &#34;&#34;&#34;
+        I return the next global frame body extended data header from current position in file.
+
+        :return: the next Ammos Extended IF data header or None if incomplete
+        :rtype: AmmosExtendedIFDataHeader
+        &#34;&#34;&#34;
+        header_size = AmmosExtendedIFDataHeader.HEADER_SIZE
+
+        bytes = self.ammos_file.read(header_size)
+
+        logging.info(&#34;\nReading global frame body extended data header\n&#34;)
+        if ((not bytes) or (len(bytes) &lt; header_size)):
+            logging.debug(&#34;Can not read all %s bytes of global frame extended data header&#34;, header_size)
+            return None
+        return AmmosExtendedIFDataHeader.from_bytes(bytes)
+
+    def read_next_if_data_body(self, number_of_data_blocks, data_length):
+        &#34;&#34;&#34;
+        I return the next data body read from current position in file.
+
+        :param number_of_data_blocks: the number of data blocks inside the body
+        :type number_of_data_blocks: int
+
+        :param data_length: the length of the raw data inside a single block
+        :type data_length: int
+        &#34;&#34;&#34;
+        header_size = AmmosIFDataBlockHeader.HEADER_SIZE
+
+        data_body = AmmosIFDataBody()
+
+        block_length = header_size + data_length
+
+        total = number_of_data_blocks*block_length
+
+        byte_string = self.ammos_file.read(block_length)
+
+        if len(byte_string) != total:
+            logging.debug(&#34;Can not read all %s bytes of data body&#34;, total)
+            return None
+
+        for i in range(0, number_of_data_blocks):
+            result = byte_string[i*block_length:(i*block_length+block_length)]
+            data_body.add_data_block(AmmosIFDataBlock(AmmosIFDataBlockHeader.from_bytes(result[0:header_size]),
+                                                      result[header_size:]))
+
+        return data_body
+
+    def read_next_global_frame_body(self, data_header_length):
+        &#34;&#34;&#34;
+        I return the next global frame body read from current position in file.
+
+        :param data_header_length: the length of the data header
+        :type data_header_length: int
+        &#34;&#34;&#34;
+        if_data_header = None
+
+        if data_header_length == AmmosIFDataHeader.HEADER_SIZE:
+            if_data_header = self.read_next_global_frame_body_data_header()
+        if data_header_length == AmmosExtendedIFDataHeader.HEADER_SIZE:
+            if_data_header = self.read_next_global_frame_body_extended_data_header()
+
+        if if_data_header is None:
+            logging.debug(&#34;Data header missing&#34;)
+            return None
+
+        if_data_body = self.read_next_if_data_body(if_data_header.block_count, if_data_header.block_length)
+
+        if if_data_body is None:
+            logging.debug(&#34;Data body missing&#34;)
+            return None
+
+        return AmmosGlobalFrameBody(if_data_header, if_data_body)
+
+    def payload(self):
+        return b&#34;&#34;.join([each.global_frame_body.data_body.payload for each in self.container.global_frames])</code></pre>
+</details>
+<h3>Ancestors</h3>
+<ul class="hlist">
+<li><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader">AbstractAmmosReader</a></li>
+<li>abc.ABC</li>
+</ul>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosIFReader.AmmosIFReader.payload"><code class="name flex">
+<span>def <span class="ident">payload</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def payload(self):
+    return b&#34;&#34;.join([each.global_frame_body.data_body.payload for each in self.container.global_frames])</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body</span></span>(<span>self, data_header_length)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next global frame body read from current position in file.</p>
+<p>:param data_header_length: the length of the data header
+:type data_header_length: int</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_body(self, data_header_length):
+    &#34;&#34;&#34;
+    I return the next global frame body read from current position in file.
+
+    :param data_header_length: the length of the data header
+    :type data_header_length: int
+    &#34;&#34;&#34;
+    if_data_header = None
+
+    if data_header_length == AmmosIFDataHeader.HEADER_SIZE:
+        if_data_header = self.read_next_global_frame_body_data_header()
+    if data_header_length == AmmosExtendedIFDataHeader.HEADER_SIZE:
+        if_data_header = self.read_next_global_frame_body_extended_data_header()
+
+    if if_data_header is None:
+        logging.debug(&#34;Data header missing&#34;)
+        return None
+
+    if_data_body = self.read_next_if_data_body(if_data_header.block_count, if_data_header.block_length)
+
+    if if_data_body is None:
+        logging.debug(&#34;Data body missing&#34;)
+        return None
+
+    return AmmosGlobalFrameBody(if_data_header, if_data_body)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body_data_header"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body_data_header</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_body_data_header(self):
+
+    header_size = AmmosIFDataHeader.HEADER_SIZE
+
+    bytes = self.ammos_file.read(header_size)
+
+    logging.info(&#34;\nReading global frame body standard data header\n&#34;)
+    if ((not bytes) or (len(bytes) &lt; header_size)):
+        logging.debug(&#34;Can not read all %s bytes of global frame body data header&#34;, header_size)
+        return None
+    return AmmosIFDataHeader.from_bytes(bytes)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body_extended_data_header"><code class="name flex">
+<span>def <span class="ident">read_next_global_frame_body_extended_data_header</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next global frame body extended data header from current position in file.</p>
+<p>:return: the next Ammos Extended IF data header or None if incomplete
+:rtype: AmmosExtendedIFDataHeader</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_global_frame_body_extended_data_header(self):
+    &#34;&#34;&#34;
+    I return the next global frame body extended data header from current position in file.
+
+    :return: the next Ammos Extended IF data header or None if incomplete
+    :rtype: AmmosExtendedIFDataHeader
+    &#34;&#34;&#34;
+    header_size = AmmosExtendedIFDataHeader.HEADER_SIZE
+
+    bytes = self.ammos_file.read(header_size)
+
+    logging.info(&#34;\nReading global frame body extended data header\n&#34;)
+    if ((not bytes) or (len(bytes) &lt; header_size)):
+        logging.debug(&#34;Can not read all %s bytes of global frame extended data header&#34;, header_size)
+        return None
+    return AmmosExtendedIFDataHeader.from_bytes(bytes)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosIFReader.AmmosIFReader.read_next_if_data_body"><code class="name flex">
+<span>def <span class="ident">read_next_if_data_body</span></span>(<span>self, number_of_data_blocks, data_length)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I return the next data body read from current position in file.</p>
+<p>:param number_of_data_blocks: the number of data blocks inside the body
+:type number_of_data_blocks: int</p>
+<p>:param data_length: the length of the raw data inside a single block
+:type data_length: int</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_next_if_data_body(self, number_of_data_blocks, data_length):
+    &#34;&#34;&#34;
+    I return the next data body read from current position in file.
+
+    :param number_of_data_blocks: the number of data blocks inside the body
+    :type number_of_data_blocks: int
+
+    :param data_length: the length of the raw data inside a single block
+    :type data_length: int
+    &#34;&#34;&#34;
+    header_size = AmmosIFDataBlockHeader.HEADER_SIZE
+
+    data_body = AmmosIFDataBody()
+
+    block_length = header_size + data_length
+
+    total = number_of_data_blocks*block_length
+
+    byte_string = self.ammos_file.read(block_length)
+
+    if len(byte_string) != total:
+        logging.debug(&#34;Can not read all %s bytes of data body&#34;, total)
+        return None
+
+    for i in range(0, number_of_data_blocks):
+        result = byte_string[i*block_length:(i*block_length+block_length)]
+        data_body.add_data_block(AmmosIFDataBlock(AmmosIFDataBlockHeader.from_bytes(result[0:header_size]),
+                                                  result[header_size:]))
+
+    return data_body</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Inherited members</h3>
+<ul class="hlist">
+<li><code><b><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader">AbstractAmmosReader</a></b></code>:
+<ul class="hlist">
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.add_tag">add_tag</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.ammos_file">ammos_file</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.container" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.container">container</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.file_name">file_name</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_all_frames_left">read_all_frames_left</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_global_frame_header">read_next_global_frame_header</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.read_next_single_frame">read_next_single_frame</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.rewind_to_start">rewind_to_start</a></code></li>
+<li><code><a title="ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags" href="AbstractAmmosReader.html#ammosreader.AbstractAmmosReader.AbstractAmmosReader.tags">tags</a></code></li>
+</ul>
+</li>
+</ul>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosIFReader.AmmosIFReader" href="#ammosreader.AmmosIFReader.AmmosIFReader">AmmosIFReader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosIFReader.AmmosIFReader.payload" href="#ammosreader.AmmosIFReader.AmmosIFReader.payload">payload</a></code></li>
+<li><code><a title="ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body" href="#ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body">read_next_global_frame_body</a></code></li>
+<li><code><a title="ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body_data_header" href="#ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body_data_header">read_next_global_frame_body_data_header</a></code></li>
+<li><code><a title="ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body_extended_data_header" href="#ammosreader.AmmosIFReader.AmmosIFReader.read_next_global_frame_body_extended_data_header">read_next_global_frame_body_extended_data_header</a></code></li>
+<li><code><a title="ammosreader.AmmosIFReader.AmmosIFReader.read_next_if_data_body" href="#ammosreader.AmmosIFReader.AmmosIFReader.read_next_if_data_body">read_next_if_data_body</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/AmmosSingleFrame.html
===================================================================
--- doc/ammosreader/AmmosSingleFrame.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/AmmosSingleFrame.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,210 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.AmmosSingleFrame API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.AmmosSingleFrame</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosSingleFrame():
+
+    def __init__(self, global_frame_header, global_frame_body):
+        self.__global_frame_header = global_frame_header
+        self.__global_frame_body = global_frame_body
+
+    @property
+    def global_frame_header(self):
+        return self.__global_frame_header
+
+    @property
+    def global_frame_body(self):
+        return self.__global_frame_body
+
+    def data(self):
+        return self.global_frame_body.data_bytes_only()
+
+    def size_correct(self):
+        return (self.global_frame_header.frame_length == (24 + self.global_frame_header.data_header_length +
+                                                          (self.global_frame_body.data_header.block_count *
+                                                           (self.global_frame_body.data_header.block_length + 4))))
+    # FIXME: Use str method instead
+
+    def __str__(self):
+        output = (
+            &#34;Global frame header\n&#34; +
+            &#34;-------------------\n&#34; +
+            &#34;Frame type:&#34; + str(self.global_frame_header.frame_type) + &#34;\n&#34; +
+            &#34;Frame count:&#34; + str(self.global_frame_header.running_frame_number) + &#34;\n&#34; +
+            &#34;Data header length:&#34; + str(self.global_frame_header.data_header_length) + &#34; bytes\n&#34; +
+            &#34;Frame length:&#34; + str(self.global_frame_header.frame_length) + &#34; bytes\n&#34;
+        )
+        return output</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.AmmosSingleFrame.AmmosSingleFrame"><code class="flex name class">
+<span>class <span class="ident">AmmosSingleFrame</span></span>
+<span>(</span><span>global_frame_header, global_frame_body)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class AmmosSingleFrame():
+
+    def __init__(self, global_frame_header, global_frame_body):
+        self.__global_frame_header = global_frame_header
+        self.__global_frame_body = global_frame_body
+
+    @property
+    def global_frame_header(self):
+        return self.__global_frame_header
+
+    @property
+    def global_frame_body(self):
+        return self.__global_frame_body
+
+    def data(self):
+        return self.global_frame_body.data_bytes_only()
+
+    def size_correct(self):
+        return (self.global_frame_header.frame_length == (24 + self.global_frame_header.data_header_length +
+                                                          (self.global_frame_body.data_header.block_count *
+                                                           (self.global_frame_body.data_header.block_length + 4))))
+    # FIXME: Use str method instead
+
+    def __str__(self):
+        output = (
+            &#34;Global frame header\n&#34; +
+            &#34;-------------------\n&#34; +
+            &#34;Frame type:&#34; + str(self.global_frame_header.frame_type) + &#34;\n&#34; +
+            &#34;Frame count:&#34; + str(self.global_frame_header.running_frame_number) + &#34;\n&#34; +
+            &#34;Data header length:&#34; + str(self.global_frame_header.data_header_length) + &#34; bytes\n&#34; +
+            &#34;Frame length:&#34; + str(self.global_frame_header.frame_length) + &#34; bytes\n&#34;
+        )
+        return output</code></pre>
+</details>
+<h3>Instance variables</h3>
+<dl>
+<dt id="ammosreader.AmmosSingleFrame.AmmosSingleFrame.global_frame_body"><code class="name">var <span class="ident">global_frame_body</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def global_frame_body(self):
+    return self.__global_frame_body</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosSingleFrame.AmmosSingleFrame.global_frame_header"><code class="name">var <span class="ident">global_frame_header</span></code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@property
+def global_frame_header(self):
+    return self.__global_frame_header</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.AmmosSingleFrame.AmmosSingleFrame.data"><code class="name flex">
+<span>def <span class="ident">data</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def data(self):
+    return self.global_frame_body.data_bytes_only()</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.AmmosSingleFrame.AmmosSingleFrame.size_correct"><code class="name flex">
+<span>def <span class="ident">size_correct</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def size_correct(self):
+    return (self.global_frame_header.frame_length == (24 + self.global_frame_header.data_header_length +
+                                                      (self.global_frame_body.data_header.block_count *
+                                                       (self.global_frame_body.data_header.block_length + 4))))</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.AmmosSingleFrame.AmmosSingleFrame" href="#ammosreader.AmmosSingleFrame.AmmosSingleFrame">AmmosSingleFrame</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.AmmosSingleFrame.AmmosSingleFrame.data" href="#ammosreader.AmmosSingleFrame.AmmosSingleFrame.data">data</a></code></li>
+<li><code><a title="ammosreader.AmmosSingleFrame.AmmosSingleFrame.global_frame_body" href="#ammosreader.AmmosSingleFrame.AmmosSingleFrame.global_frame_body">global_frame_body</a></code></li>
+<li><code><a title="ammosreader.AmmosSingleFrame.AmmosSingleFrame.global_frame_header" href="#ammosreader.AmmosSingleFrame.AmmosSingleFrame.global_frame_header">global_frame_header</a></code></li>
+<li><code><a title="ammosreader.AmmosSingleFrame.AmmosSingleFrame.size_correct" href="#ammosreader.AmmosSingleFrame.AmmosSingleFrame.size_correct">size_correct</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/IQDWTXBlock.html
===================================================================
--- doc/ammosreader/IQDWTXBlock.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/IQDWTXBlock.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,126 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.IQDWTXBlock API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.IQDWTXBlock</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">from ammosreader.PDW import PDW
+
+
+class IQDWTXBLOCK():
+
+    @classmethod
+    def from_bytes(cls, byte_string):
+        pdw = PDW.from_bytes(bytes[0:32])
+        return IQDWTXBLOCK(pdw, bytes[32:])
+
+    def __init__(self, pdw, iq):
+
+        self.pdw = pdw
+        self.iq = iq</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.IQDWTXBlock.IQDWTXBLOCK"><code class="flex name class">
+<span>class <span class="ident">IQDWTXBLOCK</span></span>
+<span>(</span><span>pdw, iq)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class IQDWTXBLOCK():
+
+    @classmethod
+    def from_bytes(cls, byte_string):
+        pdw = PDW.from_bytes(bytes[0:32])
+        return IQDWTXBLOCK(pdw, bytes[32:])
+
+    def __init__(self, pdw, iq):
+
+        self.pdw = pdw
+        self.iq = iq</code></pre>
+</details>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.IQDWTXBlock.IQDWTXBLOCK.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>byte_string)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, byte_string):
+    pdw = PDW.from_bytes(bytes[0:32])
+    return IQDWTXBLOCK(pdw, bytes[32:])</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.IQDWTXBlock.IQDWTXBLOCK" href="#ammosreader.IQDWTXBlock.IQDWTXBLOCK">IQDWTXBLOCK</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.IQDWTXBlock.IQDWTXBLOCK.from_bytes" href="#ammosreader.IQDWTXBlock.IQDWTXBLOCK.from_bytes">from_bytes</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/PDW.html
===================================================================
--- doc/ammosreader/PDW.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/PDW.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,756 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.PDW API documentation</title>
+<meta name="description" content="I store the information of a single PDW block." />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.PDW</code></h1>
+</header>
+<section id="section-intro">
+<p>I store the information of a single PDW block.</p>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">&#34;&#34;&#34;I store the information of a single PDW block.&#34;&#34;&#34;
+
+import struct
+import math
+import numpy as np
+
+
+class PDW():
+    &#34;&#34;&#34;
+    I store information from a single ppdw data block.
+
+    .. automethod:: __init__
+    &#34;&#34;&#34;
+
+    @classmethod
+    def from_bytes(cls, byte_string):
+        &#34;&#34;&#34;
+        I create an instance of class PDW from data body (8 * 32 bits).
+
+        :param byte_string: a byte string containing a single data body read from a ppdw file
+        :type byte_string: byte string
+
+        :return: an instance of class PDW with attributes set according to the data of a data body
+        :rtype: PDW
+        &#34;&#34;&#34;
+        assert(len(byte_string) == 32)
+
+        parts = struct.unpack(&#39;&lt;Q4s4s4s4s4s4s&#39;, byte_string)
+        nanoseconds = (parts[0])
+        time_of_arrival = np.datetime64(nanoseconds, &#39;ns&#39;)
+
+        third_entry = bin(int.from_bytes(parts[1], byteorder=&#39;little&#39;))
+        padding = 32-len(str(third_entry)[2:])
+        third_entry_bit_string = &#34;0&#34; * padding + str(third_entry)[2:]
+        pdw_format_identifier = int(third_entry_bit_string[0:6], 2)
+        center_frequency = int(third_entry_bit_string[5:32], 2)
+
+        fourth_entry = bin(int.from_bytes(parts[2], byteorder=&#39;little&#39;))
+        padding = 32-len(str(fourth_entry)[2:])
+        fourth_entry_bit_string = &#34;0&#34; * padding + str(fourth_entry)[2:]
+        is_valid = bool(int(fourth_entry_bit_string[0]))
+        is_pulse = bool(int(fourth_entry_bit_string[1]))
+        level_unit = int(fourth_entry_bit_string[2])
+        signal_start_missing = bool(int(fourth_entry_bit_string[3]))
+        signal_end_missing = bool(int(fourth_entry_bit_string[4]))
+        pulse_width = int(fourth_entry_bit_string[7:33], 2)
+
+        fifth_entry = bin(int.from_bytes(parts[3], byteorder=&#39;little&#39;))
+        padding = 32-len(str(fifth_entry)[2:])
+        fifth_entry_bit_string = &#34;0&#34; * padding + str(fifth_entry)[2:]
+        frequency_shift_or_bandwidth = int(fifth_entry_bit_string[0:20], 2)
+        # FIXME: You have to scale me to the range from -200.0 to 200.0 in 0.1 steps
+        pulse_level_or_pulse_field_strength = math.ceil(int(fifth_entry_bit_string[20:32], 2)) / 10
+
+        sixth_entry = bin(int.from_bytes(parts[4], byteorder=&#39;little&#39;))
+        padding = 32-len(str(sixth_entry)[2:])
+        sixth_entry_bit_string = &#34;0&#34; * padding + str(sixth_entry)[2:]
+        region_of_interest = bool(int(sixth_entry_bit_string[0]))
+        # FIXME: You have to scale me to a range from 0.0 to 6.2 in steps of 0.1 - 6.3 means unknown
+        azimuth_confidence = math.ceil(int(sixth_entry_bit_string[1:7], 2)) / 10
+        modulations = {0: &#39;Unknown&#39;, 1: &#39;Unmodulated&#39;, 2: &#39;FM&#39;, 3: &#39;LFM&#39;, 4: &#39;PSK-2&#39;, 5: &#39;PSK-3&#39;, 6: &#39;PSK-4&#39;,
+                       7: &#39;PSK-m&#39;, 8: &#39;NLFM&#39;, 9: &#39;SFM&#39;, 10: &#39;TFM&#39;, 11: &#39;Pulse too short&#39;}
+        modulation = modulations[int(sixth_entry_bit_string[7:12], 2)]
+        sector = int(sixth_entry_bit_string[28:32], 2)
+
+        seventh_entry = bin(int.from_bytes(parts[5], byteorder=&#39;little&#39;))
+        padding = 32-len(str(seventh_entry)[2:])
+        seventh_entry_bit_string = &#34;0&#34; * padding + str(seventh_entry)[2:]
+        polarities = {0: &#39;Horizontal/Unknown&#39;, 1: &#39;Vertical&#39;, 2: &#39;Counter clockwise&#39;, 3: &#39;Clockwise&#39;}
+        polarity = polarities[int(seventh_entry_bit_string[0:2], 2)]
+        df_quality = int(seventh_entry_bit_string[2:9], 2)
+        # FIXME: You have to scale me from -90 to 90 in 0.1 degree steps
+        elevation = int(seventh_entry_bit_string[9:20], 2)
+        # FIXME: You have to check me for a range from 0.0 to 359.9 in steps of 0.1
+        azimuth = 0.1 * (int(seventh_entry_bit_string[20:32], 2))
+
+        eighth_entry = bin(int.from_bytes(parts[5], byteorder=&#39;little&#39;))
+        padding = 32-len(str(eighth_entry)[2:])
+        eighth_entry_bit_string = &#34;0&#34; * padding + str(eighth_entry)[2:]
+        channel = int(eighth_entry_bit_string[0:4], 2)
+
+        return PDW(time_of_arrival, pdw_format_identifier, center_frequency, is_valid, is_pulse, level_unit,
+                   signal_start_missing, signal_end_missing, pulse_width, frequency_shift_or_bandwidth,
+                   pulse_level_or_pulse_field_strength, region_of_interest, azimuth_confidence, modulation,
+                   sector, polarity, df_quality, elevation, azimuth, channel)
+
+    def __init__(self, time_of_arrival, pdw_format_identifier, center_frequency, is_valid, is_pulse,
+                 level_unit, signal_start_missing, signal_end_missing, pulse_width, frequency_shift_or_bandwidth,
+                 pulse_level_or_pulse_field_strength, region_of_interest, azimuth_confidence, modulation,
+                 sector, polarity, df_quality, elevation, azimuth, channel):
+        r&#34;&#34;&#34;
+        I return an instance of an Pulse Data word.
+
+        :param time_of_arrival: nanoseconds since 1970-01-01 00:00:00
+        :type time_of_arrival: Integer
+        :param pdw_format: format code
+        :type pdw_format: Integer
+        :param center_frequency: center frequency in KHz
+        :type center_frequency: Integer
+        :param is_valid: flag to mark if pdw data body is valid
+        :type is_valid: Boolean
+        :param is_pulse: flag to mark if pdw data body contains a pulse or a continuous wave signal
+        :type is_pulse: Boolean
+        :param level_unit: 0 means dBµV - 1 means dBµV/m
+        :type level_unit: Integer
+        :param signal_start_missing: signal started before time of arrival
+        :type signal_start_missing: Boolean
+        :param signal_end_missing: signal stops after time of arrival
+        :type signal_end_missing: Boolean
+        :param pulse_width: pulse width in nanoseconds - Zero if no valid pulse detected
+        :type pulse_width: Integer
+        :param frequency_shift_or_bandwidth: Value in KHz - Value set to 1048575 means Unknown
+        :type frequency_shift_or_bandwidth: Integer
+        :param pulse_level_or_pulse_field_strength: Pulse level or Pulse Field Strength depending on level_unit \
+         (-200.0...200.0) in 0.1 steps / minus 204.8 means no valid level detected
+        :type pulse_level_or_pulse_field_strength: Float
+        :param region_of_interest: Marks if signal is from region of interest
+        :type region_of_interest: Boolean
+        :param azimuth_confidence: degree in steps of 0.1 (0.0-6.2) / 6.3 means confidence unknown
+        :type azimuth_confidence: Float
+        :param modulation: type of modulation (e.g. PSK-2, PSK-4, FM etc.)
+        :type modulation: String
+        :param sector: reference antenna sector (0-15)
+        :type sector: Integer
+        :param polarity: Horizontal, Vertical, Clockwise, Counter clockwise
+        :type polarity: String
+        :param df_quality: Direction finding quality in percent (0-100) - Zero means unknown
+        :type df_quality: Integer
+        :param elevation: elevation of incoming signal (from -90 to 90 degree) in steps of 0.1 degree \
+        minus 102.4 means unknown
+        :type elevation: Float
+        :param azimuth: azimuth of incoming signal (from 0 to 359.9 degree) in steps of 0.1 degree \
+        plus 409.5 means unknown
+        :type azimuth: Float
+        :param channel: detecting channel (0-16) - Zero means unknown
+        :type channel: Integer
+        :return: An instance of class PDW with attributes set according to the data of a data body
+        :rtype: PDW
+        &#34;&#34;&#34;
+        self.time_of_arrival = time_of_arrival #
+        self.pdw_format_identifier = pdw_format_identifier
+        self.center_frequency = center_frequency #
+        self.__is_valid = is_valid #
+        self.is_pulse = is_pulse #
+        self.level_unit = level_unit #
+        self.signal_start_missing = signal_start_missing
+        self.signal_end_missing = signal_end_missing
+        self.pulse_width = pulse_width #
+        self.frequency_shift_or_bandwidth = frequency_shift_or_bandwidth #
+        self.pulse_level_or_pulse_field_strength = pulse_level_or_pulse_field_strength #
+        self.region_of_interest = region_of_interest
+        self.azimuth_confidence = azimuth_confidence
+        self.modulation = modulation #
+        self.sector = sector
+        self.polarity = polarity
+        self.df_quality = df_quality #
+        self.elevation = elevation #
+        self.azimuth = azimuth
+        self.channel = channel #
+
+    def __str__(self):
+        &#34;&#34;&#34;
+        I return the string representation of myself.
+
+        :rtype: str
+        &#34;&#34;&#34;
+        output = (&#34;Time of arrival: &#34; + str(self.time_of_arrival) + &#34;\n&#34; +
+                  &#34;PDW Format identifier: &#34; + str(self.pdw_format_identifier) + &#34;\n&#34; +
+                  &#34;Center frequency: &#34; + str(self.center_frequency) + &#34; KHz\n&#34;)
+
+        if self.__is_valid:
+            output += &#34;Signal: Valid\n&#34;
+        else:
+            output += &#34;Signal: Invalid\n&#34;
+
+        if self.is_pulse:
+            output += &#34;Signal type: Pulse\n&#34;
+        else:
+            output += &#34;Signal type: Continuous wave\n&#34;
+
+        if self.level_unit == 1:
+            output += &#34;Pulse level: &#34; + str(self.pulse_level_or_pulse_field_strength) + &#34; dbµV\n&#34;
+        else:
+            output += &#34;Pulse field strength: &#34; + str(self.pulse_level_or_pulse_field_strength) + &#34; dbµV/meter\n&#34;
+
+        output += (&#34;Pulse width: &#34; + str(self.pulse_width) + &#34; nanoseconds\n&#34; +
+                   &#34;Frequency shift or bandwidth: &#34; + str(self.frequency_shift_or_bandwidth) + &#34; KHz\n&#34;)
+
+        if self.region_of_interest:
+            output += &#34;Region of interest: Yes\n&#34;
+        else:
+            output += &#34;Region of interest: No\n&#34;
+
+        if self.azimuth_confidence == 6.3:
+            output += &#34;Azimuth confidence: Invalid\n&#34;
+        else:
+            output += &#34;Azimuth confidence: &#34; + str(self.azimuth_confidence) + &#34; degree\n&#34;
+
+        output += &#34;Modulation: &#34; + str(self.modulation) + &#34;\n&#34;
+
+        if self.sector == 0:
+            output += &#34;Sector: Unknown\n&#34;
+        else:
+            output += &#34;Sector:&#34; + str(self.sector) + &#34;\n&#34;
+
+        output += &#34;Polarity: &#34; + str(self.polarity) + &#34;\n&#34;
+
+        output += &#34;DF quality: &#34; + str(self.df_quality) + &#34; %\n&#34;
+
+        if self.elevation == 1024:
+            output += &#34;Elevation: Unknown\n&#34;
+        else:
+            output += &#34;Elevation: &#34; + str(self.elevation) + &#34; degree\n&#34;
+
+        if self.azimuth == 409.5:
+            output += &#34;Azimuth: Unknown\n&#34;
+        else:
+            output += &#34;Azimuth: &#34; + str(self.azimuth) + &#34; degree\n&#34;
+
+        output += &#34;Channel: &#34; + str(self.channel) + &#34;\n&#34;
+
+        return output
+
+    def is_valid(self):
+        return self.__is_valid
+
+    def to_json(self):
+        return {&#39;time of arrival&#39;: self.time_of_arrival,
+                &#39;FORMATIDENTIFIER&#39;: self.pdw_format_identifier,
+                &#39;center frequency&#39;: self.center_frequency,
+                &#39;VALID&#39;: self.__is_valid,
+                &#39;PULSE&#39;: self.is_pulse,
+                &#39;PULSELEVEL&#39;: self.pulse_level_or_pulse_field_strength,
+                &#39;PULSEWIDTH&#39;: self.pulse_width,
+                &#39;BANDWIDTH&#39;: self.frequency_shift_or_bandwidth,
+                &#39;REGIONOFINTEREST&#39;: self.region_of_interest,
+                &#39;AZIMUTHCONFIDENCE&#39;: self.azimuth_confidence,
+                &#39;MODULATION&#39;: self.modulation,
+                &#39;SECTOR&#39;: self.sector,
+                &#39;POLARITY&#39;: self.polarity,
+                &#39;DFQUALITY&#39;: self.df_quality,
+                &#39;ELEVATION&#39;: self.elevation,
+                &#39;AZIMUTH&#39;: self.azimuth,
+                &#39;CHANNEL&#39;: self.channel
+                }
+
+if __name__ == &#39;__main__&#39;:
+    pass</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.PDW.PDW"><code class="flex name class">
+<span>class <span class="ident">PDW</span></span>
+<span>(</span><span>time_of_arrival, pdw_format_identifier, center_frequency, is_valid, is_pulse, level_unit, signal_start_missing, signal_end_missing, pulse_width, frequency_shift_or_bandwidth, pulse_level_or_pulse_field_strength, region_of_interest, azimuth_confidence, modulation, sector, polarity, df_quality, elevation, azimuth, channel)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I store information from a single ppdw data block.</p>
+<div class="admonition automethod">
+<p class="admonition-title">Automethod:&ensp;<strong>init</strong></p>
+</div>
+<p>I return an instance of an Pulse Data word.</p>
+<p>:param time_of_arrival: nanoseconds since 1970-01-01 00:00:00
+:type time_of_arrival: Integer
+:param pdw_format: format code
+:type pdw_format: Integer
+:param center_frequency: center frequency in KHz
+:type center_frequency: Integer
+:param is_valid: flag to mark if pdw data body is valid
+:type is_valid: Boolean
+:param is_pulse: flag to mark if pdw data body contains a pulse or a continuous wave signal
+:type is_pulse: Boolean
+:param level_unit: 0 means dBµV - 1 means dBµV/m
+:type level_unit: Integer
+:param signal_start_missing: signal started before time of arrival
+:type signal_start_missing: Boolean
+:param signal_end_missing: signal stops after time of arrival
+:type signal_end_missing: Boolean
+:param pulse_width: pulse width in nanoseconds - Zero if no valid pulse detected
+:type pulse_width: Integer
+:param frequency_shift_or_bandwidth: Value in KHz - Value set to 1048575 means Unknown
+:type frequency_shift_or_bandwidth: Integer
+:param pulse_level_or_pulse_field_strength: Pulse level or Pulse Field Strength depending on level_unit \
+(-200.0&hellip;200.0) in 0.1 steps / minus 204.8 means no valid level detected
+:type pulse_level_or_pulse_field_strength: Float
+:param region_of_interest: Marks if signal is from region of interest
+:type region_of_interest: Boolean
+:param azimuth_confidence: degree in steps of 0.1 (0.0-6.2) / 6.3 means confidence unknown
+:type azimuth_confidence: Float
+:param modulation: type of modulation (e.g. PSK-2, PSK-4, FM etc.)
+:type modulation: String
+:param sector: reference antenna sector (0-15)
+:type sector: Integer
+:param polarity: Horizontal, Vertical, Clockwise, Counter clockwise
+:type polarity: String
+:param df_quality: Direction finding quality in percent (0-100) - Zero means unknown
+:type df_quality: Integer
+:param elevation: elevation of incoming signal (from -90 to 90 degree) in steps of 0.1 degree \
+minus 102.4 means unknown
+:type elevation: Float
+:param azimuth: azimuth of incoming signal (from 0 to 359.9 degree) in steps of 0.1 degree \
+plus 409.5 means unknown
+:type azimuth: Float
+:param channel: detecting channel (0-16) - Zero means unknown
+:type channel: Integer
+:return: An instance of class PDW with attributes set according to the data of a data body
+:rtype: PDW</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class PDW():
+    &#34;&#34;&#34;
+    I store information from a single ppdw data block.
+
+    .. automethod:: __init__
+    &#34;&#34;&#34;
+
+    @classmethod
+    def from_bytes(cls, byte_string):
+        &#34;&#34;&#34;
+        I create an instance of class PDW from data body (8 * 32 bits).
+
+        :param byte_string: a byte string containing a single data body read from a ppdw file
+        :type byte_string: byte string
+
+        :return: an instance of class PDW with attributes set according to the data of a data body
+        :rtype: PDW
+        &#34;&#34;&#34;
+        assert(len(byte_string) == 32)
+
+        parts = struct.unpack(&#39;&lt;Q4s4s4s4s4s4s&#39;, byte_string)
+        nanoseconds = (parts[0])
+        time_of_arrival = np.datetime64(nanoseconds, &#39;ns&#39;)
+
+        third_entry = bin(int.from_bytes(parts[1], byteorder=&#39;little&#39;))
+        padding = 32-len(str(third_entry)[2:])
+        third_entry_bit_string = &#34;0&#34; * padding + str(third_entry)[2:]
+        pdw_format_identifier = int(third_entry_bit_string[0:6], 2)
+        center_frequency = int(third_entry_bit_string[5:32], 2)
+
+        fourth_entry = bin(int.from_bytes(parts[2], byteorder=&#39;little&#39;))
+        padding = 32-len(str(fourth_entry)[2:])
+        fourth_entry_bit_string = &#34;0&#34; * padding + str(fourth_entry)[2:]
+        is_valid = bool(int(fourth_entry_bit_string[0]))
+        is_pulse = bool(int(fourth_entry_bit_string[1]))
+        level_unit = int(fourth_entry_bit_string[2])
+        signal_start_missing = bool(int(fourth_entry_bit_string[3]))
+        signal_end_missing = bool(int(fourth_entry_bit_string[4]))
+        pulse_width = int(fourth_entry_bit_string[7:33], 2)
+
+        fifth_entry = bin(int.from_bytes(parts[3], byteorder=&#39;little&#39;))
+        padding = 32-len(str(fifth_entry)[2:])
+        fifth_entry_bit_string = &#34;0&#34; * padding + str(fifth_entry)[2:]
+        frequency_shift_or_bandwidth = int(fifth_entry_bit_string[0:20], 2)
+        # FIXME: You have to scale me to the range from -200.0 to 200.0 in 0.1 steps
+        pulse_level_or_pulse_field_strength = math.ceil(int(fifth_entry_bit_string[20:32], 2)) / 10
+
+        sixth_entry = bin(int.from_bytes(parts[4], byteorder=&#39;little&#39;))
+        padding = 32-len(str(sixth_entry)[2:])
+        sixth_entry_bit_string = &#34;0&#34; * padding + str(sixth_entry)[2:]
+        region_of_interest = bool(int(sixth_entry_bit_string[0]))
+        # FIXME: You have to scale me to a range from 0.0 to 6.2 in steps of 0.1 - 6.3 means unknown
+        azimuth_confidence = math.ceil(int(sixth_entry_bit_string[1:7], 2)) / 10
+        modulations = {0: &#39;Unknown&#39;, 1: &#39;Unmodulated&#39;, 2: &#39;FM&#39;, 3: &#39;LFM&#39;, 4: &#39;PSK-2&#39;, 5: &#39;PSK-3&#39;, 6: &#39;PSK-4&#39;,
+                       7: &#39;PSK-m&#39;, 8: &#39;NLFM&#39;, 9: &#39;SFM&#39;, 10: &#39;TFM&#39;, 11: &#39;Pulse too short&#39;}
+        modulation = modulations[int(sixth_entry_bit_string[7:12], 2)]
+        sector = int(sixth_entry_bit_string[28:32], 2)
+
+        seventh_entry = bin(int.from_bytes(parts[5], byteorder=&#39;little&#39;))
+        padding = 32-len(str(seventh_entry)[2:])
+        seventh_entry_bit_string = &#34;0&#34; * padding + str(seventh_entry)[2:]
+        polarities = {0: &#39;Horizontal/Unknown&#39;, 1: &#39;Vertical&#39;, 2: &#39;Counter clockwise&#39;, 3: &#39;Clockwise&#39;}
+        polarity = polarities[int(seventh_entry_bit_string[0:2], 2)]
+        df_quality = int(seventh_entry_bit_string[2:9], 2)
+        # FIXME: You have to scale me from -90 to 90 in 0.1 degree steps
+        elevation = int(seventh_entry_bit_string[9:20], 2)
+        # FIXME: You have to check me for a range from 0.0 to 359.9 in steps of 0.1
+        azimuth = 0.1 * (int(seventh_entry_bit_string[20:32], 2))
+
+        eighth_entry = bin(int.from_bytes(parts[5], byteorder=&#39;little&#39;))
+        padding = 32-len(str(eighth_entry)[2:])
+        eighth_entry_bit_string = &#34;0&#34; * padding + str(eighth_entry)[2:]
+        channel = int(eighth_entry_bit_string[0:4], 2)
+
+        return PDW(time_of_arrival, pdw_format_identifier, center_frequency, is_valid, is_pulse, level_unit,
+                   signal_start_missing, signal_end_missing, pulse_width, frequency_shift_or_bandwidth,
+                   pulse_level_or_pulse_field_strength, region_of_interest, azimuth_confidence, modulation,
+                   sector, polarity, df_quality, elevation, azimuth, channel)
+
+    def __init__(self, time_of_arrival, pdw_format_identifier, center_frequency, is_valid, is_pulse,
+                 level_unit, signal_start_missing, signal_end_missing, pulse_width, frequency_shift_or_bandwidth,
+                 pulse_level_or_pulse_field_strength, region_of_interest, azimuth_confidence, modulation,
+                 sector, polarity, df_quality, elevation, azimuth, channel):
+        r&#34;&#34;&#34;
+        I return an instance of an Pulse Data word.
+
+        :param time_of_arrival: nanoseconds since 1970-01-01 00:00:00
+        :type time_of_arrival: Integer
+        :param pdw_format: format code
+        :type pdw_format: Integer
+        :param center_frequency: center frequency in KHz
+        :type center_frequency: Integer
+        :param is_valid: flag to mark if pdw data body is valid
+        :type is_valid: Boolean
+        :param is_pulse: flag to mark if pdw data body contains a pulse or a continuous wave signal
+        :type is_pulse: Boolean
+        :param level_unit: 0 means dBµV - 1 means dBµV/m
+        :type level_unit: Integer
+        :param signal_start_missing: signal started before time of arrival
+        :type signal_start_missing: Boolean
+        :param signal_end_missing: signal stops after time of arrival
+        :type signal_end_missing: Boolean
+        :param pulse_width: pulse width in nanoseconds - Zero if no valid pulse detected
+        :type pulse_width: Integer
+        :param frequency_shift_or_bandwidth: Value in KHz - Value set to 1048575 means Unknown
+        :type frequency_shift_or_bandwidth: Integer
+        :param pulse_level_or_pulse_field_strength: Pulse level or Pulse Field Strength depending on level_unit \
+         (-200.0...200.0) in 0.1 steps / minus 204.8 means no valid level detected
+        :type pulse_level_or_pulse_field_strength: Float
+        :param region_of_interest: Marks if signal is from region of interest
+        :type region_of_interest: Boolean
+        :param azimuth_confidence: degree in steps of 0.1 (0.0-6.2) / 6.3 means confidence unknown
+        :type azimuth_confidence: Float
+        :param modulation: type of modulation (e.g. PSK-2, PSK-4, FM etc.)
+        :type modulation: String
+        :param sector: reference antenna sector (0-15)
+        :type sector: Integer
+        :param polarity: Horizontal, Vertical, Clockwise, Counter clockwise
+        :type polarity: String
+        :param df_quality: Direction finding quality in percent (0-100) - Zero means unknown
+        :type df_quality: Integer
+        :param elevation: elevation of incoming signal (from -90 to 90 degree) in steps of 0.1 degree \
+        minus 102.4 means unknown
+        :type elevation: Float
+        :param azimuth: azimuth of incoming signal (from 0 to 359.9 degree) in steps of 0.1 degree \
+        plus 409.5 means unknown
+        :type azimuth: Float
+        :param channel: detecting channel (0-16) - Zero means unknown
+        :type channel: Integer
+        :return: An instance of class PDW with attributes set according to the data of a data body
+        :rtype: PDW
+        &#34;&#34;&#34;
+        self.time_of_arrival = time_of_arrival #
+        self.pdw_format_identifier = pdw_format_identifier
+        self.center_frequency = center_frequency #
+        self.__is_valid = is_valid #
+        self.is_pulse = is_pulse #
+        self.level_unit = level_unit #
+        self.signal_start_missing = signal_start_missing
+        self.signal_end_missing = signal_end_missing
+        self.pulse_width = pulse_width #
+        self.frequency_shift_or_bandwidth = frequency_shift_or_bandwidth #
+        self.pulse_level_or_pulse_field_strength = pulse_level_or_pulse_field_strength #
+        self.region_of_interest = region_of_interest
+        self.azimuth_confidence = azimuth_confidence
+        self.modulation = modulation #
+        self.sector = sector
+        self.polarity = polarity
+        self.df_quality = df_quality #
+        self.elevation = elevation #
+        self.azimuth = azimuth
+        self.channel = channel #
+
+    def __str__(self):
+        &#34;&#34;&#34;
+        I return the string representation of myself.
+
+        :rtype: str
+        &#34;&#34;&#34;
+        output = (&#34;Time of arrival: &#34; + str(self.time_of_arrival) + &#34;\n&#34; +
+                  &#34;PDW Format identifier: &#34; + str(self.pdw_format_identifier) + &#34;\n&#34; +
+                  &#34;Center frequency: &#34; + str(self.center_frequency) + &#34; KHz\n&#34;)
+
+        if self.__is_valid:
+            output += &#34;Signal: Valid\n&#34;
+        else:
+            output += &#34;Signal: Invalid\n&#34;
+
+        if self.is_pulse:
+            output += &#34;Signal type: Pulse\n&#34;
+        else:
+            output += &#34;Signal type: Continuous wave\n&#34;
+
+        if self.level_unit == 1:
+            output += &#34;Pulse level: &#34; + str(self.pulse_level_or_pulse_field_strength) + &#34; dbµV\n&#34;
+        else:
+            output += &#34;Pulse field strength: &#34; + str(self.pulse_level_or_pulse_field_strength) + &#34; dbµV/meter\n&#34;
+
+        output += (&#34;Pulse width: &#34; + str(self.pulse_width) + &#34; nanoseconds\n&#34; +
+                   &#34;Frequency shift or bandwidth: &#34; + str(self.frequency_shift_or_bandwidth) + &#34; KHz\n&#34;)
+
+        if self.region_of_interest:
+            output += &#34;Region of interest: Yes\n&#34;
+        else:
+            output += &#34;Region of interest: No\n&#34;
+
+        if self.azimuth_confidence == 6.3:
+            output += &#34;Azimuth confidence: Invalid\n&#34;
+        else:
+            output += &#34;Azimuth confidence: &#34; + str(self.azimuth_confidence) + &#34; degree\n&#34;
+
+        output += &#34;Modulation: &#34; + str(self.modulation) + &#34;\n&#34;
+
+        if self.sector == 0:
+            output += &#34;Sector: Unknown\n&#34;
+        else:
+            output += &#34;Sector:&#34; + str(self.sector) + &#34;\n&#34;
+
+        output += &#34;Polarity: &#34; + str(self.polarity) + &#34;\n&#34;
+
+        output += &#34;DF quality: &#34; + str(self.df_quality) + &#34; %\n&#34;
+
+        if self.elevation == 1024:
+            output += &#34;Elevation: Unknown\n&#34;
+        else:
+            output += &#34;Elevation: &#34; + str(self.elevation) + &#34; degree\n&#34;
+
+        if self.azimuth == 409.5:
+            output += &#34;Azimuth: Unknown\n&#34;
+        else:
+            output += &#34;Azimuth: &#34; + str(self.azimuth) + &#34; degree\n&#34;
+
+        output += &#34;Channel: &#34; + str(self.channel) + &#34;\n&#34;
+
+        return output
+
+    def is_valid(self):
+        return self.__is_valid
+
+    def to_json(self):
+        return {&#39;time of arrival&#39;: self.time_of_arrival,
+                &#39;FORMATIDENTIFIER&#39;: self.pdw_format_identifier,
+                &#39;center frequency&#39;: self.center_frequency,
+                &#39;VALID&#39;: self.__is_valid,
+                &#39;PULSE&#39;: self.is_pulse,
+                &#39;PULSELEVEL&#39;: self.pulse_level_or_pulse_field_strength,
+                &#39;PULSEWIDTH&#39;: self.pulse_width,
+                &#39;BANDWIDTH&#39;: self.frequency_shift_or_bandwidth,
+                &#39;REGIONOFINTEREST&#39;: self.region_of_interest,
+                &#39;AZIMUTHCONFIDENCE&#39;: self.azimuth_confidence,
+                &#39;MODULATION&#39;: self.modulation,
+                &#39;SECTOR&#39;: self.sector,
+                &#39;POLARITY&#39;: self.polarity,
+                &#39;DFQUALITY&#39;: self.df_quality,
+                &#39;ELEVATION&#39;: self.elevation,
+                &#39;AZIMUTH&#39;: self.azimuth,
+                &#39;CHANNEL&#39;: self.channel
+                }</code></pre>
+</details>
+<h3>Static methods</h3>
+<dl>
+<dt id="ammosreader.PDW.PDW.from_bytes"><code class="name flex">
+<span>def <span class="ident">from_bytes</span></span>(<span>byte_string)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I create an instance of class PDW from data body (8 * 32 bits).</p>
+<p>:param byte_string: a byte string containing a single data body read from a ppdw file
+:type byte_string: byte string</p>
+<p>:return: an instance of class PDW with attributes set according to the data of a data body
+:rtype: PDW</p></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">@classmethod
+def from_bytes(cls, byte_string):
+    &#34;&#34;&#34;
+    I create an instance of class PDW from data body (8 * 32 bits).
+
+    :param byte_string: a byte string containing a single data body read from a ppdw file
+    :type byte_string: byte string
+
+    :return: an instance of class PDW with attributes set according to the data of a data body
+    :rtype: PDW
+    &#34;&#34;&#34;
+    assert(len(byte_string) == 32)
+
+    parts = struct.unpack(&#39;&lt;Q4s4s4s4s4s4s&#39;, byte_string)
+    nanoseconds = (parts[0])
+    time_of_arrival = np.datetime64(nanoseconds, &#39;ns&#39;)
+
+    third_entry = bin(int.from_bytes(parts[1], byteorder=&#39;little&#39;))
+    padding = 32-len(str(third_entry)[2:])
+    third_entry_bit_string = &#34;0&#34; * padding + str(third_entry)[2:]
+    pdw_format_identifier = int(third_entry_bit_string[0:6], 2)
+    center_frequency = int(third_entry_bit_string[5:32], 2)
+
+    fourth_entry = bin(int.from_bytes(parts[2], byteorder=&#39;little&#39;))
+    padding = 32-len(str(fourth_entry)[2:])
+    fourth_entry_bit_string = &#34;0&#34; * padding + str(fourth_entry)[2:]
+    is_valid = bool(int(fourth_entry_bit_string[0]))
+    is_pulse = bool(int(fourth_entry_bit_string[1]))
+    level_unit = int(fourth_entry_bit_string[2])
+    signal_start_missing = bool(int(fourth_entry_bit_string[3]))
+    signal_end_missing = bool(int(fourth_entry_bit_string[4]))
+    pulse_width = int(fourth_entry_bit_string[7:33], 2)
+
+    fifth_entry = bin(int.from_bytes(parts[3], byteorder=&#39;little&#39;))
+    padding = 32-len(str(fifth_entry)[2:])
+    fifth_entry_bit_string = &#34;0&#34; * padding + str(fifth_entry)[2:]
+    frequency_shift_or_bandwidth = int(fifth_entry_bit_string[0:20], 2)
+    # FIXME: You have to scale me to the range from -200.0 to 200.0 in 0.1 steps
+    pulse_level_or_pulse_field_strength = math.ceil(int(fifth_entry_bit_string[20:32], 2)) / 10
+
+    sixth_entry = bin(int.from_bytes(parts[4], byteorder=&#39;little&#39;))
+    padding = 32-len(str(sixth_entry)[2:])
+    sixth_entry_bit_string = &#34;0&#34; * padding + str(sixth_entry)[2:]
+    region_of_interest = bool(int(sixth_entry_bit_string[0]))
+    # FIXME: You have to scale me to a range from 0.0 to 6.2 in steps of 0.1 - 6.3 means unknown
+    azimuth_confidence = math.ceil(int(sixth_entry_bit_string[1:7], 2)) / 10
+    modulations = {0: &#39;Unknown&#39;, 1: &#39;Unmodulated&#39;, 2: &#39;FM&#39;, 3: &#39;LFM&#39;, 4: &#39;PSK-2&#39;, 5: &#39;PSK-3&#39;, 6: &#39;PSK-4&#39;,
+                   7: &#39;PSK-m&#39;, 8: &#39;NLFM&#39;, 9: &#39;SFM&#39;, 10: &#39;TFM&#39;, 11: &#39;Pulse too short&#39;}
+    modulation = modulations[int(sixth_entry_bit_string[7:12], 2)]
+    sector = int(sixth_entry_bit_string[28:32], 2)
+
+    seventh_entry = bin(int.from_bytes(parts[5], byteorder=&#39;little&#39;))
+    padding = 32-len(str(seventh_entry)[2:])
+    seventh_entry_bit_string = &#34;0&#34; * padding + str(seventh_entry)[2:]
+    polarities = {0: &#39;Horizontal/Unknown&#39;, 1: &#39;Vertical&#39;, 2: &#39;Counter clockwise&#39;, 3: &#39;Clockwise&#39;}
+    polarity = polarities[int(seventh_entry_bit_string[0:2], 2)]
+    df_quality = int(seventh_entry_bit_string[2:9], 2)
+    # FIXME: You have to scale me from -90 to 90 in 0.1 degree steps
+    elevation = int(seventh_entry_bit_string[9:20], 2)
+    # FIXME: You have to check me for a range from 0.0 to 359.9 in steps of 0.1
+    azimuth = 0.1 * (int(seventh_entry_bit_string[20:32], 2))
+
+    eighth_entry = bin(int.from_bytes(parts[5], byteorder=&#39;little&#39;))
+    padding = 32-len(str(eighth_entry)[2:])
+    eighth_entry_bit_string = &#34;0&#34; * padding + str(eighth_entry)[2:]
+    channel = int(eighth_entry_bit_string[0:4], 2)
+
+    return PDW(time_of_arrival, pdw_format_identifier, center_frequency, is_valid, is_pulse, level_unit,
+               signal_start_missing, signal_end_missing, pulse_width, frequency_shift_or_bandwidth,
+               pulse_level_or_pulse_field_strength, region_of_interest, azimuth_confidence, modulation,
+               sector, polarity, df_quality, elevation, azimuth, channel)</code></pre>
+</details>
+</dd>
+</dl>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.PDW.PDW.is_valid"><code class="name flex">
+<span>def <span class="ident">is_valid</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def is_valid(self):
+    return self.__is_valid</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PDW.PDW.to_json"><code class="name flex">
+<span>def <span class="ident">to_json</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def to_json(self):
+    return {&#39;time of arrival&#39;: self.time_of_arrival,
+            &#39;FORMATIDENTIFIER&#39;: self.pdw_format_identifier,
+            &#39;center frequency&#39;: self.center_frequency,
+            &#39;VALID&#39;: self.__is_valid,
+            &#39;PULSE&#39;: self.is_pulse,
+            &#39;PULSELEVEL&#39;: self.pulse_level_or_pulse_field_strength,
+            &#39;PULSEWIDTH&#39;: self.pulse_width,
+            &#39;BANDWIDTH&#39;: self.frequency_shift_or_bandwidth,
+            &#39;REGIONOFINTEREST&#39;: self.region_of_interest,
+            &#39;AZIMUTHCONFIDENCE&#39;: self.azimuth_confidence,
+            &#39;MODULATION&#39;: self.modulation,
+            &#39;SECTOR&#39;: self.sector,
+            &#39;POLARITY&#39;: self.polarity,
+            &#39;DFQUALITY&#39;: self.df_quality,
+            &#39;ELEVATION&#39;: self.elevation,
+            &#39;AZIMUTH&#39;: self.azimuth,
+            &#39;CHANNEL&#39;: self.channel
+            }</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.PDW.PDW" href="#ammosreader.PDW.PDW">PDW</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.PDW.PDW.from_bytes" href="#ammosreader.PDW.PDW.from_bytes">from_bytes</a></code></li>
+<li><code><a title="ammosreader.PDW.PDW.is_valid" href="#ammosreader.PDW.PDW.is_valid">is_valid</a></code></li>
+<li><code><a title="ammosreader.PDW.PDW.to_json" href="#ammosreader.PDW.PDW.to_json">to_json</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/PPDWContainer.html
===================================================================
--- doc/ammosreader/PPDWContainer.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/PPDWContainer.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,445 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.PPDWContainer API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.PPDWContainer</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">import numpy as np
+from datetime import datetime
+
+
+class PPDWContainer():
+    &#34;&#34;&#34;
+    I store multiple signals imported from one or more .ppdw files
+    .. automethod:: __init__
+    &#34;&#34;&#34;
+
+    def __init__(self, name, signals=None):
+
+        if signals is None:
+            self.signals = []
+        else:
+            self.signals = signals
+
+        self.name = name
+
+    def __str__(self):
+        return &#34;\n&#34;.join([&#34;Number of pulses:&#34; + str(len(self.signals)),
+                          &#34;Number of valid pulses:&#34; + str(self.number_of_valid_pulses()),
+                          &#34;Number of invalid pulses:&#34; + str(self.number_of_invalid_pulses()),
+                          &#34;Start time:&#34; + str(self.start_time()),
+                          &#34;End time:&#34; + str(self.end_time())])
+
+    def add(self, a_pdw):
+        # print(a_pdw)
+        self.signals.append(a_pdw)
+
+    def as_pulse_dict(self):
+        pulse_dict = {}
+        pulse_dict[0] = self.signals[0].to_json()
+        for index, current_pdw in enumerate(self.signals[1:]):
+            pulse_dict[index+1] = current_pdw.to_json()
+            pulse_dict[index][&#34;dtoa&#34;] = (current_pdw.time_of_arrival - pulse_dict[index][&#34;time of arrival&#34;]).item()/1000.0
+        pulse_dict[index+1][&#34;dtoa&#34;] = 0.0  # np.timedelta64(0, &#39;us&#39;)
+        return pulse_dict
+
+    def number_of_valid_pulses(self):
+        return sum(each.is_valid() for each in self.signals)
+
+    def number_of_invalid_pulses(self):
+        return sum(not each.is_valid() for each in self.signals)
+
+    def without_invalids(self):
+        return PPDWContainer(self.name, [each for each in self.signals if each.is_valid()])
+
+    def julian_date_string(self):
+        ts = (self.start_time() - np.datetime64(&#39;1970-01-01T00:00:00&#39;)) / np.timedelta64(1, &#39;s&#39;)
+        time_tuple = datetime.utcfromtimestamp(ts).timetuple()
+        return str(time_tuple.tm_year)[2:] + str(time_tuple.tm_yday).zfill(3)
+
+    def center_frequencies(self):
+        return list({each.center_frequency for each in self.signals})
+
+    def channels(self):
+        return list({each.channel for each in self.signals})
+
+    def modulations(self):
+        return list({each.modulation for each in self.signals})
+
+    def bandwidths(self):
+        return list({each.frequency_shift_or_bandwidth for each in self.signals})
+
+    def start_time(self):
+        return min([each.time_of_arrival for each in self.signals])
+
+    def end_time(self):
+        return max([each.time_of_arrival for each in self.signals])
+
+    def to_json(self):
+        return {&#39;JULIANDATE&#39;: self.julian_date_string(),
+                &#39;STARTTIME&#39;: str(self.start_time()),
+                &#39;ENDTIME&#39;: str(self.end_time()),
+                &#39;CENTERFREQUENCIES&#39;: self.center_frequencies(),
+                &#39;CHANNELS&#39;: self.channels(),
+                &#39;MODULATIONS&#39;: self.modulations(),
+                &#39;BANDWIDTHS&#39;: self.bandwidths()
+                }
+
+if __name__ == &#39;__main__&#39;:
+    pass</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.PPDWContainer.PPDWContainer"><code class="flex name class">
+<span>class <span class="ident">PPDWContainer</span></span>
+<span>(</span><span>name, signals=None)</span>
+</code></dt>
+<dd>
+<div class="desc"><p>I store multiple signals imported from one or more .ppdw files</p>
+<div class="admonition automethod">
+<p class="admonition-title">Automethod:&ensp;<strong>init</strong></p>
+</div></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class PPDWContainer():
+    &#34;&#34;&#34;
+    I store multiple signals imported from one or more .ppdw files
+    .. automethod:: __init__
+    &#34;&#34;&#34;
+
+    def __init__(self, name, signals=None):
+
+        if signals is None:
+            self.signals = []
+        else:
+            self.signals = signals
+
+        self.name = name
+
+    def __str__(self):
+        return &#34;\n&#34;.join([&#34;Number of pulses:&#34; + str(len(self.signals)),
+                          &#34;Number of valid pulses:&#34; + str(self.number_of_valid_pulses()),
+                          &#34;Number of invalid pulses:&#34; + str(self.number_of_invalid_pulses()),
+                          &#34;Start time:&#34; + str(self.start_time()),
+                          &#34;End time:&#34; + str(self.end_time())])
+
+    def add(self, a_pdw):
+        # print(a_pdw)
+        self.signals.append(a_pdw)
+
+    def as_pulse_dict(self):
+        pulse_dict = {}
+        pulse_dict[0] = self.signals[0].to_json()
+        for index, current_pdw in enumerate(self.signals[1:]):
+            pulse_dict[index+1] = current_pdw.to_json()
+            pulse_dict[index][&#34;dtoa&#34;] = (current_pdw.time_of_arrival - pulse_dict[index][&#34;time of arrival&#34;]).item()/1000.0
+        pulse_dict[index+1][&#34;dtoa&#34;] = 0.0  # np.timedelta64(0, &#39;us&#39;)
+        return pulse_dict
+
+    def number_of_valid_pulses(self):
+        return sum(each.is_valid() for each in self.signals)
+
+    def number_of_invalid_pulses(self):
+        return sum(not each.is_valid() for each in self.signals)
+
+    def without_invalids(self):
+        return PPDWContainer(self.name, [each for each in self.signals if each.is_valid()])
+
+    def julian_date_string(self):
+        ts = (self.start_time() - np.datetime64(&#39;1970-01-01T00:00:00&#39;)) / np.timedelta64(1, &#39;s&#39;)
+        time_tuple = datetime.utcfromtimestamp(ts).timetuple()
+        return str(time_tuple.tm_year)[2:] + str(time_tuple.tm_yday).zfill(3)
+
+    def center_frequencies(self):
+        return list({each.center_frequency for each in self.signals})
+
+    def channels(self):
+        return list({each.channel for each in self.signals})
+
+    def modulations(self):
+        return list({each.modulation for each in self.signals})
+
+    def bandwidths(self):
+        return list({each.frequency_shift_or_bandwidth for each in self.signals})
+
+    def start_time(self):
+        return min([each.time_of_arrival for each in self.signals])
+
+    def end_time(self):
+        return max([each.time_of_arrival for each in self.signals])
+
+    def to_json(self):
+        return {&#39;JULIANDATE&#39;: self.julian_date_string(),
+                &#39;STARTTIME&#39;: str(self.start_time()),
+                &#39;ENDTIME&#39;: str(self.end_time()),
+                &#39;CENTERFREQUENCIES&#39;: self.center_frequencies(),
+                &#39;CHANNELS&#39;: self.channels(),
+                &#39;MODULATIONS&#39;: self.modulations(),
+                &#39;BANDWIDTHS&#39;: self.bandwidths()
+                }</code></pre>
+</details>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.add"><code class="name flex">
+<span>def <span class="ident">add</span></span>(<span>self, a_pdw)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def add(self, a_pdw):
+    # print(a_pdw)
+    self.signals.append(a_pdw)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.as_pulse_dict"><code class="name flex">
+<span>def <span class="ident">as_pulse_dict</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def as_pulse_dict(self):
+    pulse_dict = {}
+    pulse_dict[0] = self.signals[0].to_json()
+    for index, current_pdw in enumerate(self.signals[1:]):
+        pulse_dict[index+1] = current_pdw.to_json()
+        pulse_dict[index][&#34;dtoa&#34;] = (current_pdw.time_of_arrival - pulse_dict[index][&#34;time of arrival&#34;]).item()/1000.0
+    pulse_dict[index+1][&#34;dtoa&#34;] = 0.0  # np.timedelta64(0, &#39;us&#39;)
+    return pulse_dict</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.bandwidths"><code class="name flex">
+<span>def <span class="ident">bandwidths</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def bandwidths(self):
+    return list({each.frequency_shift_or_bandwidth for each in self.signals})</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.center_frequencies"><code class="name flex">
+<span>def <span class="ident">center_frequencies</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def center_frequencies(self):
+    return list({each.center_frequency for each in self.signals})</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.channels"><code class="name flex">
+<span>def <span class="ident">channels</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def channels(self):
+    return list({each.channel for each in self.signals})</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.end_time"><code class="name flex">
+<span>def <span class="ident">end_time</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def end_time(self):
+    return max([each.time_of_arrival for each in self.signals])</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.julian_date_string"><code class="name flex">
+<span>def <span class="ident">julian_date_string</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def julian_date_string(self):
+    ts = (self.start_time() - np.datetime64(&#39;1970-01-01T00:00:00&#39;)) / np.timedelta64(1, &#39;s&#39;)
+    time_tuple = datetime.utcfromtimestamp(ts).timetuple()
+    return str(time_tuple.tm_year)[2:] + str(time_tuple.tm_yday).zfill(3)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.modulations"><code class="name flex">
+<span>def <span class="ident">modulations</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def modulations(self):
+    return list({each.modulation for each in self.signals})</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.number_of_invalid_pulses"><code class="name flex">
+<span>def <span class="ident">number_of_invalid_pulses</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def number_of_invalid_pulses(self):
+    return sum(not each.is_valid() for each in self.signals)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.number_of_valid_pulses"><code class="name flex">
+<span>def <span class="ident">number_of_valid_pulses</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def number_of_valid_pulses(self):
+    return sum(each.is_valid() for each in self.signals)</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.start_time"><code class="name flex">
+<span>def <span class="ident">start_time</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def start_time(self):
+    return min([each.time_of_arrival for each in self.signals])</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.to_json"><code class="name flex">
+<span>def <span class="ident">to_json</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def to_json(self):
+    return {&#39;JULIANDATE&#39;: self.julian_date_string(),
+            &#39;STARTTIME&#39;: str(self.start_time()),
+            &#39;ENDTIME&#39;: str(self.end_time()),
+            &#39;CENTERFREQUENCIES&#39;: self.center_frequencies(),
+            &#39;CHANNELS&#39;: self.channels(),
+            &#39;MODULATIONS&#39;: self.modulations(),
+            &#39;BANDWIDTHS&#39;: self.bandwidths()
+            }</code></pre>
+</details>
+</dd>
+<dt id="ammosreader.PPDWContainer.PPDWContainer.without_invalids"><code class="name flex">
+<span>def <span class="ident">without_invalids</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def without_invalids(self):
+    return PPDWContainer(self.name, [each for each in self.signals if each.is_valid()])</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.PPDWContainer.PPDWContainer" href="#ammosreader.PPDWContainer.PPDWContainer">PPDWContainer</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.add" href="#ammosreader.PPDWContainer.PPDWContainer.add">add</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.as_pulse_dict" href="#ammosreader.PPDWContainer.PPDWContainer.as_pulse_dict">as_pulse_dict</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.bandwidths" href="#ammosreader.PPDWContainer.PPDWContainer.bandwidths">bandwidths</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.center_frequencies" href="#ammosreader.PPDWContainer.PPDWContainer.center_frequencies">center_frequencies</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.channels" href="#ammosreader.PPDWContainer.PPDWContainer.channels">channels</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.end_time" href="#ammosreader.PPDWContainer.PPDWContainer.end_time">end_time</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.julian_date_string" href="#ammosreader.PPDWContainer.PPDWContainer.julian_date_string">julian_date_string</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.modulations" href="#ammosreader.PPDWContainer.PPDWContainer.modulations">modulations</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.number_of_invalid_pulses" href="#ammosreader.PPDWContainer.PPDWContainer.number_of_invalid_pulses">number_of_invalid_pulses</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.number_of_valid_pulses" href="#ammosreader.PPDWContainer.PPDWContainer.number_of_valid_pulses">number_of_valid_pulses</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.start_time" href="#ammosreader.PPDWContainer.PPDWContainer.start_time">start_time</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.to_json" href="#ammosreader.PPDWContainer.PPDWContainer.to_json">to_json</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer.PPDWContainer.without_invalids" href="#ammosreader.PPDWContainer.PPDWContainer.without_invalids">without_invalids</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/PPDWReader.html
===================================================================
--- doc/ammosreader/PPDWReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/PPDWReader.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,170 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader.PPDWReader API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Module <code>ammosreader.PPDWReader</code></h1>
+</header>
+<section id="section-intro">
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">from pathlib import Path
+
+from ammosreader.PDW import PDW
+from ammosreader.PPDWContainer import PPDWContainer
+
+class PPDWReader():
+
+    def __init__(self, a_file):
+
+        self.file = a_file
+        assert self.file.is_file()
+        self.content = self.file.read_bytes()
+        self.cursor = 0
+        self.container = PPDWContainer(self.file.stem)
+
+    def read_all_frames_left(self):
+        try:
+            while self.cursor &lt;= len(self.content) - 32:
+                current_bytes = self.content[self.cursor:self.cursor+32]
+                assert len(current_bytes) == 32
+                if not current_bytes:
+                    # print(&#39;End of file detected&#39;)
+                    break
+                if self.cursor + 32 &gt;= len(self.content):
+                    # print(&#39;Can not read all 32 bytes of next PDW. EOF&#39;)
+                    break
+                self.container.add(PDW.from_bytes(current_bytes))
+                self.cursor += 32
+        except Exception:
+            return None
+        return self.container</code></pre>
+</details>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+<h2 class="section-title" id="header-classes">Classes</h2>
+<dl>
+<dt id="ammosreader.PPDWReader.PPDWReader"><code class="flex name class">
+<span>class <span class="ident">PPDWReader</span></span>
+<span>(</span><span>a_file)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">class PPDWReader():
+
+    def __init__(self, a_file):
+
+        self.file = a_file
+        assert self.file.is_file()
+        self.content = self.file.read_bytes()
+        self.cursor = 0
+        self.container = PPDWContainer(self.file.stem)
+
+    def read_all_frames_left(self):
+        try:
+            while self.cursor &lt;= len(self.content) - 32:
+                current_bytes = self.content[self.cursor:self.cursor+32]
+                assert len(current_bytes) == 32
+                if not current_bytes:
+                    # print(&#39;End of file detected&#39;)
+                    break
+                if self.cursor + 32 &gt;= len(self.content):
+                    # print(&#39;Can not read all 32 bytes of next PDW. EOF&#39;)
+                    break
+                self.container.add(PDW.from_bytes(current_bytes))
+                self.cursor += 32
+        except Exception:
+            return None
+        return self.container</code></pre>
+</details>
+<h3>Methods</h3>
+<dl>
+<dt id="ammosreader.PPDWReader.PPDWReader.read_all_frames_left"><code class="name flex">
+<span>def <span class="ident">read_all_frames_left</span></span>(<span>self)</span>
+</code></dt>
+<dd>
+<div class="desc"></div>
+<details class="source">
+<summary>
+<span>Expand source code</span>
+</summary>
+<pre><code class="python">def read_all_frames_left(self):
+    try:
+        while self.cursor &lt;= len(self.content) - 32:
+            current_bytes = self.content[self.cursor:self.cursor+32]
+            assert len(current_bytes) == 32
+            if not current_bytes:
+                # print(&#39;End of file detected&#39;)
+                break
+            if self.cursor + 32 &gt;= len(self.content):
+                # print(&#39;Can not read all 32 bytes of next PDW. EOF&#39;)
+                break
+            self.container.add(PDW.from_bytes(current_bytes))
+            self.cursor += 32
+    except Exception:
+        return None
+    return self.container</code></pre>
+</details>
+</dd>
+</dl>
+</dd>
+</dl>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3>Super-module</h3>
+<ul>
+<li><code><a title="ammosreader" href="index.html">ammosreader</a></code></li>
+</ul>
+</li>
+<li><h3><a href="#header-classes">Classes</a></h3>
+<ul>
+<li>
+<h4><code><a title="ammosreader.PPDWReader.PPDWReader" href="#ammosreader.PPDWReader.PPDWReader">PPDWReader</a></code></h4>
+<ul class="">
+<li><code><a title="ammosreader.PPDWReader.PPDWReader.read_all_frames_left" href="#ammosreader.PPDWReader.PPDWReader.read_all_frames_left">read_all_frames_left</a></code></li>
+</ul>
+</li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: doc/ammosreader/index.html
===================================================================
--- doc/ammosreader/index.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ doc/ammosreader/index.html	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,160 @@
+<!doctype html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
+<meta name="generator" content="pdoc 0.10.0" />
+<title>ammosreader API documentation</title>
+<meta name="description" content="" />
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/sanitize.min.css" integrity="sha256-PK9q560IAAa6WVRRh76LtCaI8pjTJ2z11v0miyNNjrs=" crossorigin>
+<link rel="preload stylesheet" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/11.0.1/typography.min.css" integrity="sha256-7l/o7C8jubJiy74VsKTidCy1yBkRtiUGbVkYBylBqUg=" crossorigin>
+<link rel="stylesheet preload" as="style" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/styles/github.min.css" crossorigin>
+<style>:root{--highlight-color:#fe9}.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}#sidebar > *:last-child{margin-bottom:2cm}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}h1:target,h2:target,h3:target,h4:target,h5:target,h6:target{background:var(--highlight-color);padding:.2em 0}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{margin-top:.6em;font-weight:bold}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}dt:target .name{background:var(--highlight-color)}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}td{padding:0 .5em}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
+<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%;height:100vh;overflow:auto;position:sticky;top:0}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:1em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
+<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
+<script defer src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.1.1/highlight.min.js" integrity="sha256-Uv3H6lx7dJmRfRvH8TH6kJD1TSK1aFcwgx+mdg3epi8=" crossorigin></script>
+<script>window.addEventListener('DOMContentLoaded', () => hljs.initHighlighting())</script>
+</head>
+<body>
+<main>
+<article id="content">
+<header>
+<h1 class="title">Package <code>ammosreader</code></h1>
+</header>
+<section id="section-intro">
+</section>
+<section>
+<h2 class="section-title" id="header-submodules">Sub-modules</h2>
+<dl>
+<dt><code class="name"><a title="ammosreader.AbstractAmmosReader" href="AbstractAmmosReader.html">ammosreader.AbstractAmmosReader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide a base class for specialized AmmosReaders.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosAudioDataBody" href="AmmosAudioDataBody.html">ammosreader.AmmosAudioDataBody</a></code></dt>
+<dd>
+<div class="desc"><p>I provide an AMMOS data block for audio data frames.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosAudioDataHeader" href="AmmosAudioDataHeader.html">ammosreader.AmmosAudioDataHeader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide an AMMOS data header for audio data frames.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosAudioReader" href="AmmosAudioReader.html">ammosreader.AmmosAudioReader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide a specialized Ammos Reader for audio data.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosAudioSocketReader" href="AmmosAudioSocketReader.html">ammosreader.AmmosAudioSocketReader</a></code></dt>
+<dd>
+<div class="desc"><p>I read a Ammos datastream from a socket.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosConstants" href="AmmosConstants.html">ammosreader.AmmosConstants</a></code></dt>
+<dd>
+<div class="desc"><p>I provide several constants used in R&amp;S software.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosContainer" href="AmmosContainer.html">ammosreader.AmmosContainer</a></code></dt>
+<dd>
+<div class="desc"><p>I store the content of an R&amp;S Ammos file in a more accessible way.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosExtendedAudioDataHeader" href="AmmosExtendedAudioDataHeader.html">ammosreader.AmmosExtendedAudioDataHeader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide an Ammos extended data header for audio data frames.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosExtendedIFDataHeader" href="AmmosExtendedIFDataHeader.html">ammosreader.AmmosExtendedIFDataHeader</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosGlobalFrameBody" href="AmmosGlobalFrameBody.html">ammosreader.AmmosGlobalFrameBody</a></code></dt>
+<dd>
+<div class="desc"><p>I provide an AMMOS global frame body.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosGlobalFrameHeader" href="AmmosGlobalFrameHeader.html">ammosreader.AmmosGlobalFrameHeader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide an AMMOS global frame header.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosIFDataBlock" href="AmmosIFDataBlock.html">ammosreader.AmmosIFDataBlock</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosIFDataBlockHeader" href="AmmosIFDataBlockHeader.html">ammosreader.AmmosIFDataBlockHeader</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosIFDataBody" href="AmmosIFDataBody.html">ammosreader.AmmosIFDataBody</a></code></dt>
+<dd>
+<div class="desc"><p>I provide an AMMOS data body for IF data …</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosIFDataHeader" href="AmmosIFDataHeader.html">ammosreader.AmmosIFDataHeader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide a Ammos data header for IF data frames.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosIFReader" href="AmmosIFReader.html">ammosreader.AmmosIFReader</a></code></dt>
+<dd>
+<div class="desc"><p>I provide a specialized Ammos Reader for IF data.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.AmmosSingleFrame" href="AmmosSingleFrame.html">ammosreader.AmmosSingleFrame</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.IQDWTXBlock" href="IQDWTXBlock.html">ammosreader.IQDWTXBlock</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.PDW" href="PDW.html">ammosreader.PDW</a></code></dt>
+<dd>
+<div class="desc"><p>I store the information of a single PDW block.</p></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.PPDWContainer" href="PPDWContainer.html">ammosreader.PPDWContainer</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+<dt><code class="name"><a title="ammosreader.PPDWReader" href="PPDWReader.html">ammosreader.PPDWReader</a></code></dt>
+<dd>
+<div class="desc"></div>
+</dd>
+</dl>
+</section>
+<section>
+</section>
+<section>
+</section>
+<section>
+</section>
+</article>
+<nav id="sidebar">
+<h1>Index</h1>
+<div class="toc">
+<ul></ul>
+</div>
+<ul id="index">
+<li><h3><a href="#header-submodules">Sub-modules</a></h3>
+<ul>
+<li><code><a title="ammosreader.AbstractAmmosReader" href="AbstractAmmosReader.html">ammosreader.AbstractAmmosReader</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioDataBody" href="AmmosAudioDataBody.html">ammosreader.AmmosAudioDataBody</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioDataHeader" href="AmmosAudioDataHeader.html">ammosreader.AmmosAudioDataHeader</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioReader" href="AmmosAudioReader.html">ammosreader.AmmosAudioReader</a></code></li>
+<li><code><a title="ammosreader.AmmosAudioSocketReader" href="AmmosAudioSocketReader.html">ammosreader.AmmosAudioSocketReader</a></code></li>
+<li><code><a title="ammosreader.AmmosConstants" href="AmmosConstants.html">ammosreader.AmmosConstants</a></code></li>
+<li><code><a title="ammosreader.AmmosContainer" href="AmmosContainer.html">ammosreader.AmmosContainer</a></code></li>
+<li><code><a title="ammosreader.AmmosExtendedAudioDataHeader" href="AmmosExtendedAudioDataHeader.html">ammosreader.AmmosExtendedAudioDataHeader</a></code></li>
+<li><code><a title="ammosreader.AmmosExtendedIFDataHeader" href="AmmosExtendedIFDataHeader.html">ammosreader.AmmosExtendedIFDataHeader</a></code></li>
+<li><code><a title="ammosreader.AmmosGlobalFrameBody" href="AmmosGlobalFrameBody.html">ammosreader.AmmosGlobalFrameBody</a></code></li>
+<li><code><a title="ammosreader.AmmosGlobalFrameHeader" href="AmmosGlobalFrameHeader.html">ammosreader.AmmosGlobalFrameHeader</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlock" href="AmmosIFDataBlock.html">ammosreader.AmmosIFDataBlock</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBlockHeader" href="AmmosIFDataBlockHeader.html">ammosreader.AmmosIFDataBlockHeader</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataBody" href="AmmosIFDataBody.html">ammosreader.AmmosIFDataBody</a></code></li>
+<li><code><a title="ammosreader.AmmosIFDataHeader" href="AmmosIFDataHeader.html">ammosreader.AmmosIFDataHeader</a></code></li>
+<li><code><a title="ammosreader.AmmosIFReader" href="AmmosIFReader.html">ammosreader.AmmosIFReader</a></code></li>
+<li><code><a title="ammosreader.AmmosSingleFrame" href="AmmosSingleFrame.html">ammosreader.AmmosSingleFrame</a></code></li>
+<li><code><a title="ammosreader.IQDWTXBlock" href="IQDWTXBlock.html">ammosreader.IQDWTXBlock</a></code></li>
+<li><code><a title="ammosreader.PDW" href="PDW.html">ammosreader.PDW</a></code></li>
+<li><code><a title="ammosreader.PPDWContainer" href="PPDWContainer.html">ammosreader.PPDWContainer</a></code></li>
+<li><code><a title="ammosreader.PPDWReader" href="PPDWReader.html">ammosreader.PPDWReader</a></code></li>
+</ul>
+</li>
+</ul>
+</nav>
+</main>
+<footer id="footer">
+<p>Generated by <a href="https://pdoc3.github.io/pdoc" title="pdoc: Python API documentation generator"><cite>pdoc</cite> 0.10.0</a>.</p>
+</footer>
+</body>
+</html>
Index: blic/.buildinfo
===================================================================
--- public/.buildinfo	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,4 +1,0 @@
-# Sphinx build info version 1
-# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
-config: bd0cf0b1e5e8b74e46ffad0c7feb7650
-tags: 645f666f9bcd5a90fca523b33c5a78b7
Index: pyproject.toml
===================================================================
--- pyproject.toml	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ pyproject.toml	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,30 @@
+[build-system]
+requires = ["poetry-core>=1.0.7"]
+build-backend = "poetry.core.masonry.api"
+
+[tool.poetry]
+name = "ammosreader"
+version = "0.0.4"
+description = "A package to manage ammos datastreams"
+authors = ["See Contributors"]
+homepage = "https://gitlab.kokyou.de/enno/ammosreader"
+repository = "https://gitlab.kokyou.de/enno/ammosreader"
+license = "MIT"
+readme = "README.md"
+packages = [
+    { include = "ammosreader" }
+]
+
+include = [
+    {path = 'tests/*.py'},
+    {path = 'scripts/*.py'},
+    {path = 'sampleData/*.csv'},
+    {path = 'ammos_logger.conf'}
+]
+[tool.poetry.scripts]
+iqdw_reader = 'scripts.iqdw_reader:main'
+pdw_reader = 'scripts.pdw_reader:main'
+
+[tool.poetry.dependencies] 
+numpy = "~1.23.2" 
+
Index: qs.txt
===================================================================
--- reqs.txt	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,5 +1,0 @@
-numpy==1.21.0
-pymongo==4.1.1
-scipy==1.8.0
-setuptools==58.1.0
-sphinx_adc_theme==0.1.7
Index: quirements.txt
===================================================================
--- requirements.txt	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,7 +1,0 @@
-bitstring==3.1.9
-numpy==1.23.0
-Pillow==9.2.0
-pydub==0.25.1
-pymongo==4.1.1
-scipy==1.8.1
-setuptools==58.1.0
Index: mple_scripts/ammos_viewer.py
===================================================================
--- sample_scripts/ammos_viewer.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,109 +1,0 @@
-"""I provide a simple bit viewer specialized for AMMOS files."""
-
-import tkinter as tk
-from PIL import Image, ImageTk
-# from random import randbytes
-import bitstring
-
-from ammosreader.AmmosAudioReader import AmmosAudioReader
-
-
-class MainApplication(tk.Frame):
-    """I implement a simple bit viewer specialized for AMMOS files."""
-
-    def __init__(self, parent):
-        """I create the application window."""
-        super().__init__(parent)
-
-        self.parent = parent
-        self.file_name = "../sample_data/audio_data_sample.bin"
-        self.ammos_container = AmmosAudioReader(self.file_name).read_all_frames_left()
-        self.file = open(self.file_name, 'rb')
-        self.bytes = self.file.read(-1)
-        self.cycle = tk.IntVar()
-        self.cycle.set(self.ammos_container.unique_frame_sizes()[0])
-        self.cache = tk.IntVar()
-        self.cache.set(500)
-        self.canvas_size = (800, 600)
-        self.offset = tk.IntVar()
-        self.offset.set(0)
-        self.buildup()
-
-    def buildup(self):
-        """I build up the initial user interface."""
-        self.parent.title("File name:" + self.file_name + " Size:" + str(len(self.bytes)))
-        self.pack(fill="both", expand=True)
-        self.default_button_width = 10
-        image_frame = tk.Frame(self)
-        image_frame.pack(side=tk.LEFT)
-        self.canvas = tk.Canvas(image_frame, bg="#000000", width=self.canvas_size[0], height=self.canvas_size[1])
-        self.canvas.pack()
-        pil_image = Image.frombytes("1", self.canvas_size, self.current_bytes())
-        self.image = ImageTk.PhotoImage(pil_image)
-        # pil_image.show()
-        button_frame = tk.Frame(self)
-        self.image_id = self.canvas.create_image(0, 0, anchor='nw', image=self.image)
-        button_frame.pack(side="right")
-
-        tk.Label(button_frame, text='Cycle in bytes').pack(side=tk.TOP)
-        self.cycle_entry = tk.Entry(button_frame, text=self.cycle)
-        self.cycle_entry.pack(side=tk.TOP)
-
-        tk.Label(button_frame, text='Cache in Megabytes').pack(side=tk.TOP)
-        self.cache_entry = tk.Entry(button_frame, text=self.cache)
-        self.cache_entry.pack(side=tk.TOP)
-
-        tk.Label(button_frame, text='Offset in bytes').pack(side=tk.TOP)
-        self.offset_entry = tk.Entry(button_frame, text=self.offset)
-        self.offset_entry.pack(side=tk.TOP)
-
-        tk.Button(button_frame,
-                  text="Update",
-                  width=self.default_button_width,
-                  command=self.update_canvas).pack(side=tk.TOP, fill=tk.BOTH, expand=True)
-
-        tk.Button(
-            button_frame,
-            text="Load file",
-            width=self.default_button_width,
-            command=self.load_file).pack(side="top", fill="both", expand=True)
-
-        tk.Button(
-            button_frame,
-            text="Quit",
-            width=self.default_button_width,
-            command=self.quit).pack(side="top", fill="both", expand=True)
-
-    def current_bytes(self):
-        """I return the current bytes to display in the canvas."""
-        if self.offset.get() % 8 == 0:
-            return b"".join([self.bytes[each: each+self.canvas_size[0]] for each in range(self.offset.get(),
-                                                                                          len(self.bytes),
-                                                                                          self.cycle.get())])
-        bits = bitstring.BitArray(self.bytes)
-        new_bytes = bits[self.offset.get()*8:].tobytes()
-        return b"".join([new_bytes[each: each+self.canvas_size[0]] for each in range(0,
-                                                                                     len(new_bytes),
-                                                                                     self.cycle.get())])
-
-    def update_canvas(self):
-        """I update the canvas."""
-        self.image = ImageTk.PhotoImage(Image.frombytes("L", self.canvas_size, self.current_bytes()))
-        self.canvas.itemconfig(self.image_id, image=self.image)
-
-    def load_file(self):
-        """I load a binary ammos file."""
-        pass
-
-    def quit(self):
-        """I quit the application."""
-        self.parent.destroy()
-
-
-if __name__ == '__main__':
-    root = tk.Tk()
-    root.geometry("1920x1200")
-
-    app = MainApplication(root)
-
-    root.mainloop()
Index: mple_scripts/audio_reader.py
===================================================================
--- sample_scripts/audio_reader.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,34 +1,0 @@
-import sys
-import io
-from pydub import AudioSegment
-from pydub.playback import play
-
-from ammosreader.AmmosAudioReader import AmmosAudioReader
-
-if __name__ == '__main__':
-
-    if len(sys.argv) != 2:
-        sys.exit()
-
-    file_name = sys.argv[1]
-
-    print("File name:", file_name)
-
-    dat_file = AmmosAudioReader(file_name)
-
-    dat_file.read_all_frames_left()
-    print("Sample rate:", dat_file.container.global_frames[0].global_frame_body.data_header.sample_rate)
-    print("Container size:", dat_file.container.size())
-    print("Frequencies", dat_file.container.frequencies())
-    print("Frame types:", dat_file.container.frame_types())
-    print("Unique frame sizes", dat_file.container.unique_frame_sizes())
-    print("Total frame size:", sum(dat_file.container.frame_sizes()))
-    print("Homogenic:", dat_file.container.is_homogenic())
-    pcm_data = dat_file.pcm_for_channel(0)
-    print("PCM data size total:", len(pcm_data))
-    data = AudioSegment.from_raw(io.BytesIO(pcm_data),
-                                 sample_width=2,
-                                 frame_rate=22050,
-                                 channels=1)
-    print("Start playing audio")
-    play(data)
Index: mple_scripts/audio_socket_reader_test.py
===================================================================
--- sample_scripts/audio_socket_reader_test.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,41 +1,0 @@
-import sys
-import os
-
-sys.path.append('../src/')
-
-import socket
-
-import numpy as np
-import scipy.io.wavfile as wavfile
-
-from ammosreader.AmmosAudioSocketReader import AmmosAudioSocketReader
-
-
-if __name__ == '__main__':
-    frames = []
-
-    # create socket
-    in_socket = socket.socket()
-    in_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-    in_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
-    in_socket.bind(('127.0.0.1', 12345))
-    print('Waiting for connection')
-    in_socket.listen(1)
-    conn, _ = in_socket.accept()
-    print('Connected')
-
-    # create AmmosAudioSocketReader
-    socket_reader = AmmosAudioSocketReader(conn)
-
-    print('Reading Frames')
-    while True:
-        try:
-            frames.append(socket_reader.read_next_frame())
-        except KeyboardInterrupt:
-            break
-
-    # write frames to wav file
-    print('Writing frames to Wav File')
-    audio = np.concatenate([frame[0] for frame in frames])
-    print(audio)
-    wavfile.write(f"test.wav", frames[0][1], audio)
Index: mple_scripts/audio_socket_reader_test_streamer.py
===================================================================
--- sample_scripts/audio_socket_reader_test_streamer.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,28 +1,0 @@
-import sys
-import os
-sys.path.append('../src/')
-import socket
-
-try:
-    file_path = sys.argv[1]
-except IndexError:
-    print("Please provide a file path as argument")
-    sys.exit(1)
-except FileNotFoundError:
-    print("File not found")
-    sys.exit(1)
-
-file = open(file_path, 'rb')
-total_bytes = file.read()
-print('File read')
-
-print('Connecting to socket')
-out_socket = socket.socket()
-out_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-out_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
-out_socket.connect(('127.0.0.1', 12345))
-print('Connected')
-print('Sending Bytes')
-out_socket.sendall(total_bytes)
-out_socket.close()
-out_socket.shutdown(socket.SHUT_RDWR)
Index: mple_scripts/import_signal.py
===================================================================
--- sample_scripts/import_signal.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,94 +1,0 @@
-import sys
-import re
-import sqlite3
-import argparse
-import numpy as np
-from datetime import datetime
-from pathlib import Path
-from pymongo import MongoClient
-from ammosreader.AmmosIFReader import AmmosIFReader
-from ammosreader.PPDWReader import PPDWReader
-
-parser = argparse.ArgumentParser()
-parser.add_argument('-s', '--source', required=True, help='specify source for given signal')
-parser.add_argument('-i', '--input-dir', required=True, help='specify source directory')
-parser.add_argument('-o', '--output-file', required=True, help='specify sqlite3 database file')
-parser.add_argument('-n', '--signal-number', required=True, help='specify number for signal')
-parser.add_argument('-c', '--code', required=True, help='specify code for signal')
-
-args = parser.parse_args()
-
-source = args.source.upper()
-code = args.code.upper()
-signal_number = args.signal_number
-input_dir = Path(args.input_dir)
-sqlite3_file = Path(args.output_file)
-
-if not re.match('[A-Z0-9]{2}', source):
-    print("Source identifier", source, "invalid")
-    sys.exit()
-
-if not re.match('[A-Z][0-9]{3}[A-Z]', code):
-    print("ELINT-Code incorrect")
-    sys.exit(1)
-
-if not re.match('[0-9]{4}', signal_number):
-    print("Signal number incorrect")
-    sys.exit(1)
-
-if not input_dir.is_dir():
-    print("Input dir invalid")
-    sys.exit(1)
-
-dir_name = input_dir.name
-
-files_inside = [each for each in (input_dir.iterdir()) if (each.suffix in ['.idx', '.iqdw', '.ppdw'] and each.stem == dir_name)]
-
-if len(files_inside) != 3:
-    print(".idx, .iqdw or .ppdw file missing in", input_dir)
-    sys.exit(1)
-
-iqdw_file = (input_dir / input_dir.stem).with_suffix('.iqdw')
-ppdw_file = (input_dir / input_dir.stem).with_suffix('.ppdw')
-idx_file = (input_dir / input_dir.stem).with_suffix('.idx')
-
-#if not sqlite3_file.is_file():
-#    print("Sqlite3 database file not found at", sqlite3_file)
-#    sys.exit(1)
-
-# try:
-#    connection = sqlite3.connect(str(sqlite3_file))
-#    cursor = connection.cursor()
-# except Exception:
-#    print("Can not connect to database file", str(sqlite3_file))
-     # sys.exit(1)
-
-#ammos_if_reader = AmmosIFReader(str(iqdw_file))
-#ammos_if_reader.read_all_frames_left()
-# for each_frame in ammos_if_reader.container.global_frames:
-#    print(each_frame)
-
-ppdw_reader = PPDWReader(ppdw_file)
-ppdw_reader.read_all_frames_left()
-
-client = MongoClient('hackathon.kid.local', 27017)
-
-database = client['ELINT']
-ts = (ppdw_reader.container.start_time() - np.datetime64('1970-01-01T00:00:00')) / np.timedelta64(1, 's')
-time_tuple = datetime.utcfromtimestamp(ts).timetuple()
-julian_date_string = str(time_tuple.tm_year)[2:] + str(time_tuple.tm_yday).zfill(3)
-code_collection = database[code]
-year_collection = code_collection[str(time_tuple.tm_year)]
-source_collection = year_collection[source]
-
-json_representation = ppdw_reader.container.to_json()
-json_representation['SIGNALNUMBER'] = signal_number
-json_representation['SOURCEFILE'] = str(ppdw_file)
-source_collection.insert_one(json_representation)
-
-# for each in ppdw_reader.container.signals:
-#    each_json = each.to_json()
-#    each_json['SIGNALNUMBER'] = signal_number
-#    each_json['JULIANDATE'] = julian_date_string
-#    each_json['SOURCEFILE'] = str(ppdw_file)
-#    source_collection.insert_one(each_json)
Index: mple_scripts/import_signals.py
===================================================================
--- sample_scripts/import_signals.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,80 +1,0 @@
-"""I import .ppdw files from multiple subdirectories into a mongodb."""
-
-import sys
-import re
-import argparse
-import numpy as np
-from datetime import datetime
-from pathlib import Path
-from pymongo import MongoClient
-from ammosreader.PPDWReader import PPDWReader
-
-parser = argparse.ArgumentParser()
-parser.add_argument('-s', '--source', required=True, help='specify source for given signal')
-parser.add_argument('-i', '--input-dir', required=True, help='specify source directory')
-
-args = parser.parse_args()
-
-source = args.source.upper()
-input_dir = Path(args.input_dir)
-
-if not re.match('[A-Z0-9]{2}', source):
-    print("Source identifier", source, "invalid")
-    sys.exit()
-
-code = input_dir.name
-
-# FIXME: Directory structure differs
-# FIXME: get julian date, source identifier, signal number and ELINT-Code from input_dir path
-
-# if not re.match('[A-Z][0-9]{3}[A-Z]', code):
-#    print("ELINT-Code incorrect")
-#    sys.exit(1)
-
-
-if not input_dir.is_dir():
-    print("Input dir invalid")
-    sys.exit(1)
-
-subdirs = [f for f in input_dir.iterdir() if f.is_dir()]
-
-client = MongoClient('hackathon.kid.local', 27017)
-
-for each_dir in subdirs:
-
-    # print("Each dir", each_dir)
-    dir_name = each_dir.name
-
-    # if not re.match('[0-9]{5}', dir_name):
-    #    print("Signal number incorrect")
-    #    sys.exit(1)
-
-    files_inside = [each for each in (each_dir.iterdir()) if (each.suffix in ['.idx', '.iqdw', '.ppdw'] and
-                                                              each_dir.stem == dir_name)]
-
-    # print("Files inside", files_inside)
-    if len(files_inside) != 3:
-        print(".idx, .iqdw or .ppdw file missing in", each_dir)
-        sys.exit(1)
-
-    iqdw_file = (input_dir / each_dir / each_dir.stem).with_suffix('.iqdw')
-    ppdw_file = (input_dir / each_dir / each_dir.stem).with_suffix('.ppdw')
-    # print("PPDW file", ppdw_file)
-    idx_file = (input_dir / each_dir / each_dir.stem).with_suffix('.idx')
-
-    ppdw_reader = PPDWReader(ppdw_file)
-    ppdw_reader.read_all_frames_left()
-
-    database = client['ELINT']
-    ts = (ppdw_reader.container.start_time() - np.datetime64('1970-01-01T00:00:00')) / np.timedelta64(1, 's')
-    time_tuple = datetime.utcfromtimestamp(ts).timetuple()
-    julian_date_string = str(time_tuple.tm_year)[2:] + str(time_tuple.tm_yday).zfill(3)
-    print("Julian", julian_date_string, str(ppdw_file))
-    code_collection = database[input_dir.name]
-    year_collection = code_collection[str(time_tuple.tm_year)]
-    source_collection = year_collection[source]
-
-    json_representation = ppdw_reader.container.to_json()
-    json_representation['SIGNALNUMBER'] = dir_name
-    json_representation['SOURCEFILE'] = str(ppdw_file)
-    source_collection.insert_one(json_representation)
Index: mple_scripts/iqdw_reader.py
===================================================================
--- sample_scripts/iqdw_reader.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,20 +1,0 @@
-import sys
-
-from ammosreader.AmmosIFReader import AmmosIFReader
-
-if __name__ == '__main__':
-
-    if len(sys.argv) != 2:
-        sys.exit()
-
-    file_name = sys.argv[1]
-
-    print("File name:", file_name)
-
-    dat_file = AmmosIFReader(file_name)
-
-    dat_file.read_all_frames_left()
-    print("Frequencies", dat_file.container.frequencies())
-    print("Frame types:", dat_file.container.frame_types())
-    print("Total frame sizes:", sum(dat_file.container.frame_sizes()))
-    print("Homogenic:", dat_file.container.is_homogenic())
Index: mple_scripts/pdw_reader.py
===================================================================
--- sample_scripts/pdw_reader.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,27 +1,0 @@
-import os
-import sys
-sys.path.append('../src/')
-
-from ammosreader.PDW import PDW
-
-if __name__ == '__main__':
-
-    if len(sys.argv) != 2:
-        print("Specify name of .ppdw file")
-        sys.exit()
-
-    file_name = sys.argv[1]
-
-    with open(file_name, 'rb') as f:
-
-        while(True):
-            current_bytes = f.read(32)
-            if current_bytes == '':
-                print("End of file detected")
-                break
-            if len(current_bytes) != 32:
-                print("Can not read all 32 bytes of next PDW")
-                break
-
-            current_pdw = PDW.from_bytes(current_bytes)
-            print(current_pdw)
Index: scripts/iqdw_reader.py
===================================================================
--- scripts/iqdw_reader.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ scripts/iqdw_reader.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,19 @@
+import sys
+
+from ammosreader.AmmosIFReader import AmmosIFReader
+
+def main():
+    if len(sys.argv) != 2:
+        sys.exit()
+
+    file_name = sys.argv[1]
+
+    print("File name:", file_name)
+
+    dat_file = AmmosIFReader(file_name)
+
+    dat_file.read_all_frames_left()
+    print("Frequencies", dat_file.container.frequencies())
+    print("Frame types:", dat_file.container.frame_types())
+    print("Total frame sizes:", sum(dat_file.container.frame_sizes()))
+    print("Homogenic:", dat_file.container.is_homogenic())
Index: scripts/pdw_reader.py
===================================================================
--- scripts/pdw_reader.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
+++ scripts/pdw_reader.py	(revision dff8988960eb5307013e281ff749d9fa74557406)
@@ -0,0 +1,25 @@
+import sys
+
+from ammosreader.PDW import PDW
+
+def main():
+
+    if len(sys.argv) != 2:
+        print("Specify name of .ppdw file")
+        sys.exit()
+
+    file_name = sys.argv[1]
+
+    with open(file_name, 'rb') as f:
+
+        while(True):
+            current_bytes = f.read(32)
+            if current_bytes == '':
+                print("End of file detected")
+                break
+            if len(current_bytes) != 32:
+                print("Can not read all 32 bytes of next PDW")
+                break
+
+            current_pdw = PDW.from_bytes(current_bytes)
+            print(current_pdw)
Index: tup.py
===================================================================
--- setup.py	(revision 29bf25ae450e76dd61536c549c5adc13d8a4288f)
+++ 	(revision )
@@ -1,7 +1,0 @@
-from setuptools import setup
-
-setup(
-  name="ammosreader",
-  version="1.2.7",
-  packages=['ammosreader',],
-  scripts=['sample_scripts/iqdw_reader.py'])
