Форум » » Фигею с 3 серии. » Ответить

Фигею с 3 серии.

Вячеслав: Отладишь все на подручной 2 серии. На проект выдают 3-ю и начинается.... Имеем модуль simpl+ cо строковым параметром name$ Имеем сериал выход с этого модуля OUT$ Допустим параметр заполняем Витрина_1 Пишем конструкцию Makestring(OUT$,"%s потеря DVI сигнала",name$); В дебагере для OUT$ получаем: Параметр name$ закодирован в Win-1251 далее слово потеря закодирован в UTF-16 далее слово DVI опять в ASCII далее слово сигнала опять в UTF-16 Попытка конвертнуть русские фразы UTF16ToASCII("потеря") и UTF16ToASCII("сигнала"): Makestring(OUT$,"%s %s DVI %s",name$,UTF16ToASCII("потеря"),UTF16ToASCII("сигнала")); В функцию UTF16ToASCII() уходит не пойми что, но точно не UTF-16. Никакие телодвижения с директивами кодировки параметра UTF/ASCII и в теле модуля #ENCODING_ASCII #ENCODING_UTF16 в любых сочетаниях на ситуацию никак не влияют. Пробовал и компиляцию только для 3 серии оставлять, тоже без результата. Короче слов нет, одни эмоции.

Ответов - 16

Вячеслав: Еще не совсем понятна фраза: An encoding directive is used to indicate the default encoding of strings if the encoding is not specified by an encoding keyword. Что за ключевое слово имелось ввиду?

Игорь K.: Это ещё что..... Наберите в командной строке любого процессора 3-серии или DM коммутатора >dopephish Keyword - параметр, задающий режим работы.

eoulianov: Добрый вечер! Попробую написать доку, заодно сам доразберусь что не потрогал) Гид по кодировкам в современном SIMPL/S+ на 3-Series Чуть-чуть теории о кодировках и их хранении Windows-1251. Исторически примерно у всех (даже у китайцев) были 1-байтовые национальные кодировки, и сейчас у нас используется Windows-1251 как «Язык системы» (она выбирается в Control Panel – Region and Language – Administrative – Language for Non-Unicode programs (system locale) и называется там Russian(Russia)). В этой кодировке печатные символы имеют коды от 32 (0x20) до 255 (0xFF) и хранят эти символы традиционно по одному байту на символ. Для примера, символ Ы в ней имеет код 219 (0xDB). Кодировок полно, даже с кириллицей штук 5 вспомню, поэтому так вот имея строку и не зная её кодировки не сразу догадаешься что в неё написано. Unicode. Когда всех это поддостало, сделали Unicode, «всеобщую» кодировку где для каждого мыслимого символа есть по коду и много чего ещё. Сейчас в Unicode 9.0 использовано 271792 кода из заложенных в ней 1114112, и символ Ы в ней имеет код 1067 (0x042B). Выходило, что для хранения этих символов требовалось по 4 байта, и жадность человеческая привела к нескольким способам хранения, из которых сейчас все привыкли к UTF-8, довольно изощрённому, с переменным количеством байт для разных символов. Crestron традиционно не угадал тренд и выбрал UTF-16LE – вариант где каждый символ занимает по 2 байта, причём сначала хранится (или передаётся при потоковой передаче) старший байт. Что случается со строками в SIMPL/SIMPL+ Таки-да, ВНУТРИ SIMPL и SIMPL+ в 3-Series строки действительно состоят из 16-битных символов. Функция LEN() и String Length (SLEN) выдают именно количество символов в строке (а не её размер в байтах, например). Действительно, каждый символ может иметь код в диапазоне 0..65535, и в SIMPL+ можно его узнать с помощью функции – правильно: BYTE(), ну не зайки ли?) С младшими 8-ю битами (low byte) всё осталось как было в 2-Series, теперь расскажу что со старшими: В SIMPL строки введённые в параметры НЕ конвертируются, каждый символ там (после раскрытия всяких макроподстановок) точнёхонько попадает кодом в младший байт, кроме конструкции \u. В SIMPL можно получить символы с кодами >255 двумя способами: написав код в параметре в форме \u (например, \u042B будет Ы в Unicode) и получив строку c такими кодами из SIMPL+. В SIMPL можно передать символы с кодами >255 только в модуль SIMPL+. Никакие символы в SIMPL не работают со СТАРШИМИ байтами кода символа, они не передаются в потоках (по rs232 или через TCP/IP клиент), не проходят сквозь Intersystem Communications и CrossPoints, нет символов SIMPL их анализирующих в духе Serial to Analog, даже панели Crestron их не получат. Если вам требуется передать строку 16-битных символов между модулями SIMPL+, то это нужно делать явно, связав их одним сигналом. В отличие от SIMPL, в S+ константные строки в 3-Series преобразуются в Unicode. Сам файл USP считается написанным в кодировке «Языка системы» (обычно это Windows-1251), и S="Ы"; породит строку из одного символа с кодом 0x042B. Там так же можно использовать \u042В – получится то же самое. А вот чтобы сделать надпись с Ы в SIMPL+ 3-Series для старой панели (куда нужно передать строку в Windows-1251) придётся задать явно \xDB, или воспользоваться конвертором UTF16->WIN1251 (это как раз та разница, на которую попал автор поста!). В SIMPL+ ещё можно получить символы с кодами >255 из SIMPL или из параметров. Но я не знаю способа «сделать» символ по коду, CHR() делает символа только в 0..255, и никакой арифметики с ними нет – если вдруг знаете, поделитесь, битте) Представление строк в 3-Series: три большие разницы В 3-Series SIMPL Debugger показывает строки весьма замысловатым образом: от каждого символа берётся сначала старший байт (если он не 0), затем младший байт, потом то же самое со следующим символом и всё это вместе склеивается в колбасу, которую Debugger показывает в соответствии с Display Format. По этому виду можно довольно смутно догадываться какая там была строка, например показанное как \xDB\x04\x2B может быть строкой из трёх символов \u00DB\u0004\u002B, а может быть строкой из двух символов \u00DB\u042B или \uDB04\u002B – не угадаешь. TRACE() и PRINT() по шаблону %s в SIMPL+ символы с кодами 1..255 отображают по языку системы, т.е. в Windows-1251, код 0 обрывает строку, а символы с кодами >255 отображаются знаком вопроса, тоже не очень понятно. В общем, чтобы более-менее внятно выяснить что там сейчас в строке в S+ нужно конструкцию типа for( i=1 to len(s) ) makestring( desc, "%s\\x%X", desc, byte(s, i) ); и потом это гнать в trace(). Про конвертирование Параметры и строки в SIMPL и SIMPL+ имеют что-то вроде атрибута ASCII/UTF16, и в обеих средах есть прорва функционала, оперирующего с ним и конвертирующего сами строки. Это всё лажа к нам не имеющая отношения, их ASCII это Windows-1252, совсем без кириллицы. Пока не вызываются их конвертирующие функции этот атрибут ни на что не влияет. Варианты конверторов В общем смысле задача конвертирования состоит в превращении входного потока в выходной с какими-то условиями: • В какой кодировке идёт входящий поток (или строка). Это может быть Windows-1251, OEM(DOS) CP-866, MAC-Cyrillic, ISO 8859-5, IBM EBCDIC Cyrillic или Unicode. • Если Unicode, то важно как коды размещены в строке – с использованием старшего байта символа (как вышло у автора поста) или в только в младших байтах. Если в младших – то каким образом размещено в потоке – в UTF-8, UTF-16GE или UTF-16LE • То же на выход: скорее всего нужно делать строку только в младшие байты, нужно понять в какую кодировку, если Unicode – то в каком порядке. Или если вдруг всё это нужно показывать в SmartGraphics, куда текст вставляется в тело HTML, то там нужно делать подстановки в HTML character entity references, скажем Ы представляется как Ы или Ы Что было в 2-Series С 2-Series разговор короткий: совершенно везде внутри контроллера строки только с 1-байтовыми символами, никаких преобразований в/из Unicode нет и сам контроллер совершенно не догадывается в какой именно кодировке вы писали вашу программу, от этого никак не зависит его работа. Кириллица станет видна вам уже снаружи - в SIMPL Debugger, если system locale русская; на «старых» панелях – если в диалоге выбора шрифта для этого объекта с Indirect Text выбрать в Script значение Cyrillic (и какой дебил догадался переименовать?); на панели со Smart Graphics – если вы преобразовали кириллицу в HTML character entity references. SIMPL+ в 2-Series ничего не конвертирует в константных строках – как оно есть в файле USP, так и окажется в ELF. UPD: ограничения по длинам в 3-й серии и как передать длинный текст с кириллицей в SmartGraphics В 3-й серии в SIMPL+ можно делать строки до 65534 символов, однако наружу в SIMPL выйдет только 1024 из них, похоже это ограничение длины строки в SIMPL. Если этот выход НАПРЯМУЮ передать в SIMPL+ или на панель SmartGraphics (хоть бы и Crestron App), то строка придёт целиком (до 1024 символов), а если на пути было что угодно, хоть Serial Buffer то она скорее всего будет урезана до 255 символов и старшие байты символов будут обнулены. Есть ещё ограничение длины Indirect Text в SmartGraphics - 1017 символов. Неважно, указали вы join явно как Indirect/Append/Prepend Text Serial Join или уже в строке как CIP tag, строки более 1017 символов будут проигнорированы. Если в объекте нет Append Text Serial Join или вы используете форматирование со вставками через CIP tegs, всё-таки ещё есть способ сделать "длинную" строку: если перед пересылаемым текстом добавить \xFE\x02, то он не заменит предыдущую строку, а приклеится к ней, как поступает Append Text Serial Join - так можно передавать длинную строку порциями, я не обнаружил очевидного ограничения набираемого таким образом текста. Про другие префиксы, вызывающие стирание проекта или прошивки и MAC-адреса, а так же дым и искры на устройствах со SmartGraphics (как TSW x50, x52, x60 так и на iOS) напишу в следующий раз. UPD2: nonvolatile string Оказалось, что в nonvolatile string после перезагрузки все символы с кодом больше 255 превращаются в тыкву в "?", поэтому если что-то нужно вспомнить - по любому нужно перепаковывать в 1-байтовые строки.


Игорь K.: Хороший почин. Очень интересно. Предлагаю заинтересованным включиться в проект.

Вячеслав: В дебагере строка выходит вполне "читаемая". Понятно посмотрев пару первых букв в таблицах Win-1251 и UTF16 Т.е. никаких сомнений в смысле какие символы представляют 1 букву нет. Русские символы из параметра попадают в выходную строку однобайтными Win-1251. Потом винигрет из ASCII для латинских символов и UTF по 2 байта для каждого из русских (\x04\x..) Дабы привести всю строку к одной кодировке, первым делом я попробовал конвертировать параметр из Win-1251 в UTF. И это вполне сработало. В этот момент я увидел что латинские то символы SIMPL+ оставил в ASCII кодировке. Т.е. надо конвертировать и их тоже. Мало того что это получается какое то нагромождение функций для строк с частым чередованием латинских и русских слов, что лишь потеря читаемости кода. Главный попадос, в том что преобразовав этот винигрет к 2-x байтному представлению UTF получается выходная строка длинной в километр. И ясен пень он легко начинает упираться в ограничение 255 символов для строковых выходов модуля. Тут либо на TCP переходить - что потянет переделку всех промежуточных модулей, либо попытаться все таки привести все символы к однобайтному формату Win-1251. Что я попытался сделать загнав текст в функцию UTF16ToASCII("сигнала"). Да не тут то было. Данный текст выходящий наружу модуля UTF в случае его явного использования, в конвертер UTF16ToASCII ушел как то иначе. Времени понять как, не хватило. Но на выходе получил какую то кракозябру. Надеюсь разберусь со второго подхода. Есть конечно варианты, все русские слова в параметры загнать (благо их не много) - но это как Вы понимаете не наш метод. Или еще вариант попробовать их как сериал инпуты подать - метод не шибко лучше предыдущего варианта. До кучи там еще время подставляется (для логирования) и тэги цвета а потом это в SG xpanel в HTML character потребуется конвертировать где опять ограничение в 255 при этом на каждый русский символ придется потратить 7 символов. Итоговая формула: Lat*lenLat+Cyr*lenCyr*7<=255 Данная формула жестоко ограничивает использование кириллицы в 3-серии с выводом на панель SG Желаемое скромное (23-01-2017 14:00 Витрина_1 потеря сигнала DVI): "<FONT color=\x22#ff0000\x22>"+"23-01-2017 14:00 Витрина_1 потеря сигнала DVI"+"</FONT>\x0D" получаем аж 55+14*7=153 символа Функцию конвертера в Win-1251 придется внутрь модуля вставлять и наружу выпускать исключительно в Win-1251

Вячеслав: Продолжение истории: 3 серия иначе обрабатывает строки с юникодом (как бы понимая что собственно передается по крайней мере внутри + модуля) Т.е. имеем кириллический символ юникода \x04\x3F ("п") Начнем с функции str$=RemoveByLength(NUMBYTES, SOURCESTRING); //где SOURCESTRING="\x04\x3F" Во второй серии чтоб достать такой символ нужно было вырезать 2 символа \x04 и \x3F Т.е. длина строки была =2. str$=RemoveByLength(2, SOURCESTRING); В 3 серии символ \x04\x3F воспринимается как одна буква длиной 2 байта и надо писать уже так: str$=RemoveByLength(1, SOURCESTRING); Далее интереснее. Как я уже говорил программа миксует символы строки представляя русские буквы в 2-х байтном формате юникода, а латинские в классических 1 байтных ASCII Скажем вы передали строку "п " т.е. после буквы "п" есть еще один пробел: "\x04\x3F\x20" Теперь угадайте длину такой строки. правильный ответ =2 )) (функцией Len() я конечно не сравнивал но по логике так получается) Т.е. первый раз str$=RemoveByLength(1, SOURCESTRING); str$="\x04\x3F\"; во второй раз str$=RemoveByLength(1, SOURCESTRING); str$="\x20"; Таким образом во 2 серии для вычисления кода символа (часть алгоритма функции UTF16ToASCII()) приходилось обрабатывать "\x04\x3F\" как 2 символа: str$=RemoveByLength(2, SOURCESTRING); value=byte(str$,1)*256+byte(str$,2); //=1087 В 3-серии эта часть кода превращается в обработку 1 символа: str$=RemoveByLength(1, SOURCESTRING); value=byte(str$,1); //=1087 Т.е. функция byte в случае юникода вынимает из строки сразу 2 байта, благо её размерность типа integer это позволяет. Остается надеятся что внутренний формат хранения/интерпритации данных позволяет понять что в наборе "\x04\x3F\x20" всего 2 символа и именно "\x04\x3F" и "\x20" и это всегда будет правильно понято процессором. А вдруг это просто hex некоторого API и тогда эта "логика" может подложить свинью. Вот такие нюансы получаются.

DmitriiP: это только начало долгого и и безутешного "веселья" делал на S# парсер tcp для pioneer.... 1 или 2 байта tcpClient.IncomingDataBuffer S# коверкал в каждом ответе из-за неразберих с UTF8/UTF16 (два сивола UTF8 могли чудом превратится в один UTF16) приходилось вылавливать и сравнивать побайтово. пока новый велосипед не покатился. ибо встроенные Encoding.UTF8.GetString(inBytes, 0, inBytes.Length); тупо переставали работать/выдавали полную хрень.

teromang: DmitriiP пишет: работать/выдавали полную хрень. И правильно делал у вас кодировка UTF16 На самом деле с недавних обновлений заработал ANSI-UTF16 встроенный модуль в Crestron. На вход строку-на выходе правильная строка в Utf-16, и добавляем маркер на UTF-16

teromang: DmitriiP пишет: работать/выдавали полную хрень. И правильно делал у вас кодировка UTF16 На самом деле с недавних обновлений заработал ANSI-UTF16 встроенный модуль в Crestron. На вход строку-на выходе правильная строка в Utf-16, и добавляем маркер на UTF-16

VIM: teromang "Convert to UTF-16" или "Mark as ASCII/UTF-16"?

teromang: click here

DmitriiP: teromang пишет: И правильно делал у вас кодировка UTF16 не путайте Simpl# с Simpl (на вашей картинке) или c Simpl+ ;)

teromang: Я и не путаю По умолчанию поток обрабатывает в кодировке ANSI, или UTF-16 Для указания типа кодирования символов используется жосткое указание кодировки: "static Encoding buf= Encoding.UTF8;"

DmitriiP: а чем коооординально отличается Encoding.UTF8.GetString(inBytes, 0, inBytes.Length); от static Encoding buf= Encoding.UTF8; buf.GetString(inBytes, 0, inBytes.Length); ???

teromang: Неявным преобразованием типов

DmitriiP: если появится под рукой опять Pioneer, обязательно проверю теорию со static Encoding;) по поводу "Неявным преобразованием типов" static Encoding buf = System.Text.Encoding.UTF8; будет более явным?



полная версия страницы