Repository: google/cyanobyte (language: python)

Issue:
Add examples to schema for registers and functions (Schema validation)
Branching off of #267, aid in the development of high-quality schemas by allowing schemas to specify example values for registers and functions.

This will provide:
1. Improved documentation
2. Ability to perform verification of logical functions w/o hardware (unit tests)
3. Allow for logic-only emulation of devices for platform integrations (low priority)

This issue itself will not focus on emulations of devices.

## Spec changes

This change will add a new set of fields to the `register` objects:

```yaml
example:
    valid:
        - 0x43
        - 0x36
    errors:
         BufferOverflow: 0x10
         OtherError: 0x11
```

The will be two child fields. `valid` will contain a list of example fields that may be returned during nominal operation. `error` will be a map of custom error names (key) to their returned result (value).

The second change will come to the function objects:

```yaml
functions:
    temperature:
        computed:
            asCelsius:
                example:
                    valid:
                         - 16
                         - 20
                    errors:
                         OutOfBounds: 55
                 variables:
                     # ...
```

Similarly, each example field will be added to a particular computation. It will have some valid entries as well as a map of error types with returned results.

## Unit tests

A new `python-unittest.py` template can be used to generate device-specific unit tests. Modeled off of the existing Python templates, the register read functions will be replaced by hardcoded entries.

```python
def read_register_a():
    return 0x43 # example.valid[0]
```

These will be processed by the function execution, defined as tests. Assertions will run at the end to see if the function matches one of the valid examples.

```python
def test_ascelsius(self):
    # Run some logic
    variable = read_register_a() # Get the hardcoded 0x43
    # Additional logic
    returnVal = ... # Whatever is normally computed
    expectedVal = 16 # asCelsius.example.valid[0]
    self.assertEqual(expectedVal, returnVal)
```

Finally, running this unit test `python3 -m unittest /path/to/test.py` will verify if the results match.

## Templates

These fields can be added to `doc.md`, `datasheet.tex`, and `webpage.html` to provide additional register-level documentation.

They can also improve code documentation, like `raspberrypi.py`:

```python
def set_{{key.lower()}}(self{% if register.length > 0 %}, data{% endif %}):
        """
{{utils.pad_string("        ", register.description)}}
+        Example value is {{ register.examples.valid[0] }}.
        """
```

## Validator

This can be integrated into the existing Cyanobyte validator tool if the schema includes examples (if not it will generate a file with no tests).

The validator will receive new flags to more precisely tune its output and execution.

```
$ cyanobyte-validator --validate-schema /path/to/files.py
$ cyanobyte-validator --unit-test /path/to/files.py
```

By default the tool will do both, as well as any future validation operations. Internally, the existence of any of these flags will cause all flags to be checked. Technically you could use both flags `--validate-schema --unit-test /path/to/files.py` ahead of a potential third validation technique.


Discussion / hints:
![image](https://user-images.githubusercontent.com/3291635/115160838-54855800-a068-11eb-8638-054343e36055.png)


Fix patch:
diff --git a/cyanobyte-spec/cyanobyte.schema.json b/cyanobyte-spec/cyanobyte.schema.json
index 6c84122..604508b 100644
--- a/cyanobyte-spec/cyanobyte.schema.json
+++ b/cyanobyte-spec/cyanobyte.schema.json
@@ -237,6 +237,10 @@
                 "W",
                 "n"
               ]
+            },
+            "example": {
+              "description": "Example values of this register.",
+              "$ref": "#/definitions/Examples"
             }
           },
           "required": [
@@ -356,6 +360,10 @@
                   "type": "object",
                   "additionalProperties": false,
                   "properties": {
+                    "example": {
+                      "description": "Example return values of this function.",
+                      "$ref": "#/definitions/Examples"
+                    },
                     "input": {
                       "description": "Variables that are required before running computation.",
                       "type": "object",
@@ -429,6 +437,27 @@
         "float64"
       ]
     },
+    "Examples": {
+      "description": "Potential values, good and bad, that may be the outcome of this.",
+      "type": "object",
+      "properties": {
+        "valid": {
+          "description": "Non-exhaustive list of valid example values.",
+          "type": "array",
+          "items": {
+            "type": "number"
+          }
+        },
+        "errors": {
+          "description": "Map where key is a custom error label and value is that error result.",
+          "additionalProperties": true,
+          "type": "object"
+        }
+      },
+      "required": [
+        "valid"
+      ]
+    },
     "Command": {
       "type": "object",
       "description": "A command to be used in Pseduo-YAML operations.",
diff --git a/cyanobyte-templates/datasheet.tex b/cyanobyte-templates/datasheet.tex
index 2c241a9..9b90b10 100644
--- a/cyanobyte-templates/datasheet.tex
+++ b/cyanobyte-templates/datasheet.tex
@@ -67,12 +67,18 @@ \section{Register Description}
 
 \section{Technical specification}
 \centering
-\begin{tabular}{lcrr}
+\begin{tabular}{lcrrr}
 \toprule
- & Register Name & Register Address & Register Length \\
+ & Register Name & Register Address & Register Length & Example \\
 \midrule
 {% for key,register in registers|dictsort %}
-{{key | regex_replace('_', '\_')}} & {{register.title}} & {{register.address}} & {{register.length}} \\
+{{key | regex_replace('_', '\_')}} & {{register.title}} & {{register.address}} & {{register.length}}
+{%- if 'example' in register -%}
+& {{ register.example.valid[0] }} 
+{%- else -%}
+&
+{%- endif -%}
+\\
 {% endfor %}
 \bottomrule
 \end{tabular}
diff --git a/cyanobyte-templates/doc.md b/cyanobyte-templates/doc.md
index 8f5e15f..3317dd6 100644
--- a/cyanobyte-templates/doc.md
+++ b/cyanobyte-templates/doc.md
@@ -57,6 +57,9 @@ description: >
 {% if register.signed %}
 * Signed value
 {% endif %}
+{% if 'example' in register %}
+* Example value: `{{ register.example.valid[0] }}`
+{% endif %}
 
 {{ register.description }}
 {% endfor %}
diff --git a/cyanobyte-templates/webpage.html b/cyanobyte-templates/webpage.html
index 1607562..7d3a343 100644
--- a/cyanobyte-templates/webpage.html
+++ b/cyanobyte-templates/webpage.html
@@ -111,6 +111,9 @@ <h3>
                                 {% if register.signed %}
                                     <br><em>Signed value</em>
                                 {% endif %}
+                                {% if 'example' in register %}
+                                    <br><em>Example value: <code>{{ register.example.valid[0] }}</code></em>
+                                {% endif %}
                             </h3>
                         </td>
                         {% if key in template.registersToFields %}
diff --git a/cyanobyte.egg-info/SOURCES.txt b/cyanobyte.egg-info/SOURCES.txt
index d7961b9..6699014 100644
--- a/cyanobyte.egg-info/SOURCES.txt
+++ b/cyanobyte.egg-info/SOURCES.txt
@@ -40,6 +40,7 @@ cyanobyte-templates/mcu.c
 cyanobyte-templates/mcu.h
 cyanobyte-templates/mcu.jinja2
 cyanobyte-templates/micropython.py
+cyanobyte-templates/python-unittest.py
 cyanobyte-templates/raspberrypi-spi-emboss.py
 cyanobyte-templates/raspberrypi-spi-register.py
 cyanobyte-templates/raspberrypi.py
diff --git a/cyanobyte/validator.py b/cyanobyte/validator.py
index 67434dd..9224972 100644
--- a/cyanobyte/validator.py
+++ b/cyanobyte/validator.py
@@ -7,6 +7,8 @@
 import sys
 import json
 import click
+import os
+import os.path as path
 import yaml
 from yaml.constructor import ConstructorError
 try:
@@ -73,17 +75,64 @@ def cyanobyte_validate(input_files):
         print(e.err)
 
 
+def unittest(input_files):
+    # Load the python-unittest template file
+    template = "cyanobyte-templates/python-unittest.py"
+    try:
+        import pkg_resources
+        template = pkg_resources.resource_filename('cyanobyte-templates', 'python-unittest.py')
+    except:pass
+
+    if _DEBUG:
+        print('cyanobyte-codegen \
+            -c \
+            -o ./tmp/ \
+            -t ' + template + ' ' + ' \
+            '.join(input_files))
+    os.system('cyanobyte-codegen \
+        -c \
+        -o ./tmp/ \
+        -t ' + template + ' ' + ' \
+        '.join(input_files))
+    for i in input_files:
+        # Now execute each unittest
+        file = i.replace('.yaml', '.py')
+        file = path.basename(file)
+        # NOTE: Won't work for different package names
+        if _DEBUG:
+            print('python3 -m unittest tmp/com/cyanobyte/' + file)
+        os.system('python3 -m unittest tmp/com/cyanobyte/' + file)
+
 @click.command()
+@click.option("-d", "--debug", "debug", default=False)
+@click.option("--validate-schema", "flag_schema", is_flag=True)
+@click.option("--unit-test", "flag_unittest", is_flag=True)
 @click.argument("input_files", type=click.Path(exists=True), nargs=-1)
-def click_validate(input_files):
+def click_validate(input_files, flag_schema, flag_unittest, debug=False):
     """
     Main command line entrypoint
 
     Args:
         input_files: A list of CyanoByte documents to validate.
     """
-    cyanobyte_validate(input_files)
-
+    #pylint: disable=global-statement
+    global _DEBUG
+    _DEBUG = debug
+
+    run_schema = True
+    run_unittest = True
+    # Default all modes to true unless there's a flag
+    if flag_schema or flag_unittest:
+        # Then we only allow a few modes
+        if not flag_schema:
+            run_schema = False
+        if not flag_unittest:
+            run_unittest = False
+
+    if run_schema:
+        cyanobyte_validate(input_files)
+    if run_unittest:
+        unittest(input_files)
 
 if __name__ == "__main__":
     click_validate(sys.argv[1:])
diff --git a/peripherals/BMP280.yaml b/peripherals/BMP280.yaml
index abd15d8..5943da4 100644
--- a/peripherals/BMP280.yaml
+++ b/peripherals/BMP280.yaml
@@ -42,18 +42,27 @@ registers:
     title: Temperature MSB
     description: Most-significant bit of temperature measurement result.
     readWrite: R
+    example:
+      valid:
+        - 124
   TempLsb:
     address: 0xFB
     length: 8
     title: Temperature LSB
     description: Middle-significant bit of temperature measurement result.
     readWrite: R
+    example:
+      valid:
+        - 748
   TempXlsb:
     address: 0xFC
     length: 8
     title: Temperature XLSB
     description: Least-significant bit of temperature measurement result.
     readWrite: R
+    example:
+      valid:
+        - 144
   DigT1:
     address: 0x88
     length: 16
@@ -61,6 +70,9 @@ registers:
     description: Compensation register used for temperature measurement result.
     readWrite: R
     signed: false
+    example:
+      valid:
+        - 27504
   DigT2:
     address: 0x8A
     length: 16
@@ -68,6 +80,9 @@ registers:
     description: Compensation register used for temperature measurement result.
     readWrite: R
     signed: true
+    example:
+      valid:
+        - 26435
   DigT3:
     address: 0x8C
     length: 16
@@ -75,24 +90,36 @@ registers:
     description: Compensation register used for temperature measurement result.
     readWrite: R
     signed: true
+    example:
+      valid:
+        - -1000
   PressureMsb:
     address: 0xF7
     length: 8
     title: Pressure MSB
     description: Most-significant bit of pressure measurement result.
     readWrite: R
+    example:
+      valid:
+        - 15600
   PressureLsb:
     address: 0xF8
     length: 8
     title: Pressure LSB
     description: Middle-significant bit of pressure measurement result.
     readWrite: R
+    example:
+      valid:
+        - 33400
   PressureXlsb:
     address: 0xF9
     length: 8
     title: Pressure XLSB
     description: Least-significant bit of pressure measurement result.
     readWrite: R
+    example:
+      valid:
+        - 15920
   DigP1:
     address: 0x8E
     length: 16
@@ -100,6 +127,9 @@ registers:
     title: Digital Pressure Compensation 1
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - 36477
   DigP2:
     address: 0x90
     length: 16
@@ -107,6 +137,9 @@ registers:
     title: Digital Pressure Compensation 2
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - -10685
   DigP3:
     address: 0x92
     length: 16
@@ -114,6 +147,9 @@ registers:
     title: Digital Pressure Compensation 3
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - 3024
   DigP4:
     address: 0x94
     length: 16
@@ -121,6 +157,9 @@ registers:
     title: Digital Pressure Compensation 4
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - 2855
   DigP5:
     address: 0x96
     length: 16
@@ -128,6 +167,9 @@ registers:
     title: Digital Pressure Compensation 5
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - 140
   DigP6:
     address: 0x98
     length: 16
@@ -135,6 +177,9 @@ registers:
     title: Digital Pressure Compensation 6
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - -7
   DigP7:
     address: 0x9A
     length: 16
@@ -142,6 +187,9 @@ registers:
     title: Digital Pressure Compensation 7
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - 15500
   DigP8:
     address: 0x9C
     length: 16
@@ -149,6 +197,9 @@ registers:
     title: Digital Pressure Compensation 8
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - -14600
   DigP9:
     address: 0x9E
     length: 16
@@ -156,6 +207,9 @@ registers:
     title: Digital Pressure Compensation 9
     description: Compensation register used for Pascals conversion.
     readWrite: R
+    example:
+      valid:
+        - 6000
 functions:
   temperature:
     title: Temperature as read by sensor
@@ -184,6 +238,9 @@ functions:
                   bits: 4
         return: output
       asCelsius:
+        example:
+          valid:
+            - 25.080284726874652
         variables:
           valueMsb: int8
           valueLsb: int8
@@ -271,6 +328,9 @@ functions:
                   bits: 4
         return: output
       asHpa:
+        example:
+          valid:
+            - 100653.27026737288
         variables:
           valueMsb: int8
           valueLsb: int8


Test patch:
diff --git a/cyanobyte-templates/python-unittest.py b/cyanobyte-templates/python-unittest.py
new file mode 100644
index 0000000..37cea0c
--- /dev/null
+++ b/cyanobyte-templates/python-unittest.py
@@ -0,0 +1,125 @@
+{% import 'macros.jinja2' as utils %}
+{% import 'base.python.jinja2' as py %}
+{% set template = namespace(enum=false, sign=false, math=false, struct=false, time=false) %}
+{{ utils.pad_string('# ', utils.license(info.copyright.name, info.copyright.date, info.license.name)) -}}
+#
+# Auto-generated file for {{ info.title }} v{{ info.version }}.
+# Generated from {{ fileName }} using Cyanobyte Codegen v{{ version }}
+
+import unittest
+
+{# Copy logic macro from `raspberrypi.py` #}
+{% macro logic(logicalSteps, function) -%}
+
+{% for step in logicalSteps %}
+{% for key in step.keys() %}
+{% if step[key] is mapping and 'rawRead' in step[key] %}
+        {% set bytes = (step[key].rawRead / 8) | round(1, 'ceil') | int %}
+        {{key}} = 0
+        {% for n in range(bytes) %}
+        {# Read each byte one at a time from device #}
+        _datum = self.bus.read_byte(self.device_address)
+        {{key}} = {{key}} << 8 | _datum
+        {% endfor %}
+        {% break %}
+{% endif %}
+{# Check if assignment is a send-op #}
+{% if key == '$cmdWrite' %}
+        {% if 'value' in step[key] %}
+        self.set_{{step[key].register[12:].lower()}}({{step[key].value}})
+        {% else %}
+        self.set_{{step[key].register[12:].lower()}}()
+        {% endif %}
+        {% break %}
+{%- endif %}
+{% if key == '$delay' %}
+        time.sleep({{ step[key].for / 1000 }})
+{{ logic(step[key].after, function) }}
+        {% break %}
+{%- endif %}
+{# Check if assignment op #}
+{% if step[key] is string and step[key][0:1] == "=" %}
+        {{key | camel_to_snake}} {{step[key]}}
+{%- endif %}
+{# Check if assignment is a send-op #}
+{% if key == 'send' %}
+        self.set_{{function.register[12:].lower()}}({{step[key]}})
+{%- endif %}
+{# Check if assignment is register read op #}
+{% if step[key] is string and step[key][:12] == '#/registers/' %}
+        {{key | camel_to_snake}} = self.get_{{step[key][12:].lower()}}()
+{%- endif %}
+{# Check if assignment is function call op #}
+{% if step[key] is string and step[key][:12] == '#/functions/' %}
+        {{key | camel_to_snake}} = self.{{step[key].lower() | regex_replace('#/functions/(?P<function>.+)/(?P<compute>.+)', '\\g<function>_\\g<compute>')}}()
+{%- endif %}
+{# If the value is a list, then this is a logical setter #}
+{% if step[key] is iterable and step[key] is not string %}
+        {{key | camel_to_snake}} = {{py.recursiveAssignLogic(step[key][0], step[key][0].keys()) -}}
+{%- endif %}
+
+{% endfor %}
+{%- endfor %}
+{%- endmacro %}
+
+{{ py.importStdLibs(fields, functions, i2c, template) -}}
+
+class Test{{info.title}}(unittest.TestCase):
+    """
+    Test class to validate behavior for {{info.title}}.
+    """
+    {% for r in registers %}
+    def get_{{r.lower()}}(self):
+        {% if 'example' in registers[r] %}
+        return {{registers[r].example.valid[0]}} # Hardcoded example
+        {% else %}
+        # registers.{{r}}.example does not exist
+        # This will be okay unless we try to call it.
+        raise ValueError("Example does not exist for register {{r}}.")
+        {% endif %}
+
+    def set_{{r.lower()}}(self, val):
+        # Ignore.
+        return
+
+    {% endfor %}
+
+    {% for f in functions %}
+    {% for c in functions[f].computed %}
+    {% set compute = functions[f].computed[c] %}
+    {% if 'example' in compute %}
+    def {{f.lower()}}_{{c.lower()}}(self):
+        return {{compute.example.valid[0]}} # Hardcoded example
+
+    def test_{{c.lower()}}(self):
+        # Execute actual code
+        {# Read `value` if applicable #}
+        {% if 'input' in compute %}
+        {%- for vkey,variable in compute.input|dictsort %}
+        {% if vkey == 'value' %}
+        # Read value of register into a variable
+        value = self.get_{{function.register[12:].lower()}}()
+        {% endif %}
+        {% endfor -%}
+        {% endif %}
+        {# Handle the logic #}
+{{ logic(compute.logic, function) -}}
+        {# Return if applicable #}
+        {# Return a tuple #}
+        {% if 'return' in compute and compute.return is not string %}
+        returnValue = [{% for returnValue in compute.return %}{{ returnValue | camel_to_snake }}{{ ", " if not loop.last }}{% endfor %}]
+        {# Return a plain value #}
+        {% elif compute.return is string %}
+            {# See if we need to massage the data type #}
+            {% if compute.output == 'int16' %}
+        # Convert from a unsigned short to a signed short
+        {{compute.return}} = struct.unpack("h", struct.pack("H", {{compute.return}}))[0]
+            {% endif %}
+        returnValue = {{compute.return}}
+        expectedValue = {{functions[f].computed[c].example.valid[0]}}
+        {% endif %}
+        self.assertEqual(returnValue, expectedValue)
+
+    {% endif %}
+    {% endfor %}
+    {% endfor %}
diff --git a/test/sampleData/datasheet/BMP280.tex b/test/sampleData/datasheet/BMP280.tex
index d9472c2..0136c12 100644
--- a/test/sampleData/datasheet/BMP280.tex
+++ b/test/sampleData/datasheet/BMP280.tex
@@ -49,50 +49,86 @@ \section{Overview}
 
 \section{Register Description}
 \begin{itemize}
-\item Digital Pressure Compensation 1 - Used for Pascals conversion
-\item Digital Pressure Compensation 2 - Used for Pascals conversion
-\item Digital Pressure Compensation 3 - Used for Pascals conversion
-\item Digital Pressure Compensation 4 - Used for Pascals conversion
-\item Digital Pressure Compensation 5 - Used for Pascals conversion
-\item Digital Pressure Compensation 6 - Used for Pascals conversion
-\item Digital Pressure Compensation 7 - Used for Pascals conversion
-\item Digital Pressure Compensation 8 - Used for Pascals conversion
-\item Digital Pressure Compensation 9 - Used for Pascals conversion
-\item Digital Temperature Compensation 1 - Used for Celcius conversion
-\item Digital Temperature Compensation 2 - Used for Celcius conversion
-\item Digital Temperature Compensation 3 - Used for Celcius conversion
-\item Pressure LSB - Part 2 of Pressure
-\item Pressure MSB - Part 1 of Pressure
-\item Pressure XLSB - Part 3 of Pressure
-\item Temperature LSB - Part 2 of temperature
-\item Temperature MSB - Part 1 of temperature
-\item Temperature XLSB - Final part of temperature
+\item Digital Pressure Compensation 1 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 2 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 3 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 4 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 5 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 6 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 7 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 8 - Compensation register used for Pascals conversion.
+\item Digital Pressure Compensation 9 - Compensation register used for Pascals conversion.
+\item Digital Temperature Compensation 1 - Compensation register used for temperature measurement result.
+\item Digital Temperature Compensation 2 - Compensation register used for temperature measurement result.
+\item Digital Temperature Compensation 3 - Compensation register used for temperature measurement result.
+\item Pressure LSB - Middle-significant bit of pressure measurement result.
+\item Pressure MSB - Most-significant bit of pressure measurement result.
+\item Pressure XLSB - Least-significant bit of pressure measurement result.
+\item Temperature LSB - Middle-significant bit of temperature measurement result.
+\item Temperature MSB - Most-significant bit of temperature measurement result.
+\item Temperature XLSB - Least-significant bit of temperature measurement result.
 \end{itemize}
 
 \section{Technical specification}
 \centering
 \begin{tabular}{lcrr}
 \toprule
- & Register Name & Register Address & Register Length \\
+ & Register Name & Register Address & Register Length & Example \\
 \midrule
-DigP1 & Digital Pressure Compensation 1 & 142 & 16 \\
-DigP2 & Digital Pressure Compensation 2 & 144 & 16 \\
-DigP3 & Digital Pressure Compensation 3 & 146 & 16 \\
-DigP4 & Digital Pressure Compensation 4 & 148 & 16 \\
-DigP5 & Digital Pressure Compensation 5 & 150 & 16 \\
-DigP6 & Digital Pressure Compensation 6 & 152 & 16 \\
-DigP7 & Digital Pressure Compensation 7 & 154 & 16 \\
-DigP8 & Digital Pressure Compensation 8 & 156 & 16 \\
-DigP9 & Digital Pressure Compensation 9 & 158 & 16 \\
-DigT1 & Digital Temperature Compensation 1 & 136 & 16 \\
-DigT2 & Digital Temperature Compensation 2 & 138 & 16 \\
-DigT3 & Digital Temperature Compensation 3 & 140 & 16 \\
-PressureLsb & Pressure LSB & 248 & 8 \\
-PressureMsb & Pressure MSB & 247 & 8 \\
-PressureXlsb & Pressure XLSB & 249 & 8 \\
-TempLsb & Temperature LSB & 251 & 8 \\
-TempMsb & Temperature MSB & 250 & 8 \\
-TempXlsb & Temperature XLSB & 252 & 8 \\
+DigP1 & Digital Pressure Compensation 1 & 142 & 16
+& 36477 
+\\
+DigP2 & Digital Pressure Compensation 2 & 144 & 16
+& -10685 
+\\
+DigP3 & Digital Pressure Compensation 3 & 146 & 16
+& 3024 
+\\
+DigP4 & Digital Pressure Compensation 4 & 148 & 16
+& 2855 
+\\
+DigP5 & Digital Pressure Compensation 5 & 150 & 16
+& 140 
+\\
+DigP6 & Digital Pressure Compensation 6 & 152 & 16
+& -7 
+\\
+DigP7 & Digital Pressure Compensation 7 & 154 & 16
+& 15500 
+\\
+DigP8 & Digital Pressure Compensation 8 & 156 & 16
+& -14600 
+\\
+DigP9 & Digital Pressure Compensation 9 & 158 & 16
+& 6000 
+\\
+DigT1 & Digital Temperature Compensation 1 & 136 & 16
+& 27504 
+\\
+DigT2 & Digital Temperature Compensation 2 & 138 & 16
+& 26435 
+\\
+DigT3 & Digital Temperature Compensation 3 & 140 & 16
+& -1000 
+\\
+PressureLsb & Pressure LSB & 248 & 8
+& 33400 
+\\
+PressureMsb & Pressure MSB & 247 & 8
+& 15600 
+\\
+PressureXlsb & Pressure XLSB & 249 & 8
+& 15920 
+\\
+TempLsb & Temperature LSB & 251 & 8
+& 748 
+\\
+TempMsb & Temperature MSB & 250 & 8
+& 124 
+\\
+TempXlsb & Temperature XLSB & 252 & 8
+& 144 
+\\
 \bottomrule
 \end{tabular}
 
@@ -106,15 +142,15 @@ \section{Functions}
 \toprule
   & Description \\
 \midrule
-pressure & Reads the atmospheric pressure \\
-temperature & Reads the temperature \\
+pressure & Reads the atmospheric pressure as a raw value or in hPa. \\
+temperature & Reads the temperature as a raw value or in Celsius. \\
 \bottomrule
 \end{tabular}
 
 
 \raggedright
 \subsection{Function pressure }
-Reads the atmospheric pressure \\
+Reads the atmospheric pressure as a raw value or in hPa. \\
 
 \centering
 \begin{tabular}{lcr}
@@ -136,7 +172,7 @@ \subsection{Function pressure }
 
 \raggedright
 \subsection{Function temperature }
-Reads the temperature \\
+Reads the temperature as a raw value or in Celsius. \\
 
 \centering
 \begin{tabular}{lcr}
diff --git a/test/sampleData/markdown/BMP280.md b/test/sampleData/markdown/BMP280.md
index f4fe48b..874810f 100644
--- a/test/sampleData/markdown/BMP280.md
+++ b/test/sampleData/markdown/BMP280.md
@@ -19,6 +19,7 @@ description: >
 * Address 142
 * 16-bytes
 * Read-only
+* Example value: `36477`
 
 Compensation register used for Pascals conversion.
 
@@ -28,6 +29,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `-10685`
 
 Compensation register used for Pascals conversion.
 
@@ -37,6 +39,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `3024`
 
 Compensation register used for Pascals conversion.
 
@@ -46,6 +49,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `2855`
 
 Compensation register used for Pascals conversion.
 
@@ -55,6 +59,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `140`
 
 Compensation register used for Pascals conversion.
 
@@ -64,6 +69,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `-7`
 
 Compensation register used for Pascals conversion.
 
@@ -73,6 +79,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `15500`
 
 Compensation register used for Pascals conversion.
 
@@ -82,6 +89,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `-14600`
 
 Compensation register used for Pascals conversion.
 
@@ -91,6 +99,7 @@ Compensation register used for Pascals conversion.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `6000`
 
 Compensation register used for Pascals conversion.
 
@@ -99,6 +108,7 @@ Compensation register used for Pascals conversion.
 * Address 136
 * 16-bytes
 * Read-only
+* Example value: `27504`
 
 Compensation register used for temperature measurement result.
 
@@ -108,6 +118,7 @@ Compensation register used for temperature measurement result.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `26435`
 
 Compensation register used for temperature measurement result.
 
@@ -117,6 +128,7 @@ Compensation register used for temperature measurement result.
 * 16-bytes
 * Read-only
 * Signed value
+* Example value: `-1000`
 
 Compensation register used for temperature measurement result.
 
@@ -125,6 +137,7 @@ Compensation register used for temperature measurement result.
 * Address 248
 * 8-bytes
 * Read-only
+* Example value: `33400`
 
 Middle-significant bit of pressure measurement result.
 
@@ -133,6 +146,7 @@ Middle-significant bit of pressure measurement result.
 * Address 247
 * 8-bytes
 * Read-only
+* Example value: `15600`
 
 Most-significant bit of pressure measurement result.
 
@@ -141,6 +155,7 @@ Most-significant bit of pressure measurement result.
 * Address 249
 * 8-bytes
 * Read-only
+* Example value: `15920`
 
 Least-significant bit of pressure measurement result.
 
@@ -149,6 +164,7 @@ Least-significant bit of pressure measurement result.
 * Address 251
 * 8-bytes
 * Read-only
+* Example value: `748`
 
 Middle-significant bit of temperature measurement result.
 
@@ -157,6 +173,7 @@ Middle-significant bit of temperature measurement result.
 * Address 250
 * 8-bytes
 * Read-only
+* Example value: `124`
 
 Most-significant bit of temperature measurement result.
 
@@ -165,6 +182,7 @@ Most-significant bit of temperature measurement result.
 * Address 252
 * 8-bytes
 * Read-only
+* Example value: `144`
 
 Least-significant bit of temperature measurement result.
 
diff --git a/test/sampleData/webpage/BMP280.html b/test/sampleData/webpage/BMP280.html
index 283d2b7..227002d 100644
--- a/test/sampleData/webpage/BMP280.html
+++ b/test/sampleData/webpage/BMP280.html
@@ -65,11 +65,12 @@ <h3>
                                 Addr 136 <br><br>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>27504</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Temperature Compensation 1</h1>
-                            <h2>Used for Celcius conversion</h2>
+                            <h2>Compensation register used for temperature measurement result.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -79,11 +80,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>26435</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Temperature Compensation 2</h1>
-                            <h2>Used for Celcius conversion</h2>
+                            <h2>Compensation register used for temperature measurement result.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -93,11 +95,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>-1000</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Temperature Compensation 3</h1>
-                            <h2>Used for Celcius conversion</h2>
+                            <h2>Compensation register used for temperature measurement result.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -106,11 +109,12 @@ <h3>
                                 Addr 142 <br><br>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>36477</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 1</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -120,11 +124,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>-10685</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 2</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -134,11 +139,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>3024</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 3</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -148,11 +154,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>2855</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 4</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -162,11 +169,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>140</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 5</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -176,11 +184,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>-7</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 6</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -190,11 +199,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>15500</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 7</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -204,11 +214,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>-14600</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 8</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -218,11 +229,12 @@ <h3>
                                 16-bytes <br>
                                     <br><em>Read-only</em>
                                     <br><em>Signed value</em>
+                                    <br><em>Example value: <code>6000</code></em>
                             </h3>
                         </td>
                         <td colspan="16" width="93.75%">
                             <h1>Digital Pressure Compensation 9</h1>
-                            <h2>Used for Pascals conversion</h2>
+                            <h2>Compensation register used for Pascals conversion.</h2>
                         </td>
                     </tr>
                     <tr aria-colspan="32">
@@ -231,11 +243,12 @@ <h3>
                                 Addr 247 <br><br>
                                 8-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>15600</code></em>
                             </h3>
                         </td>
                         <td colspan="8" width="43.75%">
                             <h1>Pressure MSB</h1>
-                            <h2>Part 1 of Pressure</h2>
+                            <h2>Most-significant bit of pressure measurement result.</h2>
                         </td>
                         <td colspan="23" width="43.75%">
                             <!-- intentionally leave empty -->
@@ -247,11 +260,12 @@ <h3>
                                 Addr 248 <br><br>
                                 8-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>33400</code></em>
                             </h3>
                         </td>
                         <td colspan="8" width="43.75%">
                             <h1>Pressure LSB</h1>
-                            <h2>Part 2 of Pressure</h2>
+                            <h2>Middle-significant bit of pressure measurement result.</h2>
                         </td>
                         <td colspan="23" width="43.75%">
                             <!-- intentionally leave empty -->
@@ -263,11 +277,12 @@ <h3>
                                 Addr 249 <br><br>
                                 8-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>15920</code></em>
                             </h3>
                         </td>
                         <td colspan="8" width="43.75%">
                             <h1>Pressure XLSB</h1>
-                            <h2>Part 3 of Pressure</h2>
+                            <h2>Least-significant bit of pressure measurement result.</h2>
                         </td>
                         <td colspan="23" width="43.75%">
                             <!-- intentionally leave empty -->
@@ -279,11 +294,12 @@ <h3>
                                 Addr 250 <br><br>
                                 8-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>124</code></em>
                             </h3>
                         </td>
                         <td colspan="8" width="43.75%">
                             <h1>Temperature MSB</h1>
-                            <h2>Part 1 of temperature</h2>
+                            <h2>Most-significant bit of temperature measurement result.</h2>
                         </td>
                         <td colspan="23" width="43.75%">
                             <!-- intentionally leave empty -->
@@ -295,11 +311,12 @@ <h3>
                                 Addr 251 <br><br>
                                 8-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>748</code></em>
                             </h3>
                         </td>
                         <td colspan="8" width="43.75%">
                             <h1>Temperature LSB</h1>
-                            <h2>Part 2 of temperature</h2>
+                            <h2>Middle-significant bit of temperature measurement result.</h2>
                         </td>
                         <td colspan="23" width="43.75%">
                             <!-- intentionally leave empty -->
@@ -311,11 +328,12 @@ <h3>
                                 Addr 252 <br><br>
                                 8-bytes <br>
                                     <br><em>Read-only</em>
+                                    <br><em>Example value: <code>144</code></em>
                             </h3>
                         </td>
                         <td colspan="8" width="43.75%">
                             <h1>Temperature XLSB</h1>
-                            <h2>Final part of temperature</h2>
+                            <h2>Least-significant bit of temperature measurement result.</h2>
                         </td>
                         <td colspan="23" width="43.75%">
                             <!-- intentionally leave empty -->
@@ -329,19 +347,19 @@ <h2>Functions</h2>
             <ul>
                 <li>
                     <b>pressure.asHpa</b> -
-                    Reads the atmospheric pressure
+                    Reads the atmospheric pressure as a raw value or in hPa.
                 </li>
                 <li>
                     <b>pressure.asRaw</b> -
-                    Reads the atmospheric pressure
+                    Reads the atmospheric pressure as a raw value or in hPa.
                 </li>
                 <li>
                     <b>temperature.asCelsius</b> -
-                    Reads the temperature
+                    Reads the temperature as a raw value or in Celsius.
                 </li>
                 <li>
                     <b>temperature.asRaw</b> -
-                    Reads the temperature
+                    Reads the temperature as a raw value or in Celsius.
                 </li>
             </ul>
         </section>