An open API service indexing awesome lists of open source software.

https://github.com/pmiddend/hs-tango

Haskell bindings to the Tango controls system
https://github.com/pmiddend/hs-tango

haskell tango-controls

Last synced: 4 months ago
JSON representation

Haskell bindings to the Tango controls system

Awesome Lists containing this project

README

          

* hs-tango

[[https://www.gnu.org/licenses/gpl-3.0][https://img.shields.io/badge/License-GPLv3-blue.svg]]
[[Hackage][https://img.shields.io/hackage/v/hs-tango.svg]]
[[CI][https://github.com/pmiddend/hs-tango/actions/workflows/build-with-ubuntu.yaml/badge.svg]]

** How to install
*** General instructions
A simple =cabal install hs-tango= should suffice to build and install the library, as you would for any other Haskell library. Of course, you need to have the development packages for Tango (namely "cpptango") installed.

The [[https://tango-controls.readthedocs.io/en/latest/installation/tango-on-linux.html#debian-ubuntu][Tango documentation]] has instructions on how to install Tango for different operating systems. On *Debian* and *Ubuntu*, for example, you can do =apt install libtango-dev=.
*** With Nix

If you're using the Nix package manager, you have to enable flakes, and then use the accompanying =flake.nix=. To get Tango, it uses the [[https://gitlab.desy.de/cfel-sc-public/tango-flake][tango-flake]] from your truly. You can simply clone the repository, do =nix develop=, and then =cabal build=.
** Usage
*** Client, reading attributes

There is haddock documentation available. But just to illustrate how to use the library, here's a little client example:

#+begin_src haskell
{-# LANGUAGE OverloadedStrings #-}

module Main where

import Tango.Client(
parseTangoUrl,
withDeviceProxy,
getTimeout,
AttributeName(..),
readBoolAttribute,
readBoolSpectrumAttribute
)

main :: IO ()
main =
case parseTangoUrl "sys/tg_test/1" of
Left e -> error "couldn't resolve tango URL"
Right deviceAddress -> withDeviceProxy deviceAddress $ \proxy -> do
timeout <- getTimeout proxy
putStrLn $ "proxy timeout is " <> show timeout

booleanResult <- readBoolAttribute proxy (AttributeName "boolean_scalar")
putStrLn $ "boolean_scalar is " <> show booleanResult

booleanResultBetter <- readBoolAttribute proxy (AttributeName "boolean_scalar")
putStrLn $ "boolean_scalar better is " <> show booleanResultBetter

booleanSpectrumResult <- readBoolSpectrumAttribute proxy (AttributeName "boolean_spectrum")
putStrLn $ "boolean_spectrum is " <> show booleanSpectrumResult
#+end_src
*** Client, subscribing to events

In this example, we are subscribing to changes in the attribute =boolean_scalar= and waiting for two changes (the =forM_= loop).

#+begin_src haskell
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}

module Main where

import Control.Concurrent (newChan, readChan, writeChan)
import Control.Monad (forM_)
import Control.Monad.IO.Class (liftIO)
import Data.Int (Int16)
import Data.Text.IO qualified as TIO
import Tango.Client

main =
case parseTangoUrl "sys/tg_test/1" of
Left e -> error "couldn't resolve tango URL"
Right deviceAddress -> withDeviceProxy deviceAddress \proxy -> do
timeout <- getTimeout proxy

chan <- newChan

let attributeName = AttributeName "boolean_scalar"
eventCallback attribute bool = liftIO do
boolValue <- readBoolAttribute proxy attributeName
putStrLn $ "got a change: " <> show boolValue
writeChan chan True

pollAttribute proxy attributeName (Milliseconds 2000)

withSubscribedEvent proxy attributeName ChangeEvent False eventCallback do
forM_ [0 .. 2] \_ -> do
putStrLn "waiting for change"
_ <- readChan chan
putStrLn "received change"
#+end_src

*** Example: Web Astor

Under =benchmark= in the =.cabal= file, you will find =web-astor=, which is a web-based implementation of the Astor starter overlay. It runs on =localhost:8081= and displays a HTML version of Astor, asking for a Tango host. The code is short and should be fairly easy to grasp. A screenshot of that should explain it well:

[[https://raw.githubusercontent.com/pmiddend/hs-tango/main/doc-assets/web-astor.png]]

The example uses Servant and Lucid to render the HTML.
** What's missing

- Server: Everything
- Client
+ Setting advanced attribute properties, specifically event-related ones like =rel_change= and the period for periodic events. This is no technical difficulty, you just have to write the code.
+ Commands returning or receiving an =UInt32=. I'm not sure how to handle this, since tango has no such data type.
+ In event callbacks, it would be good to transport more information like the list of errors, not just a boolean (see cppTango's =event.h=)
+ Dynamic attribute properties such as the "quality" (currently we're only exporting read/write value)
** Rationale for the used dependencies

- =derive-storable= so that we can just declare data types as records, and have C =Storable= instances generated
- =text= to replace =String= for textual data (=ByteString= might have been an option, we haven't decided yet)
- =unliftio= to have the opssibility to have code running in =MonadIO=
** Interesting links/documentation

- [[https://www.esrf.fr/computing/cs/tango/tango_doc/kernel_doc/cpp_doc/classTango_1_1DeviceProxy.html][DeviceProxy C++ API reference]]