OberonCore

Библиотека  Wiki  Форум  BlackBox  Компоненты  Проекты
Текущее время: Понедельник, 11 Декабрь, 2017 16:08

Часовой пояс: UTC + 3 часа




Начать новую тему Ответить на тему  [ Сообщений: 19 ] 
Автор Сообщение
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 14:22 
Аватара пользователя

Зарегистрирован: Суббота, 26 Ноябрь, 2005 02:12
Сообщения: 430
Откуда: Егорьевск
Код:
MODULE M;

    IMPORT SYSTEM;

    TYPE
        Msg* = ABSTRACT RECORD END;
        MsgA* = RECORD (Msg)
            a-, b-: INTEGER
        END;
        MsgB* = RECORD (Msg)
            x-, y-, z-: SHORTREAL
        END;

        MsgHandler* = POINTER TO ABSTRACT RECORD
        END;

    PROCEDURE (h: MsgHandler) Handle- (IN msg: Msg), NEW, ABSTRACT;

    PROCEDURE DataToMsg (type: INTEGER; IN a: ARRAY OF BYTE; len: INTEGER; VAR msg: ANYREC);
    BEGIN
        SetType(msg, type); (* как это сделать? *)
        SYSTEM.MOVE( SYSTEM.ADR(a), SYSTEM.ADR(msg), len )
    END DataToMsg;

    PROCEDURE DataReceived* (id: BYTE; IN a: ARRAY OF BYTE; len: INTEGER; h: MsgHandler);
        TYPE
            MsgX = RECORD (Msg) END;
        VAR ok: BOOLEAN; type: INTEGER; msg: MsgX;
    BEGIN
        ok := FALSE;
        CASE id OF 10H:
            IF len = SIZE(MsgA) THEN
                ok := TRUE;
                type := GetType(MsgA) (* как это сделать? *)
            END
        | 11H:
            IF len = SIZE(MsgB) THEN
                ok := TRUE;
                type := GetType(MsgB) (* как это сделать? *)
            END
        ELSE
        END;

        IF ok THEN
            DataToMsg(type, a, len, msg);
            h.Handle(msg)
        END
    END DataReceived;

END M.

MODULE M1;

    IMPORT M, StdLog;

    TYPE
        MsgHandler = POINTER TO RECORD (M.MsgHandler) END;

    PROCEDURE (h: MsgHandler) Handler (IN msg: Msg);
    BEGIN
        WITH msg: M.MsgA DO
            StdLog.String("A:"); StdLog.Int(msg.a); StdLog.Int(msg.b); StdLog.Ln
        | msg: M.MsgB DO
            StdLog.String("B:"); StdLog.Real(msg.x); StdLog.Real(msg.y); StdLog.Real(msg.z); StdLog.Ln
        END
    END Handler;

    PROCEDURE Test*;
        VAR a: ARRAY 8 OF BYTE;
            h: MsgHandler;
    BEGIN
        a[0] := 1; a[1] := 1; a[2] := 0; a[3] := 0;
        a[4] := 2; a[5] := 1; a[6] := 0; a[7] := 0;
        NEW(h);
        M.DataReceived(10H, a, 8, h)
    END Test;

END M1.


Желательно с помощью Kernel.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 14:48 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2915
Откуда: г. Ярославль
Зачем такое нужно?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 14:59 
Аватара пользователя

Зарегистрирован: Суббота, 26 Ноябрь, 2005 02:12
Сообщения: 430
Откуда: Егорьевск
Хочу реализовать обмен "сообщениями" между 2-мя компьютерами. Обрабатывать сообщения удобно таким способом:

Код:
PROCEDURE (h: Handler) MsgReceived (IN msg: Msg);
BEGIN
    WITH msg: MsgA DO
        ...
    | msg: MsgB DO
        ...
    ...
    END
END MsgReceived;


а не таким:

Код:
PROCEDURE MsgReceived (id: INTEGER; IN data: ARRAY OF BYTE; len: INTEGER);
BEGIN
    CASE id OF
    00H:
        ...
    | 01H:
        ...
    ...
    END
END MsgReceived;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 16:15 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2431
Откуда: Россия, Ярославль
Обмен сообщениями между компами я организовал через джаббер, с использованием базового сообщения абстрактного типа. код примерно такой, постараюсь удалить весь джабер и оставить суть:
Код:
IMPORT SYSTEM, Kernel, Meta

   TYPE
MsgPtr* = POINTER TO Message;
Message* = ABSTRACT RECORD (AbfBus.Message) END;
Alien* = POINTER TO RECORD (Message)
         data* : Items.Item;
      END;
   Converter* = POINTER TO ABSTRACT RECORD END;
   PROCEDURE (c : Converter) ItemToMsg*(item : Items.Item; VAR msg : MsgPtr; res : INTEGER), NEW, ABSTRACT;
   PROCEDURE (c : Converter) MsgToItem*(VAR msg : Message; OUT item : Items.Item), NEW, ABSTRACT;
   StdConv = POINTER TO RECORD(Bus.Converter) END;
   
PROCEDURE LookupItem (VAR r: ANYREC; OUT i: Meta.Item);
   VAR type: Kernel.Type; mod: Kernel.Module; attr: Kernel.ItemAttr;
   BEGIN   (* create a meta item for a global variable passed as VAR parameter *)
      attr.obj := Meta.varObj;
      attr.typ := Meta.recTyp;
      attr.vis := Meta.exported;
      attr.adr := SYSTEM.ADR(r);
      attr.mod := NIL;
      attr.desc := SYSTEM.VAL(Kernel.Type, SYSTEM.TYP(r));
      attr.ptr := NIL;
      attr.ext := NIL;
      attr.mod := NIL;
      Meta.GetThisItem(attr, i)
   END LookupItem;   

PROCEDURE (c : StdConv) ItemToMsg(item : Items.Item; VAR msg : Bus.MsgPtr; res : INTEGER);
   VAR name, summ : ARRAY 127 OF CHAR; this : Meta.Item; x : ANYPTR; hash : SternMd5.Hash; i : INTEGER; fnum, fp : ARRAY 127 OF CHAR; al : Bus.Alien; sp : Bus.Special;
BEGIN
      name:=item.GetParam(Const.type)$;
      Meta.LookupPath(name, this);
      IF this.Valid() THEN
         x:=this.New();
         ASSERT(x#NIL);
         msg:=x(Bus.MsgPtr);
         LookupItem(msg, this);
         i:=0; Inc(fnum);
      ELSE
         NEW(al); al.data:=item;
         msg:=al;
      END;
   END ItemToMsg;



Вложения:
code.zip [6.38 КБ]
Скачиваний: 180
Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 16:21 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2431
Откуда: Россия, Ярославль
В общем, суть в том, что мы наследуем тип сообщения от абстрактного типа, реализовываем нужный нам тип сообщения, затем передаём его произвольным образом на другой комп, при этом передаём тип сообщения(я передаю название типа например "MyModule.MyMsg"), если на другом компе имеется модуль с тем же самым типом сообщения, создаём новый экземпляр нужного типа(x:=this.New()) и сразу подключаем к нему Meta-элемент(LookupItem) и заполняем его из полученных данных.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 16:24 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2431
Откуда: Россия, Ярославль
Тип сообщения наследуется от абстрактного типа межможульной шины сообщений http://forum.oberoncore.ru/viewtopic.php?f=47&t=269&start=0&hilit=Advanced+BlackBox+Framework - AbfBus.Message с целью дальнейшего распространения полученных из сети сообщений по шине, не отходя от кассы, так сказать


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Суббота, 11 Сентябрь, 2010 18:13 
Аватара пользователя

Зарегистрирован: Суббота, 26 Ноябрь, 2005 02:12
Сообщения: 430
Откуда: Егорьевск
В итоге сделал так:

Код:
MODULE TmpM3;

   IMPORT SYSTEM, Kernel;

   TYPE
      Msg* = POINTER TO ABSTRACT RECORD END;
      MsgHandler* = POINTER TO ABSTRACT RECORD END;
      Table* = POINTER TO ABSTRACT RECORD END;

   PROCEDURE (h: MsgHandler) Handle- (msg: Msg), NEW, ABSTRACT;

   PROCEDURE (t: Table) Lookup- (id: BYTE; OUT len: BYTE; OUT type: INTEGER; OUT ok: BOOLEAN), NEW, ABSTRACT;

   PROCEDURE DataReceived* (id: BYTE; IN a: ARRAY OF BYTE; len: BYTE; h: MsgHandler; table: Table);
      VAR type: INTEGER; len1: BYTE; ok: BOOLEAN;
         msg: Msg;
   BEGIN
      table.Lookup(id, len1, type, ok);
      IF ok & (len = len1) THEN
         Kernel.NewObj( msg, SYSTEM.VAL( Kernel.Type, type) );
         SYSTEM.MOVE( SYSTEM.ADR(a), SYSTEM.ADR(msg^), len );
         ASSERT(msg # NIL);
         h.Handle(msg)
      END
   END DataReceived;

END TmpM3.


Код:
MODULE TmpM4;

   (* этот модуль должен создаваться автоматически *)

   IMPORT SYSTEM, TmpM3;

   TYPE
      MsgA* = POINTER TO MsgADesc;
      MsgADesc* = RECORD (TmpM3.Msg)
         a-, b-: INTEGER
      END;
      MsgB* = POINTER TO MsgBDesc;
      MsgBDesc* = RECORD (TmpM3.Msg)
         x-, y-, z-: SHORTREAL
      END;

      Table = POINTER TO RECORD (TmpM3.Table) END;

   VAR
      table-: Table;

   PROCEDURE (t: Table) Lookup (id: BYTE; OUT len: BYTE; OUT type: INTEGER; OUT ok: BOOLEAN);
   BEGIN
      CASE id OF 10H:
         len := SIZE(MsgADesc); type := SYSTEM.TYP(MsgADesc);
         ok := TRUE
      | 11H:
         len := SIZE(MsgBDesc); type := SYSTEM.TYP(MsgBDesc);
         ok := TRUE
      ELSE
         ok := FALSE
      END
   END Lookup;

BEGIN
   NEW(table)
END TmpM4.


Код:
MODULE TmpM5;

   IMPORT TmpM3, TmpM4, StdLog;

   TYPE
      MsgHandler = POINTER TO RECORD (TmpM3.MsgHandler) END;

   PROCEDURE (h: MsgHandler) Handle (msg: TmpM3.Msg);
   BEGIN
      WITH msg: TmpM4.MsgA DO
         StdLog.String("A:"); StdLog.Int(msg.a); StdLog.Int(msg.b); StdLog.Ln
      | msg: TmpM4.MsgB DO
         StdLog.String("B:");
            StdLog.Real(msg.x); StdLog.Real(msg.y); StdLog.Real(msg.z);
            StdLog.Ln
      END
   END Handle;

   PROCEDURE Test*;
      VAR h: MsgHandler;
         a: ARRAY 12 OF BYTE;
   BEGIN
      a[0] := 1; a[1] := 1; a[2] := 0; a[3] := 0;
      a[4] := 2; a[5] := 1; a[6] := 0; a[7] := 0;
      NEW(h);
      TmpM3.DataReceived(10H, a, 8, h, TmpM4.table)
   END Test;

END TmpM5.

!(Q)TmpM5.Test


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Воскресенье, 12 Сентябрь, 2010 21:41 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 8882
Откуда: Россия, Орёл
Ваша сетевая библиотеке в Блэкбоксе получателе должна вызывать какой-то обработчик, передавая ему запись нужного типа. Чтобы привести байтовый буфер к нужному типу, можете использовать функцию SYSTEM.THISRECORD. Она недокументирована, пример можно увидеть в Meta:

Код:
   PROCEDURE (VAR rec: Item) CallWith* (proc: PROCEDURE(VAR rec, par: ANYREC); VAR par: ANYREC), NEW;
   BEGIN
      ASSERT(rec.ext = NIL, 31);
      ASSERT(rec.ptr # NIL, 20);
      ASSERT(rec.typ = recTyp, 21);
      ASSERT(rec.obj = varObj, 22);
      ASSERT((rec.mod = NIL) OR (rec.mod.refcnt >= 0), 23);
      proc(SYSTEM.THISRECORD(rec.adr, SYSTEM.VAL(INTEGER, rec.desc)), par)
   END CallWith;


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 13 Сентябрь, 2010 11:29 
Аватара пользователя

Зарегистрирован: Суббота, 26 Ноябрь, 2005 02:12
Сообщения: 430
Откуда: Егорьевск
Спасибо! Как раз то, что нужно.

Код:
MODULE TmpM3;

   IMPORT SYSTEM;

   TYPE
      Msg* = ABSTRACT RECORD END;
      MsgHandler* = POINTER TO ABSTRACT RECORD END;
      Table* = POINTER TO ABSTRACT RECORD END;

   PROCEDURE (h: MsgHandler) Handle- (IN msg: Msg), NEW, ABSTRACT;

   PROCEDURE (t: Table) Lookup- (id: BYTE; OUT len: BYTE; OUT type: INTEGER; OUT ok: BOOLEAN), NEW, ABSTRACT;

   PROCEDURE DataReceived* (id: BYTE; IN a: ARRAY OF BYTE; len: BYTE; h: MsgHandler; table: Table);
      VAR type: INTEGER; len1: BYTE; ok: BOOLEAN;
   BEGIN
      table.Lookup(id, len1, type, ok);
      IF ok & (len = len1) THEN
         h.Handle( SYSTEM.THISRECORD( SYSTEM.ADR(a), type ) )
      END
   END DataReceived;

END TmpM3.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 13 Сентябрь, 2010 14:47 

Зарегистрирован: Вторник, 29 Август, 2006 12:32
Сообщения: 2431
Откуда: Россия, Ярославль
мегахак!!! а я то, огород городил...


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Пятница, 06 Январь, 2012 14:50 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2915
Откуда: г. Ярославль
Не нашёл лучшего места, чем тут, чтобы зафиксировать концептуальный примерчик. Задача: необходимо рассылать уведомления по шине (здесь считаем, что это статическая RECORD без полей), зная только имя типа уведомления в виде цепочки символов.


Код:
MODULE TestMeta;

(**
   project   = "TestMeta"
   organization   = ""
   contributors   = ""
   version   = "System/Rsrc/About"
   copyright   = "Kuzmitskiy Ivan Alexandrovich"
   license   = "Docu/BB-License"
   purpose   = "Лабораторный образец, демонстрирующий один из способов создания переменной, тип который задан цепочкой символов"
   changes   = "
   - 20120106, kia, автогенерация заголовка
"
   issues   = ""
**)

   IMPORT
      Log := StdLog, Meta;

   TYPE
      Message* = ABSTRACT RECORD END;
      PMessage* = POINTER TO Message;
      NotifyMsg* = RECORD (Message) END;
      NotifyMsg1* = RECORD (Message) END;
      NotifyMsg2* = RECORD (Message) END;

   PROCEDURE Handle (VAR msg: Message);
   BEGIN
      WITH msg: NotifyMsg DO
         Log.String('TestMeta, обработка NotifyMsg'); Log.Ln
      | msg: NotifyMsg1 DO
         Log.String('TestMeta, обработка NotifyMsg1'); Log.Ln
      | msg: NotifyMsg2 DO
         Log.String('TestMeta, обработка NotifyMsg2'); Log.Ln
      ELSE
      END
   END Handle;

   PROCEDURE Do* (s: ARRAY OF CHAR);
      VAR this: Meta.Item; x: ANYPTR; pn: PMessage; n: NotifyMsg;
   BEGIN
      Meta.LookupPath(s, this);
      IF this.Valid() THEN
         x := this.New(); ASSERT(x # NIL, 60);
         Handle(x(PMessage))
      ELSE
         Log.String('TestMeta: Тип не найден!'); Log.Ln;
      END;
   END Do;

END TestMeta.

^Q"TestMeta.Do('')"
^Q"TestMeta.Do('TestMeta.NotifyMsg')"
^Q"TestMeta.Do('TestMeta.NotifyMsg1')"
^Q"TestMeta.Do('TestMeta.NotifyMsg2')"


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 09 Январь, 2012 10:13 
Модератор
Аватара пользователя

Зарегистрирован: Понедельник, 14 Ноябрь, 2005 18:39
Сообщения: 8882
Откуда: Россия, Орёл
Хороший пример, но у него есть важный изъян: порождается динамический экземпляр.
Для прикладного программирования это можно стерпеть, но вообще, каждый раз, когда я такое вижу, мне обидно за то, что мы скатываемся к стилю Явы/Шарпов - плодить мусор там, где Оберон, с его полиморфизмом для записей на стеке, позволяет этого не делать...

В вашем случае, чтобы "не плодить", можно сделать модулёк, которая внутри решает эту проблему (подстановку пустого экземпляра записи по имени) через SYSTEM...
Самый простой способ - использовать THISREC.

Если без SYSTEM - то можно сделать такой модулёк, который хранит по одному экземпляру записей по их имени и отдаёт нужную.

Это как дополнение к Вашему примеру. В нагруженных приложениях это важно.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 09 Январь, 2012 14:53 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2915
Откуда: г. Ярославль
Я ещё не понял, как пользоваться SYSTEM.THISRECORD :(


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 09 Январь, 2012 15:03 
Аватара пользователя

Зарегистрирован: Вторник, 19 Сентябрь, 2006 21:54
Сообщения: 2284
Откуда: Россия, Санкт-Петербург
Илья Ермаков писал(а):
Самый простой способ - использовать THISREC.
Чего?
В документации не нашёл такого.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Понедельник, 09 Январь, 2012 15:07 
Модератор
Аватара пользователя

Зарегистрирован: Среда, 16 Ноябрь, 2005 00:53
Сообщения: 4468
Откуда: Россия, Орёл
В документации её и нету. Была выкопана в исходниках компилятора и затем обнаружена в коде модуля Meta.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Вторник, 10 Январь, 2012 18:59 
Аватара пользователя

Зарегистрирован: Пятница, 25 Сентябрь, 2009 13:10
Сообщения: 1158
Откуда: Tel-Aviv
Илья Ермаков писал(а):
Самый простой способ - использовать THISREC.

То есть использовать недокументированную функциональность?


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 11 Январь, 2012 12:53 

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 7724
Откуда: Троицк, Москва
Заразная какая болезнь.


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 11 Январь, 2012 13:35 

Зарегистрирован: Четверг, 17 Ноябрь, 2005 11:51
Сообщения: 2915
Откуда: г. Ярославль
Это не болезнь, а поиск средств для обмена сообщениями между экземплярами BlackBox. Всем известно, что экземпляры BlackBox функционируют в чужеродной, "не-оберон"-среде :), поэтому просто так сообщение не передашь!

Надо его, это сообщение, обязательно завернуть в полиэтиленовый пакет в целях инфекционной безопасности, да сургучом залить, а при получении распечатать :)


Вернуться к началу
 Профиль  
 
СообщениеДобавлено: Среда, 11 Январь, 2012 15:33 

Зарегистрирован: Пятница, 25 Ноябрь, 2005 12:02
Сообщения: 7724
Откуда: Троицк, Москва
Иван Кузьмицкий писал(а):
Это не болезнь, а поиск средств для обмена сообщениями между экземплярами BlackBox.
Ну, пусть.


Вернуться к началу
 Профиль  
 
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 19 ] 

Часовой пояс: UTC + 3 часа


Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Вся информация, размещаемая участниками на конференции (тексты сообщений, вложения и пр.) © 2005-2017, участники конференции «OberonCore», если специально не оговорено иное.
Администрация не несет ответственности за мнения, стиль и достоверность высказываний участников, равно как и за безопасность материалов, предоставляемых участниками во вложениях.
Без разрешения участников и ссылки на конференцию «OberonCore» любое воспроизведение и/или копирование высказываний полностью и/или по частям запрещено.
Powered by phpBB® Forum Software © phpBB Group
Русская поддержка phpBB