{"id":15293193,"url":"https://github.com/ams-osram/osp_aomw","last_synced_at":"2026-04-30T00:35:01.015Z","repository":{"id":257802715,"uuid":"852860101","full_name":"ams-OSRAM/OSP_aomw","owner":"ams-OSRAM","description":"A library with middleware for OSP applications.","archived":false,"fork":false,"pushed_at":"2025-03-03T10:53:58.000Z","size":102,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-03T11:38:50.134Z","etag":null,"topics":["arduino","as1163","e3731i","library","osp","rgb-led"],"latest_commit_sha":null,"homepage":"https://github.com/ams-OSRAM/OSP_aotop","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ams-OSRAM.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-05T14:54:23.000Z","updated_at":"2025-03-03T10:53:28.000Z","dependencies_parsed_at":"2024-09-27T14:43:23.200Z","dependency_job_id":"6de1b1db-5f8e-48e7-a35f-1782efe9f484","html_url":"https://github.com/ams-OSRAM/OSP_aomw","commit_stats":{"total_commits":3,"total_committers":1,"mean_commits":3.0,"dds":0.0,"last_synced_commit":"2290e62c54b5ea50f47b5da6a2779d49296e1a5d"},"previous_names":["ams-osram/osp_aomw"],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ams-OSRAM%2FOSP_aomw","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ams-OSRAM%2FOSP_aomw/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ams-OSRAM%2FOSP_aomw/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ams-OSRAM%2FOSP_aomw/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ams-OSRAM","download_url":"https://codeload.github.com/ams-OSRAM/OSP_aomw/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245284326,"owners_count":20590306,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["arduino","as1163","e3731i","library","osp","rgb-led"],"created_at":"2024-09-30T16:44:58.514Z","updated_at":"2026-04-30T00:35:01.009Z","avatar_url":"https://github.com/ams-OSRAM.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# OSP Middleware aomw\n\nLibrary \"OSP Middleware aomw\", usually abbreviated to \"aomw\",\nis one of the **aolibs**; short for Arduino OSP libraries from ams-OSRAM.\nThis suite implements support for chips that use the Open System Protocol, \nlike the AS1163 (\"SAID\") or the OSIRE E3731i (\"RGBi\").\nThe landing page for the _aolibs_ is on \n[GitHub](https://github.com/ams-OSRAM/OSP_aotop).\n\n\n## Introduction\n\nLibrary _aomw_ is a library with middleware for OSP applications.\nIt implements features like building a topology map of an OSP chain \n(which type of chip at which OSP address), has several I2C device drivers \n(for I2C devices used in the evaluation kit) and scripting \n(simple light animations).\n\n![aomw in context](extras/aolibs-aomw.drawio.png)\n\nThese features are typically used in the `aoapps` library.\n\nThis library also contains a module for color conversions: `aomw_color`.\nThe module is needed to tweak the PWM settings of individual RGB triplets\nin order for a series of them to all show the exact same color;\nand to keep that color when temperature changes. Module `aomw_color`\ncomes with _examples_ but it is not used in the various demos because \nit requires management of color calibration data, beyond the scope of the\nevaluation kit.\n\n\n## Examples\n\nThis library comes with the following examples.\nYou can find them in the Arduino IDE via \n[File \u003e Examples \u003e OSP Middleware aomw \u003e ...](examples):\n\n- **aomw_min** ([source](examples/aomw_min))  \n  This demo scans the OSP chain using the topo builder from the middleware to \n  form a topology map of all nodes of the OSP chain. Next, it toggles\n  the first triplet between magenta and yellow. Note that topo abstracts\n  away that a SAID has three RGB triplets and an RGBI one, and that they\n  need different telegrams for the same results.\n  \n- **aomw_topodump** ([source](examples/aomw_topodump))  \n  This demo scans the OSP chain using the topo builder from the middleware to \n  form a topology map of all nodes of the OSP chain. Next, it prints out the \n  chain configuration: nodes, triplets, i2cbridges.\n  It does feature some time measurement code. See the comment at\n  the end of the sketch for an analysis of the measurements.\n  \n- **aomw_topodemo** ([source](examples/aomw_topodemo))  \n  This demo first creates a topology map of all nodes of the OSP chain. \n  Next it animates a running led animation, constantly updating the triplets.\n  The topo map creation and running led animation is driven from a state\n  machine. This would allow running commands from serial or scanning for \n  presses of UI buttons.\n  \n- **aomw_toposkip** ([source](examples/aomw_toposkip))  \n  This demos the SKIPCHN feature: the topo builder skips channel x of a SAID if\n  the SAID has the SKIPCHNx bit set in OTP. The demo begins with no channels\n  skipped, but each step adds one channel to skip.\n  \n- **aomw_flag** ([source](examples/aomw_flag))  \n  This demo builds a topology map of all nodes of the OSP chain. Next, it \n  uses this topo map to paint country flags spread out over an entire OSP chain.\n\n- **aomw_sseg** ([source](examples/aomw_sseg))  \n  This demo initializes an OSP chain, powers the I2C bridge in a SAID \n  and checks whether there is a quad 7-segment display - as on the SAIDsense \n  board. If there is, the demo configures the display and starts showing \n  increasing numbers.\n\n- **aomw_as6212** ([source](examples/aomw_as6212))  \n  This demo initializes an OSP chain, powers the I2C bridge in a SAID and checks \n  whether there is an AS6212 temperature sensor - as on the SAIDsense board. \n  If there is, the demo configures the sensor and starts reading and printing \n  temperatures at a steady pace.\n\n- **aomw_sfh5721**  ([source](examples/aomw_sfh5721))  \n  This demo initializes an OSP chain, powers the I2C bridge in a SAID and \n  checks whether there is a SFH5721 light sensor - as on the SAIDsense board. \n  If there is, the demo configures the sensor and starts reading and printing \n  light levels at a steady pace.\n\n- **aomw_as5600** ([source](examples/aomw_as5600))  \n  This demo initializes an OSP chain, powers the I2C bridge in a SAID and checks \n  whether there is a AS5600 rotary sensor - as on the SAIDsense board. \n  If there is, the demo configures the sensor and starts reading and printing \n  angles at a steady pace.\n\n- **aomw_iox4b4l** ([source](examples/aomw_iox4b4l))  \n  This demo initializes an OSP chain, powers the I2C bridge in a SAID and \n  checks whether there is a \"selector\". A selector is an I/O-expander (IOX),\n  an I2C device that exposes a set of GPIO pins, in the case of a selector\n  connected to 4 buttons and 4 indicator LEDs.\n  If the selector is found (there is on on the SAIDbasic board and one on \n  the SAIDsense board), the demo plays a light show on the connected \n  indicator LEDs, which can be interrupted by pressing a button connected \n  to the IOX.\n\n- **aomw_eeprom** ([source](examples/aomw_eeprom))  \n  This demo initializes an OSP chain, powers the I2C bridge in a SAID\n  and checks whether there is an EEPROM. If so, reads and prints the\n  entire EEPROM contents, then modifies one row and then restores that.\n  It finalizes by doing a compare of the current EEPROM content with\n  the values read at the start.\n  \n- **aomw_tscript** ([source](examples/aomw_tscript))  \n  This demo uses topo to initialize the OSP chain, then installs one of the\n  animation scripts. The main program continuously loops over all script\n  instructions to draw the \"frames\".\n  \n- **aomw_colormath** ([source](examples/aomw_colormath))  \n  This demo shows how to compute the duty cycles for the R, G, and B LEDs of\n  a calibrated triplet, in order to reach a target color point. This demo \n  also includes a (post-mixing) temperature correction.\n  The demo is \"mathematical\" in that it shows _how_ the computations are done.\n  This demo does not _control_ triplets, or use actual sensor data \n  (temperature), it spoofs inputs and only prints outputs to Serial. \n  See `aomw_colordemo` for a more realistic example.\n  \n- **aomw_colordemo** ([source](examples/aomw_colordemo))  \n  This demo shows how to get uniform colors over multiple RGB triplets with\n  varying temperatures. It controls a SAID chain with triplets, using the \n  temperature sensor in the SAIDs as an approximation of the triplets' \n  temperatures. Note however, the supplied calibration data, although real, \n  is very unlikely to match the users' hardware.\n\n      \n## Module architecture\n\nThis library contains several modules (a source and header file), \nsee figure below. The green boxes are header files (`.h`), \nthe blue boxes are source files (`.cpp`). Arrows indicate `#include`.\nThe modules in the red pane have a common characteristic: they \nare drivers for I2C devices via a SAID. \n\n![Modules](extras/aomw-modules.drawio.png)\n\n- **aomw_topo** (`aomw_topo.cpp` and `aomw_topo.h`) builds and then \n  provides the so-called \"topology map\", a data structure describing the \n  attached OSP chain: how many OSP nodes, how many RGB triplets, how many \n  I2C bridges, plus to which OSP node each triplet or I2C bridge connects. \n  Building the map includes reset, init and a scan (identity, otp) of all \n  nodes, plus configuring all nodes (drive current, power state, errors).\n  \n  Another high level feature of the topo module is to abstract away how to \n  _drive_ triplets (is a triplet on a channel, the channel's drive current \n  settings, the available PWM bits). The topo module defines its own\n  dynamic range: \"topo brightness range\", ranging from 0 to 0x7FFF and \n  is able to map that to any triplet (RGBI's and RGBs connected to SAID).\n  The `aomw_topo_settriplet` abstractions makes it _the API_ \n  for other modules (`aomw_tscript`, `aomw_flag`, most apps in library aoapps).\n  \n  The topo module also has a command handler that can be registered with the \n  command interpreter. This makes the topology map and the high level\n  `aomw_topo_settriplet()` available through the serial interface.\n  \n- **aomw_tscript** (`aomw_tscript.cpp` and `aomw_tscript.h`) implements an\n  interpreter that executes instructions describing an animation on an RGB \n  strip. Typically those scripts are stored in an EEPROM, but the scripts can \n  also come from other sources, there is no dependency from `aomw_tscript` to \n  `aomw_eeprom`. This module uses `aomw_topo` to render the script so any\n  OSP chain supported by topo could be used as a target.\n  \n  The script is an balance between functionality and low memory footprint.\n  Instructions are 16 bits (so a 256 byte EEPROM can store 128 instructions).\n  The RGB values in the instruction are only 3 bit each (so 8 shades). A more\n  detailed explanation is in [aomw_tscript.cpp](src/aomw_tscript.cpp).\n  \n  This module also contains some animation scripts. The application \n  [eepromflasher](https://github.com/ams-OSRAM/OSP_aotop/tree/main/examples/eepromflasher)\n  allows writing scripts to EEPROMs. The app \n  [aoapps_aniscript](https://github.com/ams-OSRAM/OSP_aoapps/tree/main/src/aoapps_aniscript.cpp)\n  reads those EEPROMs and play the animation.\n\n- **aomw_flag** (`aomw_flag.cpp` and `aomw_flag.h`) is a module that can \"paint\"\n  one of its supported country flags (Dutch, European union) to the OSP chain. \n  The flags are available by name and by index. This module uses `aomw_topo` \n  to render the flags on RGB modules.\n  \n  The app [aoapps_swflag](https://github.com/ams-OSRAM/OSP_aoapps/tree/main/src/aoapps_swflag.cpp)\n  uses this module to paint a flag.\n\n- **aomw_color** (`aomw_color.cpp` and `aomw_color.h`) is a module that \n  contains color data types and color conversion routines with the aim to\n  realize uniform colors in an OSP chain irrespective of variations in \n  manufacturing (exact color point of an LED) and irrespective of local \n  temperature (differences). This module comes with two examples \n  ([math](examples/aomw_colormath) and [demo](examples/aomw_colordemo)); \n  but it is not used in any real demo (because the calibration data does not \n  match \"your\" hardware).\n\n- **aomw_iox4b4l** (`aomw_iox4b4l.cpp` and `aomw_iox4b4l.h`) is a driver for \n  a \"selector\" as is found on the SAIDbasic and SAIDsense board. A selector\n  is an I2C based I/O-expander with 4 of its GPIOs attached to an indicator LED, \n  and 4 of its GPIOs attached to a button.\n\n  The app [aoapps_swflag](https://github.com/ams-OSRAM/OSP_aoapps/tree/main/src/aoapps_swflag.cpp)\n  uses the buttons of the selector to select one in four country flags\n  (and it uses the indicator LEDs to indicate the currently selected flag).\n  \n  The app [aoapps_sensors](https://github.com/ams-OSRAM/OSP_aoapps/tree/main/src/aoapps_sensors.cpp)\n  uses the buttons of the selector to select which sensor is active\n  (and it uses the indicator LEDs to indicate the currently selected sensor).\n\n- **aomw_eeprom** (`aomw_eeprom.cpp` and `aomw_eeprom.h`) is a driver for\n  I2C based EEPROMs (AT24C02C with 256 locations of 1 byte). The driver \n  can read bytes from or write bytes to such an EEPROM. It also has a \n  compare feature and a presence check (test if an EEPROM is attached \n  to the I2C bus of a SAID).\n\n- **aomw_as5600** (`aomw_as5600.cpp` and `aomw_as5600.h`) \n  is a driver for an I2C based magnetic rotary sensor (AS5600).\n  It is a simple driver. Upon startup it configures the sensor for its \n  (factory) default register settings. Furthermore there is a function\n  to read the (raw) angle and a function to read the magnetic force.\n\n- **aomw_as6212** (`aomw_as6212.cpp` and `aomw_as6212.h`) \n  is a driver for an I2C based temperature sensor (AS6212).\n  It is a simple driver; it does not support the thresholds, nor\n  the CONFIG fields AL, IM, POL, CF[]. In addition to a function to get \n  the temperature the conversion rate can be controlled.\n\n- **aomw_sfh5721** (`aomw_sfh5721.cpp` and `aomw_sfh5721.h`) \n  is a driver for an I2C based ambient light sensor (SFH 5721).\n  It is a simple driver; it does not support any configuration or \n  channel selection, there is only a function to get the ambient lux level.\n\n- **aomw_sseg** (`aomw_sseg.cpp`, `aomw_sseg.i` and `aomw_sseg.h`) \n  is a driver for a quad 7-segment display as found on SAIDsense board. It uses \n  four I2C based I/O-expanders (PCA9554) to drive the four 7-segment \n  display modules. It includes a font (`aomw_sseg.i`) for the entire ASCII \n  set (although some characters are hard to render on a 7-segment display). \n  This font comes from [Maarten Pennings' GitHub](https://github.com/maarten-pennings/SevenSegment-over-Serial/tree/main/font).\n\nEach module has its own header file, but the library has an overarching \nheader `aomw.h`, which includes the module headers. It is suggested that \nusers just include the overarching header.\n\n\n## API\n\nThe header [aomw.h](src/aomw.h) contains the API of this library.\nIt includes the module headers. The headers contain little documentation; \nfor that see the module source files. \n\n### aomw\n\n- `aomw_init()` not really needed, but added for forward compatibility.\n- `AOMW_VERSION`  identifies the version of the library.\n\n### aomw_topo\n\nThe core functions are `aomw_topo_build()` and `aomw_topo_settriplet(tix,rgb)`.\n\nThe API of the topo module can be divided in several parts.\nFirst of all there are the functions to build the topology map.\n\n- `aomw_topo_build()` is the high level function sending multiple telegrams\n  to probe the OSP chain and build the topology map. this includes \n  reset and init.\n- `aomw_topo_build_start()`, `aomw_topo_build_step()`, and `aomw_topo_build_done()`\n  achieve the same as `aomw_topo_build()`, but these only send\n  one telegram per call (see below on execution architecture).\n  \nSecondly, there are functions to query the topology map.\n\n- `aomw_topo_loop()` indicates direction loop or bidir.\n- `aomw_topo_numnodes()` returns the number of OSP node, and\n  `aomw_topo_node_id(addr)` returns the type of each node.\n  `aomw_topo_node_numtriplets(addr)` returns the number of triplets \n  associated with a node, and `aomw_topo_node_triplet1(addr)` the index\n  of the first triplet associated to it.\n- More important are the triplet functions: `aomw_topo_numtriplets()`\n  returns the number of triplets, `aomw_topo_triplet_addr(tix)` returns\n  the address of the OSP node driving the triplet, `aomw_topo_triplet_chan(tix)`\n  returns the channel number withing the OSP node driving the triplet, and\n  `aomw_topo_triplet_onchan(tix)` returns true if the OSP node uses channels.\n- Two functions list all I2C bridges:\n  `aomw_topo_numi2cbridges()` list the total amount, and \n  `aomw_topo_i2cbridge_addr(bix)` the associated OSP node.\n- `aomw_topo_i2cfind(daddr7)` searches all I2C bridges for an I2C device that\n  acknowledges a read from I2C device address `daddr7`.\n\nThirdly, there are functions to print (dump) the topology map.\n\n- `aomw_topo_dump_summary()` prints a one-line summary to `Serial`.\n- `aomw_topo_dump_nodes()` prints a table of all OSP nodes to `Serial`.\n- `aomw_topo_dump_triplets()` prints a table all triplets to `Serial`.\n- `aomw_topo_dump_i2cbridges()` prints a table of all I2C bridges to `Serial`.\n- `aomw_topo_dump_power()` prints the max power consumption of the nodes to `Serial`.\n\nFourthly, there is the high level API to use the topology map to \ncontrol (the color/brightness of) triplets.\n\n- `AOMW_TOPO_BRIGHTNESS_MAX` defines the \"topo brightness range\" \n  maximum value (0 is the minimum).\n- Type `aomw_topo_rgb_t` is a struct with three fields (r/g/b) each supposed \n  to be in the \"topo brightness range\".\n- `aomw_topo_red`..`aomw_topo_white` some stock colors \n  (of type `aomw_topo_rgb_t`).\n- Key function `aomw_topo_settriplet(tix,rgb)` sets a triplet `tix` \n  to a color `rgb`. As an extra feature, `rgb` is dimmed down using \n  the global dim level (see `aomw_topo_dim_set`).\n- `aomw_topo_dim_set(dim)` and `aomw_topo_dim_get()` allow the caller to set\n  a multiplication factor (0..dim/1024) for `settriplet`.\n\nFifthly, there is a command handler.\n\n- `aomw_topo_cmd_register()` registers the `topo` command with the command \n  interpreter. This makes the topology map and the high level\n  `aomw_topo_settriplet()` and `aomw_topo_dim_set()` available through \n  the serial interface.\n\n\n### aomw_tscript\n\nThe tiny animation script interpreter has two high level functions.\n\n- `aomw_tscript_install(*ints,num)` installs a script \n  (i.e. an array of 16 bit instructions) for the interpreter.\n- `aomw_tscript_playframe()` plays one frame from the installed script.\n  Should be called repeatedly with a constant rate to play the whole\n  script with a fixed frame rate. Automatically wraps around.\n\nLower level functions\n\n- `aomw_tscript_gotofirst()`, `aomw_tscript_gotonext()`, and \n  `aomw_tscript_atend()` form the iterator used by play frame.\n- `aomw_tscript_get()` returns the decoded instruction under the \n  cursor (pointer) of the iterator.\n- `aomw_tscript_playinst()` plays one instruction (the one under the \n  cursor/pointer of the iterator). Note that one frame could be built-up \n  from multiple instructions via the \"with-previous\" flag.\n\nFinally this module has some stock scripts.\n\n- `aomw_tscript_rainbow()`, `aomw_tscript_rainbow_bytes()`\n- `aomw_tscript_bouncingblock()`, `aomw_tscript_bouncingblock_bytes()`\n- `aomw_tscript_colormix()`, `aomw_tscript_colormix_bytes()`\n- `aomw_tscript_heartbeat()`, `aomw_tscript_heartbeat_bytes()`\n\n\n### aomw_flag\n\nThe flag module has \"painters\": functions that paint a pattern on \nthe OSP chain, using the `aomw_topo_settriplet()`.\n\n- `aomw_flag_painter_dutch()`\n- `aomw_flag_painter_columbia()`\n- `aomw_flag_painter_japan()`\n- `aomw_flag_painter_mali()`\n- `aomw_flag_painter_italy()`\n- `aomw_flag_painter_europe()`\n- `aomw_flag_painter_usa()`\n- `aomw_flag_painter_china()`\n\nNext to that, the painters are also available by index:\n\n- `AOMW_FLAG_PIX_DUTCH`\n- `AOMW_FLAG_PIX_COLUMBIA`\n- `AOMW_FLAG_PIX_JAPAN` \n- `AOMW_FLAG_PIX_MALI`    \n- `AOMW_FLAG_PIX_ITALY`\n- `AOMW_FLAG_PIX_EUROPE`\n- `AOMW_FLAG_PIX_USA`   \n- `AOMW_FLAG_PIX_CHINA`\n\nThe index can be used for this (lookup) table.\n\n- `aomw_flag_count()`, `aomw_flag_name(pix)`, and `aomw_flag_painter(pix)`\n\n\n### aomw_color\n\nThe color module has several data types representing colors in different \ncolor spaces.\n\n- `aomw_color_cxcyiv1_t` and `aomw_color_cxcyiv3_t` \n  CIE x,y coordinates and luminous intensity (Cx,Cy,Iv).\n  This is a color space that matches the human eye, it is used to _calibrate_\n  LED colors; it is less suited for color _computations_.\n  The helper functions `aomw_color_cxcyiv1_to_str()` and \n  `aomw_color_cxcyiv3_to_str()` convert instances to a string.\n\n- `aomw_color_xyz1_t` and `aomw_color_xyz3_t` tristimulus X, Y, Z color space.\n  This color space is used by the color _computations_ in this library. \n  The helper functions `aomw_color_xyz1_to_str()` and \n  `aomw_color_xyz3_to_str()` convert instances to a string.\n\n- `aomw_color_mix_t` and `aomw_color_pwm_t` represent duty cycles as \n  fractional numbers (`float`) or as (`uint16_t`) PWM settings.\n  The helper functions `aomw_color_mix_to_str()` and \n  `aomw_color_pwm_to_str()` convert instances to a string.\n\n- `aomw_color_poly_t`, `aomw_color_poly1_t` and `aomw_color_poly3_t` \n  represent polynomials that are used to correct a `aomw_color_cxcyiv1/3_t`\n  color point when temperature drifts away from the color calibration\n  reference temperature.\n\nCalibration data typically comes for fewer drive currents than the SAID \nsupports. Therefore, this library provides interpolation functions\n`aomw_color_interpolate3()` that interpolates between two \n`aomw_color_cxcyiv3_t`. There is also the helper `aomw_color_interpolate1()`.\n\nCalibration data typically comes for one single reference temperature.\nTherefore this library provides temperature correction functions\n`aomw_color_poly_apply3()` on `aomw_color_cxcyiv3_t`.  There is also the \nhelper `aomw_color_poly_apply1()`.\n\nCalibration data typically comes in the form of `aomw_color_cxcyiv3_t`,\nbut color computations use `aomw_color_xyz3_t`. This library \ntherefore has conversion function `aomw_color_cxcyiv3_to_xyz3()`.\nThere is also the helper `aomw_color_cxcyiv1_to_xyz1()`.\n\nThe color module has two color computation functions.\n\n- `aomw_color_computemix()` computes the mixing ratio of the red, green and\n  blue led, in order to reach a target color. It needs the calibration data\n  of the triplet for which to compute the mixing ratio.\n\n- `aomw_color_mix_to_pwm()` computes the PWM settings from the mixing ratio.\n\nSee section [Color computation](#color-computation) for details on \nthe implementation.\n\n\n### aomw_iox4b4l\n\nThis module implements a driver for a \"selector\".\n\nA selector is an I2C based I/O-expander (PCA9554ABS and PCA6408ABSHP)\nconnected to 4 buttons and 4 indicator LEDs, providing a simple user \ninterface to selected one of four.\nSuch a selector is present on the SAIDbasic board (PCA6408ABSHP)\nand the SAIDsense board (PCA9554ABS).\n\nFirst, the driver needs to be coupled to an selector:\n\n- `aomw_iox4b4l_present(addr,daddr7)` checks if the I/O-expander \n  with I2C address `daddr7` is on the bus of the OSP node `addr` \n  (SAID with I2C bridge).\n- `aomw_iox4b4l_init(addr,daddr7,pincfg)` couples the I/O-expander \n  (with address `daddr7`, attached to the OSP node with address `addr`)\n  to the driver.\n  This driver is not multi-instance. It can only control one IOX.\n  The `pincfg` describes which pin is button or LED and whether it is\n  low active or high active.\n- There are macros for `daddr7` and `pincfg` for two boards in the eval kit \n  that have a selector: `AOMW_IOX4B4L_DADDR7_SAIDSENSE`, `AOMW_IOX4B4L_PINCFG_SAIDSENSE`\n  for SAIDsense and `AOMW_IOX4B4L_DADDR7_SAIDBASIC`, `AOMW_IOX4B4L_PINCFG_SAIDBASIC`\n  for SAIDbasic.\n\nTo control the indicator LEDs on the selector:\n\n- `aomw_iox4b4l_led_on(leds)`, `aomw_iox4b4l_led_off(leds)`, \n  `aomw_iox4b4l_led_tgl`, and `aomw_iox4b4l_led_set(leds)`\n  control the indicator LEDs connected to the I/O-expander.\n- `AOMW_IOX4B4L_LEDxxx` are the various masks used for the `leds`\n  parameter; they denote one (or zero, or all) indicator LEDs.\n\nTo check the buttons on the selector:\n\n- `aomw_iox4b4l_but_scan()` scans all input lines of the I/O-expander \n  (those were the buttons are attached to) and stores the current \n  four button states, maintaining the previous state too.\n- `aomw_iox4b4l_but_wentdown(buts)`, `aomw_iox4b4l_but_isdown(buts)`, \n  `aomw_iox4b4l_but_wentup(buts)`, and `aomw4b4l_iox_but_isup(buts)` \n  report the last transition or current button state.\n- `AOMW_IOX4B4L_BUTxxx` are the various masks used for the `buts`\n  parameter; they denote one (or zero, or all) buttons.\n\n\n### aomw_eeprom\n\nThis module implements a driver for an EEPROM memory.\n\nThe EEPROMS used in the OSP evaluation kit are I2C devices storing 1 byte\nin 256 locations (AT24C02C). Depending on their position in the system, \nthese I2C EEPROMs have a different I2C address. There is an EEPROM on the \nOSP32 board, on the SAIDbasic board and there are stand-alone EEPROM sticks\n(that can be plugged into the OSP32 or SAIDbasic board).\n\nFor the boards in the eval kit, the I2C addresses of the used EEPROMs are \nalready defined:\n\n- `AOMW_EEPROM_DADDR7_OSP32` address of the EEPROM on OSP32 board.\n- `AOMW_EEPROM_DADDR7_SAIDBASIC` address of the EEPROM on SAIDbasic board.\n- `AOMW_EEPROM_DADDR7_STICK` address of the EEPROM on I2C EEPROM stick.\n\nThe access functions have the I2C address as parameter \n(next to the OSP address and the EEPROM memory address):\n\n- `aomw_eeprom_read(...)`    reads bytes from an I2C EEPROM.\n- `aomw_eeprom_write(...)`   writes bytes to an I2C EEPROM.\n- `aomw_eeprom_compare(...)` reads bytes from an I2C EEPROM and compares them with a buffer.\n- `aomw_eeprom_present(...)` checks if an EEPROM is present on an I2C bus.\n\n\n### aomw_as5600\n\nThis module implements a driver for an \n[AS5600 magnetic rotary sensor](https://ams-osram.com/products/sensor-solutions/position-sensors/ams-as5600-position-sensor).\n\nThe AS5600 is an I2C sensor, present on the SAIDsense board.\n\nFirst, the driver needs to be coupled to an I2C device:\n\n- `aomw_as5600_present(addr)` checks if the AS5600 is \n  on the bus of the OSP node `addr` (SAID with I2C bridge).\n- `aomw_as5600_init(addr)` couples the AS5600, attached to the OSP node with \n  address `addr`, to the driver.\n  This driver is not multi-instance. It can only control one AS5600.\n- The macro `AOMW_AS5600_DADDR7_SAIDSENSE` maps to the I2C address of \n  the AS5600 on the SAIDsense board.\n  \nThis is a simple driver, it allows no configuration of the sensor.\nIt only has two \"getters\":\n\n- `aomw_as5600_angle_get()` gets the angle measured by the sensor.\n- `aomw_as5600_force_get()` gets the magnetic force measured by the sensor.\n\n\n### aomw_as6212\n\nThis module implements a driver for an \n[AS6212 temperature sensor](https://ams-osram.com/products/sensor-solutions/temperature-sensors/ams-as621x-temperature-sensors).\n\nThe AS6212 is an I2C sensor, present on the SAIDsense board.\n\nFirst, the driver needs to be coupled to an I2C device:\n\n- `aomw_as6212_present(addr)` checks if the AS6212 is \n  on the bus of the OSP node `addr` (SAID with I2C bridge).\n- `aomw_as6212_init(addr)` couples the AS6212, attached to the OSP node with \n  address `addr`, to the driver.\n  This driver is not multi-instance. It can only control one AS6212.\n- The macro `AOMW_AS6212_DADDR7_SAIDSENSE` maps to the I2C address of \n  the AS6212 on the SAIDsense board.\n  \nThis is a simple driver, it allows only configuration of the conversion\nrate and has one \"getters\":\n\n- `aomw_as6212_temp_get()` gets the temperature measured by the sensor.\n- `aomw_as6212_convrate_set(...)`, `aomw_as6212_convrate_get()` sets and \n   gets the conversion rate.\n\n\n### aomw_sfh5721\n\nThis module implements a driver for an \n[SFH5721 ambient light sensor](https://ams-osram.com/products/sensor-solutions/ambient-light-color-spectral-proximity-sensors/osram-chip-led-sfh-5721).\n\nThe SFH5721 is an I2C sensor, present on the SAIDsense board.\n\nFirst, the driver needs to be coupled to an I2C device:\n\n- `aomw_sfh5721_present(addr)` checks if the SFH5721 is \n  on the bus of the OSP node `addr` (SAID with I2C bridge).\n- `aomw_sfh5721_init(addr)` couples the SFH5721, attached to the OSP node with \n  address `addr`, to the driver.\n  This driver is not multi-instance. It can only control one SFH5721.\n- The macro `AOMW_SFH5721_DADDR7_SAIDSENSE` maps to the I2C address of \n  the SFH5721 on the SAIDsense board.\n  \nThis is a simple driver, it has one \"getter\":\n\n- `aomw_sfh5721_als_get()` gets the ambient light measured by the sensor.\n\n\n### aomw_sseg\n\nThis module implements a driver for a quad-segment display as\npresent on the SAIDsense board.\n\nFirst, the driver needs to be coupled to an I2C device:\n\n- `aomw_sseg_present(addr)` checks if the display is \n  on the bus of the OSP node `addr` (SAID with I2C bridge).\n- `aomw_sseg_init(addr)` couples the display, attached to the OSP node with \n  address `addr`, to the driver.\n  This driver is not multi-instance. It can only control one display.\n- The macros `AOMW_SSEG_X_DADDR7_SAIDSENSE` map to the I2C address of \n  I/O-expanders that drive the display on the SAIDsense board.\n  \nThere are several ways to write to the display:\n\n- `aomw_sseg_clr()` clears the display, all segments off.\n- `aomw_sseg_set(...)` an array of bytes (with 8 bits for each of the segments) determines what is shown.\n- `aomw_sseg_print(...)` the passed string is printed - using a built-in font.\n- `aomw_sseg_printf(...)` as `printf`.\n\n\n## Color computation\n\nThe module `aomw_color` provides an a reference implementation \nof color computations with the aim to achieve uniform colors\nindependent of _manufacturing variation_ and independent of LED\n_temperature_ at run time. It relies on a data base with \n_color calibration_ data (color points) and _temperature correction_ \ndata (\"polynomials\") per RGB triplet. \n\nKey input for the color computation is the _target_ color (which includes \nbrightness) that must be realized with some source triplet. Other inputs \nare the selected drive current (which may depend on the target color), the \ntriplet temperature and the PWM range configured in the driver. \n\nThe diagram below shows the computation steps, all the inputs and the \ndatabase with calibration data. It is annotated (in fixed width font) with \nthe names of functions and data types from this library that are needed for \neach step. Some of these are found in module `aomw_color`, others in the\nexample [`aomw_colordemo`](examples/aomw_colordemo).\n\n![Color computation](extras/aomw_color.drawio.png)\n\nThis flow computes the PWM settings for the red, green and blue LED of the \nsource triplet so that it emits the target color. \n\nThe example [`aomw_colordemo`](examples/aomw_colordemo) shows how a\ncalibration database (`caldb`) could be organized:\n\n- The array `caldb_colors[]` stores the color points per RGB triplet for two \n  drive currents. This results in storing three floats (Cx,Cy,Iv) for red, \n  three for green and three for blue, times two (for the drive currents).\n  This results in 18 floats per triplet.\n  \n- Given a triplet index and a drive current, the `caldb` interpolates between\n  the two stored drive currents to obtain (Cx,Cy,Iv) for red, green and blue.\n\n- The array `caldb_polys[]` stores the temperature dependencies (via a second \n  degree polynomial) per RGB triplet. This results in storing two float\n  polynomial coefficients (a,b) per color space component (Cx,Cy,Iv) for red, \n  three for green and three for blue. This results in another 18 floats per \n  triplet. The `aomw_colordemo` also shows a solution that uses one generic\n  polynomial instead of per triplet.\n\n- The next step is to use the actual triplet temperature, and polynomial\n  to compute the temperature shift of the color points.\n  \n- All these computations are in the `cxcyiv3` domain, the last abstraction\n  the calibration database in `aomw_colordemo` makes is to convert to the \n  XYZ color space.\n\n- The database exposes one function `void caldb_get(tix,current,tempc,*triplet)`,\n  where `tix` is the triplet index, `cur` is the drive current, `tempc`\n  the triplet temperature, and `triplet` is an output parameter returning \n  the calibration parameters.\n  \n- The calibration database could also expose the temperature correction \n  polynomials for a _post_ mixing temperature correction approach. See\n  [`aomw_colormath`](examples/aomw_colormath) for an example.\n\nOnce the calibration database supplies the color point of a triplet,\nthe function `aomw_color_computemix()` computes the mixing ratios for that\ntriplet to reach a specified target color. A step is `aomw_color_mix_to_pwm()`\nwhich maps the mixing ratios to 14, 15 or 16 bit PWM driver.\n\n\n## Execution architecture\n\nOne aspect in this library touches the topic of execution architecture. \nThe topo build (`aomw_topo_build()`) sends multiple telegrams\nto probe the OSP chain and build the topology map. Running this is \none go would block other tasks (e.g. checking button presses or\nreceiving commands via serial) for a too long time.\n\nTherefore, `aomw_topo_build()` has been split in three parts \n(`aomw_topo_build_start()`, `aomw_topo_build_step()`, and \n`aomw_topo_build_done()`). These functions send one telegram per call. \nThis is more suitable when other time critical\ntasks need to be executed as well.\n\n\n## Commands\n\nThe topo module also has a command handler that can be registered with the \ncommand interpreter. This makes the topology map and the high level\n`aomw_topo_settriplet()` available through the serial interface.\n\n```cpp\n// Pick commands that we want in this application\nvoid cmds_register() {\n  aocmd_register();           // include all standard commands from aocmd\n  aomw_topo_cmd_register();   // include the topo command\n  Serial.printf(\"cmds: registered\\n\");\n}\n\nvoid setup() {\n  // Identify over Serial\n  Serial.begin(115200);\n\n  // Initialize all libraries\n  aospi_init(); \n  aoosp_init();\n  aocmd_init();\n  aoui32_init();\n  aomw_init();\n\n  cmds_register();\n  ...\n}\n\nvoid loop() {\n  // Process incoming characters (commands)\n  aocmd_cint_pollserial();\n  ...\n}\n```\n\nNote that the command `topo enum` is more powerful than `osp enum`;\nit is \"query-able\".\n\n\n## Version history _aomw_\n\n- **2026 April 29, 1.0.1**\n  - Versions printout now separated with `,` (in examples).\n  - Documentation improved in `aomw_sfh5721.cpp`.\n  - Bug fix: reorder do/print in `aomw_flag.ino`.\n  \n- **2025 September 17, 1.0.0**\n  - Compatibility **warning** `aomw_iox` module and its demo `aomw_iox.ino` are removed (replaced by `aomw_iox4b4l`).\n  - Updated documentation.\n  - Added module `aomw_as5600` (magnetic rotary sensor) and example `aomw_as5600.ino` for SAIDsense board.\n  - Added module `aomw_as6212` (temperature sensor) and example `aomw_as6212.ino` for SAIDsense board.\n  - Added module `aomw_iox4b4l` (I/O-expander with 4 buttons and 4 LEDs) and example `aomw_iox4b4l.ino` for SAIDsense board.\n  - Added module `aomw_sfh5721` (ambient light sensor) and example `aomw_sfh5721.ino` for SAIDsense board.\n  - Added module `aomw_sseg` (quad 7-segment display) and example `aomw_sseg.ino` for SAIDsense board.\n  - Added demo `aomw_toposkip.ino`.\n  - Topo builder now skips a triplet if SKIPCHNx is set in OTP; also does not set current for skipped channels.\n\n- **2025 May 21, 0.5.0**\n  - Added link to examples.\n  - Added module `aomw_color` with an examples `aomw_colormath.ino` and `aomw_colordemo`; updated `readme.md` accordingly.\n  - Added `aomw_topo_dump_power()` also as part of `topo enum` command.\n  - Fixed commented code in `aomw_eeprom_compare()`.\n  - Fix: made `aomw_topo.h` self contained: added `#include \u003cstdint.h\u003e`.\n  - Added OSP32 v12 names for LEDs (e.g. L1.0 aka OUT0).\n  - Documented the used max PWM.\n  \n- **2025 March 3, 0.4.3**\n  - Extended memory for topo to cover largest possible OSP chain.\n  - Fixed typos in doc and code.\n  - Fixed links to apps.\n\n- **2024 November 29, 0.4.2**\n  - Renamed some `err` variables to `result`.\n  - `aomw_tscript_get()` now has \"script installed\" assert.\n  - Updated API documentation of tscript.\n  - Updated `readme.md` and some sources (typos, signaling -\u003e indicator; I/O-expander).\n  \n- **2024 October 8, 0.4.1**\n  - Fixed parsing problems Doxygen.\n  - Prefixed `modules.drawio.png` with library short name.\n  - Updated topology and tiny script documentation (in cpp files).\n  - Fixed doc on \"under voltage\".\n  - Moved domain from `github.com/ams-OSRAM-Group` to `github.com/ams-OSRAM`.\n  - Term cleanup (\"indicator LEDs\" and \"I/O-expander\").\n  - Fixed bug in `walk` animation in `aomw_tscript.ino`.\n  - Fixed HARDWARE description in `aomw_iox.ino`.\n  - Fixed ADDR bug and added printf with used device address in `aomw_eeprom.ino`.\n  - `aomw_flag.ino` now also shows how to use iterator.\n  - Update to `readme.md`.\n  - Added BEHAVIOR section to explanation in examples.\n\n- **2024 September 5, 0.4.0**\n  - API section in readme now shows parameter names.\n  - Adapted to `aoosp_exec_resetinit` not needing `last` and `loop`.\n  - Introduced \"topo brightness range\".\n  - Warning to run `topo build` first.\n  - More uniform error messages in command `topo`.\n  - Added color `aomw_topo_off`.\n  - Moved from shorthand `bix` to `iix` for \"I2C bridge index\".\n  - Added links in `readme.md` for all example sketches.\n  - added `name` to `aomw_topo_rgb_t`.\n  - Example `aomw_min` added.\n  - Corrected link to GitHub from aotop to OSP_aotop.\n  - Remove \"oalib\" from `sentence=` in `library.properties`.\n  - Arduino name changed from `OSP Middleware - aomw` to `OSP Middleware aomw`.\n  - Renamed dir `extra` to `extras`.\n  - `license.txt`, `examples\\xxx.ino` line endings changed from LF to CR+LF.\n\n- **2024 July 02, 0.3.0**  \n  - Initial release candidate.\n\n\n(end)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fams-osram%2Fosp_aomw","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fams-osram%2Fosp_aomw","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fams-osram%2Fosp_aomw/lists"}