From 17f91dbb273b33e9eb9b19081db0054de1031e0b Mon Sep 17 00:00:00 2001 From: Manolis Surligas Date: Tue, 3 Sep 2019 16:23:39 +0300 Subject: [PATCH] Add developers information on README --- README.md | 175 ++++++++++++++++-- .../LSF_HD_Horizontal_Color1-300x66.png | Bin 0 -> 13288 bytes docs/assets/SatNOGS-logo-vertical-black.png | Bin 0 -> 3488 bytes docs/assets/gr-satnogs.png | Bin 0 -> 8795 bytes 4 files changed, 158 insertions(+), 17 deletions(-) create mode 100644 docs/assets/LSF_HD_Horizontal_Color1-300x66.png create mode 100644 docs/assets/SatNOGS-logo-vertical-black.png create mode 100644 docs/assets/gr-satnogs.png diff --git a/README.md b/README.md index e0536bc..18ad313 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,15 @@ # gr-satnogs: SatNOGS GNU Radio Out-Of-Tree Module -gr-satnogs is an out-of-tree GNU Radio module that provides all the necessary tools -for decoding signals from various scientific and academic sattelites. +![gr-satnogs](docs/assets/gr-satnogs.png) -## Install +gr-satnogs is an out-of-tree GNU Radio module that provides all the necessary tools +for decoding signals from various scientific and academic satellites. +It also provides blocks for debugging and experimenting with known satellite +telecommunication schemes. + +## Installation ### Requirements -* GNU Radio ( > 3.7.7 ) +* GNU Radio ( > 3.7.11 ) * CMake ( > 3.1) * G++ (with C++11 support) * VOLK @@ -59,13 +63,13 @@ E.g: `cmake -DCMAKE_INSTALL_PREFIX=/usr ..` Also, by default the build system enables a set of blocks used for debugging -during the development. The enable/disable switch is controled through the +during the development. The enable/disable switch is controlled through the `INCLUDE_DEBUG_BLOCKS` boolean variable. If for example, you want to disable the debugging blocks, the **CMake** command would be: `cmake -DINCLUDE_DEBUG_BLOCKS=OFF ..` -Another common control option is the library sugffix of the Linux distribution. +Another common control option is the library suffix of the Linux distribution. There are distributions like Fedora, openSUSE, e.t.c that the their 64-bit version use the `lib64` folder to store the 64-bit versions of their dynamic libraries. On the other hand, distributions like Ubuntu do the exact opposite. They use @@ -77,28 +81,165 @@ can be specified with the `LIB_SUFFIX` variable. For example: will install the libraries at the `/usr/lib64` directory. -## Website -For more indormation about SatNOGS please visit our [site](https://satnogs.org/). +## Development Guide +The development is performed on the `master` branch. +For special cases where a team of developers should work an a common feature, +maintainers may add a special branch on the repository. +However, it will be removed at the time it will be merged on the `master` branch. +All developers should derive the `master` branch for their feature branches and merge +requests should also issued at this branch. +Developers should ensure that do **not** alter the CMake version tags in any +way. + It is a responsibility of the maintainers team. -## Release Policy +Before submitting a new merge request, rebase the `master` branch and +confirm that the automated CI tests have successfully completed for all platforms +mandated by the `.gitlab-ci.yml` recipe. + +### Adding a new Satellite Demodulator +Demodulators are responsible for filtering, resampling and demodulating an +analog signal and converting it into suitable form, for a decoder to be able +to extract the frame and its data. In most cases this is a simple bit stream. + +If the existing demodulators (FSK, AFSK, BPSK, DUV) do not meet +the requirements of a satellite, you may submit your custom demodulator. +Please make sure that you put the GNU Radio Companion files in the `apps/flowgraphs` +directory. + +### Adding a new Satellite Decoder +With the new architecture, adding a new satellite has become an easy and straight +forward task. +The decoders are implemented using the following approach. + +There is a generic block called `frame_decoder`. +This block should not be altered at any case. If you find yourself in a situation +that you need to apply modifications on this block, raise an issue on the +[issue tracker](https://gitlab.com/librespacefoundation/satnogs/gr-satnogs/issues) +The `frame_decoder` block accepts two parameters. A `satnogs::decoder` +object and the item size of the input stream. Internally, the `frame_decoder` +invokes the `decode()` method of the `satnogs::decoder` class. + +The `satnogs::decoder` class, is a virtual class providing a generic API that +every derived decoder class should implement. +The core of this class is the + +``` +decoder_status_t decode (const void *in, int len) +``` +method. This method accepts an input buffer `in`. The type of the items depends +on the implementation. It also takes the `len` argument specifying the number +of items available in the `in` buffer. +The method returns a `decoder_status_t` class object. + +``` +class decoder_status +{ +public: + int consumed; + bool decode_success; + pmt::pmt_t data; + + decoder_status () : + consumed(0), + decode_success(false), + data(pmt::make_dict()) + { + } +}; + +typedef class decoder_status decoder_status_t; +``` +The class contains three fields that allow the `frame_decoder` block to operate +continuously, without any further assistance. It is responsibility of the derived +decoder class to properly set the values to these fields. + +* The `consumed` class should contain the number of items consumed during the +`decode()` method invocation. It is ok to consume 0, less than `len` or `len` +items but not more. +* `decode_success` should be set to true only if a frame was successfully +decoded and its data are available on the `data` field. +* `data` field is a `pmt::pmt_t` dictionary containing the decoded data and other +information regarding it, using the `gr-satnogs` metadata format. More about them +in the [Metadata](#metadata) section + +### Metadata +Each decoder generates a `pmt::pmt_t` dictionary containing the decoded data and +other information regarding the decoded frame. +The `gr::satnogs::metadata` class provides a set of commonly used metadata +keys. +The table below describes some of them: + +| Key | Description | +| --- | ----------- | +| pdu | This string field contains the decoded data in base64 form | +| time | The time at which the frame was received. Time is represented in an ISO 8601 string with microsecond accuracy | +| crc_valid | Boolean indicating if the CRC check has been successfully passed | +| freq_offset | Float value indicating the frequency offset observed | +| corrected_bits | `uint64_t` with the number of corrected bits | +| symbol_erasures | `uint64_t` with the number of erased symbols | +| sample_start | `uint64_t` with the sample index at which the decoder identified the start of the frame | +| sample_cnt | `uint64_t` with the number of samples of a valid frame. `sample_start + sample_cnt` specify the length of a frame in samples | + +The method `Json::Value +metadata::to_json(const pmt::pmt_t& m)` is converts the dictionary `m` +into a valid JSON object. There is also the `std::string +metadata::keys()` static method which returns a list with the available +metadata keys. This method is also available in Python through the Swig interface. + For example: + +``` +$ python +>>> import satnogs +>>> satnogs.metadata.keys() +'[pdu, crc_valid, freq_offset, corrected_bits, time, sample_start, sample_cnt, symbol_erasures]' +>>> +``` + +Using the `json_converter` block, developers can convert a `pmt::pmt_t` +dictionary of a decoder into a `pmt::pmt_t` blob, +containing the raw bytes of the JSON string, which then can be passed to a UDP +sink targeting the `satnogs-client`. +The `json_converter` block accepts also a string that may be used to inject +an arbitrary number of additional information under the `extra` JSON field. +Of course, this string should be in a JSON valid format. + +### Release Policy The `gr-satnogs` OOT module uses the `major.api-compatibility.minor` -versioning scheme. -is used by the [satnogs-client](https://gitlab.com/librespacefoundation/satnogs/satnogs-client), so the release and versioning policy is based on how the -satnogs client is affected by the changes on the `gr-satnogs` software. +versioning scheme. is used by the +[satnogs-client](https://gitlab.com/librespacefoundation/satnogs/satnogs-client), + so the release and versioning policy is based on how the +`satnogs-client` is affected by the changes on the `gr-satnogs` software. * Minor changes, bug fixes or improvements that do not affect in anyway the `satnogs-client` advance the `minor` version. -* The `api-compatibility` indicates changes that require modifications on `satnogs-client` but do not brake the backwards compatibility (e.g a new satallite decoder). In other words, -the `satnogs-client` should continue to operate normally without any modifications. -Changes on `satnogs-client` should be performed only to integrate the new features. +* The `api-compatibility` indicates changes that require modifications +on `satnogs-client` but do not brake the backwards compatibility +(e.g a new satellite decoder). +In other words, the `satnogs-client` should continue to operate normally +without any modifications. Changes on `satnogs-client` should be performed + only to integrate the new features. * `major` version advances when the changes break backwards compatibility with the `satnogs-client`. For every release change a tag with the corresponding version is created. -Releases can be retrieved by the [tags](https://gitlab.com/librespacefoundation/satnogs/gr-satnogs/tags) page. +Releases can be retrieved by the +[tags](https://gitlab.com/librespacefoundation/satnogs/gr-satnogs/tags) page. + +## Website and Contact +For more information about SatNOGS please visit our [site](https://satnogs.org/) +and our [community forums](https://community.libre.space). +You can also chat with the SatNOGS community at +[https://riot.im/app/#/room/#satnogs:matrix.org](https://riot.im/app/#/room/#satnogs:matrix.org), +or on IRC at `#satnogs` on Freenode. +For chatting around the development and for watching the changes in project's gitlab repositories, +join in [https://riot.im/app/#/room/#satnogs-dev:matrix.org](https://riot.im/app/#/room/#satnogs-dev:matrix.org) +or the IRC channel `#satnogs-dev` on Freenode. ## License -© 2016,2017,2018 [Libre Space Foundation](http://librespacefoundation.org). +![SatNOGS](docs/assets/SatNOGS-logo-vertical-black.png) +![Libre Space Foundation](docs/assets/LSF_HD_Horizontal_Color1-300x66.png) +© 2016-2019 [Libre Space Foundation](https://libre.space). Licensed under the [GPLv3](LICENSE). + diff --git a/docs/assets/LSF_HD_Horizontal_Color1-300x66.png b/docs/assets/LSF_HD_Horizontal_Color1-300x66.png new file mode 100644 index 0000000000000000000000000000000000000000..2dff1699b3f5a58cc389b45e07c91eb9b29b1c06 GIT binary patch literal 13288 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 literal 0 HcmV?d00001 diff --git a/docs/assets/SatNOGS-logo-vertical-black.png b/docs/assets/SatNOGS-logo-vertical-black.png new file mode 100644 index 0000000000000000000000000000000000000000..caa66c3cb94de437baa62dc0f35171d9491ed6b4 GIT binary patch literal 3488 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 OKu^a|yH3+C_WuB9h}+x% literal 0 HcmV?d00001