/uniset-example-go

Example of using libuniset in conjunction with golang

Primary LanguageGoMIT LicenseMIT

uniset-example-go

Пример работы с package uniset

Демонстрационная задача:

Есть два насоса, один наполняет бак, другой опустошает. Как только бак наполнился, наполнявший насос должен отключиться, а второй (опустошающий) должен включиться. Как только бак пустой опять включается наполнящий насос (а-ля "пинг-понг") Задача написать логику реализующую это взаимодействие, через uniset-датчики.

Рассчитан на тех, кто знаком с uniset

Зависимости:

  • libUniSet2
  • libUniSet2Extensions
  • libUniSet2GO
  • uniset2-codegen-go

Компиляция

make

Запуск

  1. Создать репозиторий
 cd Services/Administrator; ./create
  1. Запустить SM
 cd Services/SM; ./start_fg.sh
  1. Запускаем
 start_fg.sh

Краткое описание реализации

Реализация использует "стандартный" для uniset-систем подход. Для каждого объекта создаётся специальный xml-файл с описанием входов, выходов и параметров. По этому файлу при помощи утилиты uniset2-codegen-go генерируется sk-файл (skeleton) содержащий всё необходимое для реализации логики (списки входов и выходов, in/out переменные содержащие текущее значение датчиков, функцию инициализации привязок к датчиком из конфигурационного файла). А дальше уже реализуются функции обработки событий по изменению датчиков и таймеров. В общем случае объекты реализуют логику в отдельной go-рутине, которая в цикле делает

  • обновление состояния входов
  • выполнение шага алгоритма
  • обработка таймеров (если есть)
  • обновление состояния выходов

Каждый объект который хочет получать уведомления об изменении датчиков, должен реализовать интерфейс UObject.

В данном примере реализованы два "класса" Pump и Imitator. Пример xml-файла описывающего imitator

<?xml version="1.0" encoding="utf-8"?>
<!--
	name 		- название класса

	type
	====
		in 	- входные регистры (только для чтения)
		out	- выходные регистры (запись)
-->
<Imitator>
  <settings>
	<set name="class-name" val="Imitator"/>
  </settings>
  <variables>
	   <item name="step" type="long" default="5"/>
	   <item name="min" type="long" default="0"/>
	   <item name="max" type="long" default="100"/>
  </variables>
  <smap>
	<item name="level_s" iotype="AI" vartype="out" comment="уровень в цистерне"/>
	<item name="cmdLoad_c" iotype="DO" vartype="in" omment="наполнять"/>
	<item name="cmdUnLoad_c" iotype="DO" vartype="in" omment="опустошать"/>
  </smap>

  <msgmap>
  </msgmap>
</Imitator>

На основе него генерируется файл imitator_sk.go

// DO NOT EDIT THIS FILE. IT IS AUTOGENERATED FILE.
// ALL YOUR CHANGES WILL BE LOST.
//
// НЕ РЕДАКТИРУЙТЕ ЭТОТ ФАЙЛ. ЭТОТ ФАЙЛ СОЗДАН АВТОМАТИЧЕСКИ.
// ВСЕ ВАШИ ИЗМЕНЕНИЯ БУДУТ ПОТЕРЯНЫ

package main

import (
	"fmt"
	"time"
	"uniset"
)

// ----------------------------------------------------------------------------------
type Imitator_SK struct {

	// ID
	level_s     uniset.ObjectID
	cmdLoad_c   uniset.ObjectID
	cmdUnLoad_c uniset.ObjectID

	// i/o
	out_level_s    int64
	in_cmdLoad_c   int64
	in_cmdUnLoad_c int64

	// variables
	step int64 /*!<  */
	min  int64 /*!<  */
	max  int64 /*!<  */

	ins  []*uniset.Int64Value // список входов
	outs []*uniset.Int64Value // список выходов

	myname     string
	id         uniset.ObjectID
	sleep_msec time.Duration
}

// ----------------------------------------------------------------------------------
func Init_Imitator(sk *Imitator, name string, section string) {

	sk.myname = name

	cfg, err := uniset.GetConfigParamsByName(name, section)
	if err != nil {
		panic(fmt.Sprintf("(Init_Imitator): error: %s", err))
	}

	sk.id = uniset.InitObjectID(cfg, "", name)

	sk.sleep_msec = time.Duration(200 * time.Millisecond)
	sk.step = uniset.InitInt64(cfg, "step", "5")
	sk.min = uniset.InitInt64(cfg, "min", "0")
	sk.max = uniset.InitInt64(cfg, "max", "100")

	sk.level_s = uniset.InitSensorID(cfg, "level_s", "")
	sk.cmdLoad_c = uniset.InitSensorID(cfg, "cmdLoad_c", "")
	sk.cmdUnLoad_c = uniset.InitSensorID(cfg, "cmdUnLoad_c", "")

	if sk.level_s == uniset.DefaultObjectID {
		panic(fmt.Sprintf("%s(Init_Imitator): Unknown ID for level_s\n", sk.myname))
	}
	if sk.cmdLoad_c == uniset.DefaultObjectID {
		panic(fmt.Sprintf("%s(Init_Imitator): Unknown ID for cmdLoad_c\n", sk.myname))
	}
	if sk.cmdUnLoad_c == uniset.DefaultObjectID {
		panic(fmt.Sprintf("%s(Init_Imitator): Unknown ID for cmdUnLoad_c\n", sk.myname))
	}

	sk.ins = []*uniset.Int64Value{
		uniset.NewInt64Value(&sk.cmdLoad_c, &sk.in_cmdLoad_c),
		uniset.NewInt64Value(&sk.cmdUnLoad_c, &sk.in_cmdUnLoad_c),
	}

	sk.outs = []*uniset.Int64Value{
		uniset.NewInt64Value(&sk.level_s, &sk.out_level_s),
	}

}

// ----------------------------------------------------------------------------------