РЖДфон десять лет спустя

в 8:01, , рубрики: Блог компании Timeweb Cloud
Приветствую всех.

Сегодня поговорим об одном уже достаточно древнем и во многих областях уникальном девайсе — нашумевшем в своё время защищённом терминале сбора данных для РЖД. В ходе статьи проведём неофициальный обзор данного аппарата, сравним его с устройством того же класса, попробуем разобраться, какова была история и дальнейшая судьба данного проекта, и собрать в одном месте всю известную мне информацию по теме. Постараемся воздержаться от реплик типа «Аццтой!!!1» или «Вы ничего не понимаете, это же топ за свои деньги!» и быть максимально объективными.

РЖДфон десять лет спустя - 1

Как оно начиналось

Итак, в далёком две тысячи двенадцатом году на выставке «Инфотранс-2012» компанией R-Style был представлен защищённый мобильный терминал для нужд РЖД. Это был ещё не герой сегодняшний статьи, в нём отсутствовал лазерный сканер, а дизайн несколько отличался. Тем не менее, работал он на Android четвёртой версии, имел схожий дизайн и, судя по всему, аналогичную электронную начинку. Упоминание этого аппарата обнаружилось в посте некого sg79 в ЖЖ (не вижу смысла перезаливать фотографии сюда, тем более, что они не мои. На случай внезапного протухания ссылки я сохранил этот пост в Internet Archive). Увы, кроме не самых детальных фотографий устройства, а также его фото в морозильнике (где демонстрировалась его морозостойкость) больше ничего найти не вышло. Найти экземпляр в коллекцию и на обзор мне также не довелось.
UPD: в комментариях кинули ссылку на один весьма примечательный пост. Вот что это за аппарат!

Первый настоящий российский смартфон

Весной две тысячи тринадцатого (на следующий день после моего дня рождения, однако) товарищем KY05 была выпущена статья "Первый настоящий российский смартфон?". В ней коротко сообщалось о том, что в России планируется начать производство некого устройства на базе Android. Также была приложена фотография какой-то электроники, первоначально принятая пользователями за стоковую.
Коротенькая заметка закономерно вызвала ожесточённую дискуссию, впрочем, чего-то большего на тот момент никто особо не выяснил.

Инфотранс-2013

Своего рода мемом РЖДфон стал осенью две тысячи тринадцатого. Тогда Алексей AlexeyNadezhin Надёжин (хорошо известный здесь своими обзорами на светодиодные лампы и элементы питания) выложил в своём блоге пост о данном устройстве. Пост вызвал внушительный общественный резонанс, а фотографии из него изрядно «затуманили» поисковую выдачу. Материалы вызвали у аудитории крайне противоречивое мнение: кто-то заявлял, что это новая инновация, кто-то считал девайс банальным распилом средств. Позже были выложены и другие посты: Смартфон РЖД в работе, Смартфон от РЖД: расставляем точки над i. Был и небольшой обзор «чистой» прошивки.

Для кого предназначался РЖДфон?

Отдельно следует упомянуть то, кому вообще выдавались такие устройства. Его основными пользователями должны были стать различные работники депо, путейцы, составители поездов. Проводникам такие устройства не полагались.

Вообще, если говорить именно о проводниках, то разновидностей устройств для них было достаточно большое количество. В основном это были терминалы сбора данных Motorola/Honeywell или же «защищённые» Android-смартфоны с софтом РЖД. Вот пример такого устройства.

Обзор оборудования

С краткой историей ознакомились. Переходим к самому аппарату.

РЖДфон десять лет спустя - 2

FRMD101A поставляется в коробке из плотного белого картона без опознавательных знаков. На одной из граней приклеена этикетка с моделью и IMEI.

РЖДфон десять лет спустя - 3

А вот и сам аппарат. На передней части экран с приклеенной защитной плёнкой, датчик приближения, разговорный и основной динамики, микрофон, кнопки быстрого запуска (телефон, камера и диктофон), логотип РЖД. Фронтальной камерой девайс не оснащён. Справа от разговорного динамика светодиодный индикатор.

РЖДфон десять лет спустя - 4

На обратной стороне камера со вспышкой, крышка аккумулятора (фиксируется она винтом под плоскую отвёртку, который также неплохо откручивается отечественным пятаком образца 1997 года), контакты для док-станции (их распиновку можно будет увидеть чуть позднее).

РЖДфон десять лет спустя - 5

Сверху окошко лазерного сканера, заглушки, закрывающие разъёмы microUSB и 3,5 мм, а также свойственную скорее КПК, нежели смартфонам, кнопку RESET. Также видны ушки для ремешка.
Многие смеялись над тем, что заглушки прикручены суровым отечественным саморезом, проглядев, однако, что в надписи рядом со сканером есть опечатка. Впрочем, несмотря на столь кондовое крепление, заглушки не выглядят особо надёжными и при постоянном их открывании есть шанс, что они отвалятся или перестанут закрываться. Впрочем, возможно, что это всего лишь последствия восьми лет лежания…

Снизу же ничего интересного нет — только слот для контактных смарт-карт (абсолютно стандартных, типа ISO7816). Заглушка его очень неудобная и дубовая. Однако если карта будет вставлена туда при начале эксплуатации устройства и всегда будет находиться там, то это даже плюс (во всяком случае, к влагозащите точно). Но, повторяюсь, что это, возможно, всего лишь последствия долгих лет хранения, и изначально заглушки были куда лучше.

РЖДфон десять лет спустя - 6

Снимем крышку. Она имеет резиновую прокладку, призванную защищать внутренности устройства от попадания внутрь пыли и жидкости. Крышка прилегает весьма плотно, что не может не радовать.

РЖДфон десять лет спустя - 7

Аккумулятор имеет ёмкость 5000 мА*ч. Увы, за долгие годы лежания он изрядно подустал.

РЖДфон десять лет спустя - 8

Под аккумулятором находятся слоты для SIM и microSD, наклейка, аналогичная той, что была на коробке. Контакты подключения батареи подпружиненные, выглядят надёжно.

РЖДфон десять лет спустя - 9

Разберём аппарат. Ничего сложного в этом нет: вытаскиваем заглушки по периметру (аккуратно, а то рискуете потом обратно их не засунуть), откручиваем винты. Ещё четыре винта спрятаны под резиновой прокладкой под крышкой. Прокладка эта никак не приклеена, просто уложена в паз.
По центру плата встраиваемого USB-считывателя смарт-карт Athena. Чуть ниже виден край резервного аккумулятора. В самом низу контакты для док-станции.

РЖДфон десять лет спустя - 10

Осторожно отсоединяем шлейфик сенсора и вынимаем всю начинку.

РЖДфон десять лет спустя - 11

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

РЖДфон десять лет спустя - 12

А вот и весьма кондовая и увесистая док-станция. Видны некоторые огрехи и в целом топорное изготовление, но, в общем-то, в остальном — ничего так.

РЖДфон десять лет спустя - 13

Снизу у неё прикручен металлический уголок для крепления на стену. При необходимости его можно снять и поставить другой стороной, либо убрать вообще.
Прикручен он, кстати, не на саморезы, а на нормальные винты. В пластик корпуса вплавлены закладные гайки.

РЖДфон десять лет спустя - 14

С обратной стороны мало интересного, лишь разъём microUSB. Не самое привычное решение, подставки терминалов сбора данных обычно оснащены разъёмом miniUSB или даже полноразмерным USB-B.
В посте про использование этих устройств на практике слегка позабавила фотография с кучей этих терминалов в индивидуальных подставках и кучей воткнутых в удлинитель зарядников, отдалённо напоминающая фотоприколы про зарядку телефонов в армии. Судя по всему, многоместные подставки под пять терминалов сразу особого распространения не получили.

РЖДфон десять лет спустя - 15

Разберём док-станцию. Внутри ожидаемо пусто, лишь одна-единственная плата. На ней можно увидеть и распиновку.
Пайка хорошая: флюс отмыт, припаяно всё аккуратно, провода имеют разъёмы для подключения.

РЖДфон десять лет спустя - 16

А вот и всякая мелочёвка. Весьма удобный ремешок на шею (разумеется, в корпоративном дизайне), зарядка, гарнитура, кабель.
Зарядник выдаёт пять вольт и один ампер, а также обладает чрезмерной лёгкостью, всё как во времена бюджетных смартфонов. Кабель microUSB с очень длинным разъёмом: отвратительное решение, при потере кабеля придётся искать аналогичный или подкромсать обычный. Похожее решение встречал на дешёвом смартфоне DEXP. Гарнитура самая обычная, такие в лучшие времена клали в комплекте к любому смартфону. Есть небольшое подозрение, что она тут не «родная».

РЖДфон десять лет спустя - 17

Ну а вот так девайс лежит в док-станции.

Первое включение

Соберём аппарат обратно и рассмотрим его с программной части. Мне достался экземпляр с заводской прошивкой, без установленного софта РЖД. Вставляем аккумулятор, закручиваем винт крепления крышки и жмём кнопку включения.

РЖДфон десять лет спустя - 18

Аппарат запускается, приветствуя нас логотипом Android Jelly Bean.

РЖДфон десять лет спустя - 19

Дальше загорается надпись «Welcome», в духе бюджетных китайских ведроидов.

РЖДфон десять лет спустя - 20

И, наконец, система загружается.

Как он в использовании?

Увы, время этой версии Android давно прошло. Нынешние версии популярных приложений разжирели до невероятных даже по тем меркам размеров и на такой аппарат попросту не встанут. Да и просто для просмотра интернета экземпляр не лучший выбор, немало сайтов открываются очень так себе, к тому же менять масштаб страницы в браузере, ориентированном на управление пальцами, на устройстве, которое даже мультитач не поддерживает, откровенно неудобно. Сейчас такой аппарат подойдёт больше для коллекции, чем для реального применения. Резистивным сенсором на Android пользоваться несколько непривычно, первое время я даже пробовал управлять им с помощью стилуса от КПК.

Впрочем, это я так. На деле же вряд ли кто-то будет смотреть мемасики на промышленном терминале. РЖДшный софт вообще работал в Kiosk mode, были заблокированы практически все элементы управления ОС Android.

Смарт-карты

Устройство поддерживает работу со смарт-картами стандарта ISO7816, к которому принадлежит подавляющее большинство контактных смарт-карт. В качестве считывателя, как уже упоминалось, используется таковой от Athena Smartcard Solutions. Разумеется, если написать свой софт, считывать при помощи этого устройства можно будет любые другие поддерживаемые карты, а не только лишь таковые для РЖД.

РЖДфон десять лет спустя - 21

Считыватель совершенно массовый, выпускается и в отдельно стоящем исполнении для подключения по USB к обычному ПК.

РЖДфон десять лет спустя - 22

А вот и предустановленное тестовое приложение для данного считывателя.

Сканер

Здесь установлен одномерный лазерный сканер. Какой именно сканирующий модуль тут стоит, мне неведомо, скорее всего, некий OEM, например, от того же Symbol. Ничего плохого в этом нет, точно такие же ставят в массово выпускающиеся терминалы сбора данных.

РЖДфон десять лет спустя - 23

Для теста сканера тоже есть своё приложение. Жмём кнопку — сканер загорается, при успешном считывании кода раздаётся звук.
Что печально, так это то, что отсутствует отдельная кнопка для сканирования штрих-кода. На боковых гранях есть только кнопки громкости и блокировки. А ведь такое решение делает работу со сканером куда удобнее. Во всех терминалах сбора данных, что у меня есть, такая кнопка наличествует.

Сравнение

Совершенно логично, что сравнивать такой аппарат с каким-то потребительским (тем более бюджетным) смартфоном не совсем корректно. Нужен какой-то девайс, который мог бы быть с ним «на равных». И в качестве такого возьмём терминал сбора данных Motorola (Symbol/Zebra) MC40N0. Он так же работает на Android OS и имеет схожие характеристики.

РЖДфон десять лет спустя - 24

Что сразу бросается в глаза — Motorola куда компактнее. Особенно это видно, если положить два девайса рядом.

РЖДфон десять лет спустя - 25

Экран РЖДфона ужасен — на улице в ясную погоду даже на максимальной яркости ничего не видно. И нет, проблема не в том, что я не отклеил защитную плёнку — «голый» экран со снятым сенсором тоже прекрасно бликует, что было выяснено при разборке.

РЖДфон десять лет спустя - 26

А вот Motorola держится бодрячком. Увы, камера этого не передаёт, но бликов заметно меньше…

РЖДфон десять лет спустя - 27

Но зато сенсор РЖДфона резистивный, что в сочетании с ориентированными на пальцы элементами управления позволяет при некоторой сноровке пользоваться девайсом даже на морозе в негнущихся варежках.

РЖДфон десять лет спустя - 28

РЖДфон десять лет спустя - 29

Тип резервного питания тоже отличается — РЖДфон использует второй литий-ионный аккумулятор, позволяющий аппарату работать (правда, недолго) даже при отсутствии основного. MC40N0 же оснащён NiMH-батареей, поддерживающей только оперативную память. Для смены аккумулятора необходимо нажать и удерживать кнопку питания, а затем выбрать пункт «Battery swap».

РЖДфон десять лет спустя - 30

Примерно такой аккумулятор стоит внутри него. 2,4 вольта и скромные 20 мА*ч. Этого с лихвой хватает, чтобы держать память в течение нескольких минут.

РЖДфон десять лет спустя - 31

А вот для примера резервный литий-ионный аккумулятор внутри терминала сбора данных M3 Mobile Compia.

РЖДфон десять лет спустя - 32

Сканеры тоже порядочно отличаются: РЖДфон имеет обычный одномерный лазерный, Motorola — двумерный. Если в первом используется знакомая всем система с колеблющимся зеркальцем и фотодатчиком, во втором лазер за распознавание отвечает камера с отдельным блоком обработки изображения. При этом луч лазера неподвижен, а для создания паттерна сканирования используется линза Френеля. Преимущества такого сканера очевидны: он может «взять» код с экрана, распознать QR, DataMatrix или PDF417, справиться со слегка повреждённым или плохо читаемым кодом. Ну и к тому же он не содержит подвижных частей, что повышает его устойчивость к ударам и прочим жизненным потрясениям. Впрочем, возможно, что в терминале РЖД возможность считывания двумерных штрих-кодов попросту не была востребована, отчего было решено установить обычный лазерный сканер.

РЖДфон десять лет спустя - 33

По части характеристик MC40N0 серьёзно обгоняет предмет нашего обзора: более мощный процессор, в два раза больше памяти. Но и цена тоже соответствующая — в районе ста тысяч рублей.

Приложение сканера

Мне стало интересно, как устроена работа с самим сканером. Открываем всем известный ADB App Control, быстро находим название пакета: com.cct.scantest. Копируем его на компьютер. Распаковав его как ZIP и не найдя ничего интересного, пробуем декомпилировать.
Вся логика приложения оказалась весьма простая, так что исходник я разместил прямо тут:

Собственно

package com.cct.scantest;

import android.app.Activity;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.Process;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import gnu.io.PortInUseException;
import gnu.io.RXTXPort;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.util.TooManyListenersException;

public class ScanTest extends Activity implements View.OnClickListener {
    private static final String LOGTAG = "ScanTest";
    private Button btnExit;
    private Button btnScan;
    private FileWriter cmdOutput;
    /* access modifiers changed from: private */
    public InputStream dataInput;
    /* access modifiers changed from: private */
    public Handler mHandler = new Handler() {
        public void handleMessage(Message msg) {
            ScanTest.this.textCode.setText((String) msg.obj);
            new Thread(new SoundPlayer(ScanTest.this, (SoundPlayer) null)).start();
        }
    };
    /* access modifiers changed from: private */
    public final Runnable mRestoreGpioState = new Runnable() {
        public void run() {
            if (!ScanTest.this.mRestoreGpioStateHandled) {
                ScanTest.this.mRestoreGpioStateHandled = true;
                ScanTest.this.setScanGpioState(false);
            }
        }
    };
    /* access modifiers changed from: private */
    public volatile boolean mRestoreGpioStateHandled = false;
    private SerialPort serialPort;
    /* access modifiers changed from: private */
    public TextView textCode;

    private class SoundPlayer implements Runnable {
        /* access modifiers changed from: private */
        public MediaPlayer mPlayer;

        private SoundPlayer() {
        }

        /* synthetic */ SoundPlayer(ScanTest scanTest, SoundPlayer soundPlayer) {
            this();
        }

        public void run() {
            this.mPlayer = MediaPlayer.create(ScanTest.this.getApplicationContext(), R.raw.ok);
            this.mPlayer.setLooping(false);
            this.mPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                public void onCompletion(MediaPlayer mp) {
                    SoundPlayer.this.mPlayer.release();
                }
            });
            this.mPlayer.start();
        }
    }

    private final class SerialEventsListener implements SerialPortEventListener {
        private SerialEventsListener() {
        }

        /* synthetic */ SerialEventsListener(ScanTest scanTest, SerialEventsListener serialEventsListener) {
            this();
        }

        public void serialEvent(SerialPortEvent ev) {
            if (ev.getEventType() == 1) {
                byte[] readBuffer = new byte[512];
                String sReadBuff = "";
                while (ScanTest.this.dataInput.available() > 0) {
                    try {
                        sReadBuff = String.valueOf(sReadBuff) + new String(readBuffer, 0, ScanTest.this.dataInput.read(readBuffer), "UTF-8");
                    } catch (IOException e) {
                        Log.e(ScanTest.LOGTAG, "Error Reading from serial port", e);
                    }
                }
                Log.d(ScanTest.LOGTAG, "read data:" + sReadBuff);
                Message.obtain(ScanTest.this.mHandler, 1, sReadBuff).sendToTarget();
                if (!ScanTest.this.mRestoreGpioStateHandled) {
                    ScanTest.this.mHandler.removeCallbacks(ScanTest.this.mRestoreGpioState);
                    ScanTest.this.setScanGpioState(false);
                }
            }
        }
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        this.textCode = (TextView) findViewById(R.id.text_code);
        this.btnScan = (Button) findViewById(R.id.btn_scan);
        this.btnExit = (Button) findViewById(R.id.btn_exit);
        this.btnScan.setOnClickListener(this);
        this.btnExit.setOnClickListener(this);
    }

    /* access modifiers changed from: protected */
    public void onResume() {
        super.onResume();
        registerPort();
    }

    /* access modifiers changed from: protected */
    public void onPause() {
        super.onPause();
        unRegisterPort();
    }

    public void onClick(View view) {
        if (view.getId() == R.id.btn_scan) {
            this.textCode.setText("");
            laserScan();
            return;
        }
        setScanGpioState(false);
        unRegisterPort();
        Process.killProcess(Process.myPid());
    }

    private void laserScan() {
        setScanGpioState(false);
        try {
            Thread.sleep(10);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i(LOGTAG, e.toString());
        }
        setScanGpioState(true);
        this.mRestoreGpioStateHandled = false;
        this.mHandler.postDelayed(this.mRestoreGpioState, 3000);
    }

    /* access modifiers changed from: private */
    public void setScanGpioState(boolean state) {
        if (this.cmdOutput != null) {
            try {
                this.cmdOutput.write(state ? 48 : 49);
                this.cmdOutput.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void registerPort() {
        try {
            this.serialPort = new RXTXPort("/dev/ttyMSM2");
            this.dataInput = this.serialPort.getInputStream();
            this.cmdOutput = new FileWriter("/dev/scan");
            this.serialPort.addEventListener(new SerialEventsListener(this, (SerialEventsListener) null));
            this.serialPort.notifyOnDataAvailable(true);
            this.serialPort.setSerialPortParams(9600, 8, 1, 0);
            this.serialPort.setFlowControlMode(0);
        } catch (IOException e) {
            Log.e(LOGTAG, "I/O Exception " + e.getMessage());
        } catch (PortInUseException e2) {
            Log.e(LOGTAG, "Port in use by " + e2.currentOwner);
        } catch (UnsupportedCommOperationException e3) {
            Log.e(LOGTAG, "Unsupported Operation " + e3.getMessage());
        } catch (TooManyListenersException e4) {
            Log.e(LOGTAG, "Too many listeners");
        }
    }

    private void unRegisterPort() {
        if (this.dataInput != null) {
            try {
                this.dataInput.close();
            } catch (IOException e) {
                Log.e(LOGTAG, "unRegisterPort Input", e);
            }
            this.dataInput = null;
        }
        if (this.cmdOutput != null) {
            try {
                this.cmdOutput.close();
            } catch (IOException e2) {
                Log.e(LOGTAG, "unRegisterPort Output", e2);
            }
        }
        if (this.serialPort != null) {
            this.serialPort.removeEventListener();
            this.serialPort.close();
        }
        this.serialPort = null;
    }
}

Как видно, ничего сложного здесь нет: при нажатии кнопки сканирования происходит вызов функции laserScan(), активирующей сканер, и дальнейшее чтение из последовательного порта. При успешном считывании проигрывается mp3-шка с характерным звуком, а код отображается в окне программы.

Так что же в итоге?

Итак, устройство получилось во многих смыслах неоднозначное. С одной стороны, не обошлось без недоработок (некоторые из которых весьма существенные). С другой стороны, данный аппарат — пример того, как в рекордные сроки было разработано, отлажено и запущено в серийное производство специализированное устройство с массой возможностей по приемлемой цене. Большинство тех, кто много имел дело с подобным оборудованием, согласятся, что сорок с небольшим тысяч рублей — более чем подходящая цена для такого терминала, тем более для его первой партии, где в цену включены и различные сопутствующие затраты вроде сертификации. А если учесть, что на тот момент немало продаваемых ТСД продолжали работать на базе даже тогда уже порядком устаревшей Windows CE, а аппараты на Android только начинали набирать популярность, цена данного устройства становится ещё «вкуснее».

В любом случае, проект получился весьма и весьма интересным. Увы, этим всё и закончилось. Сайт R-Style давно загнулся, а терминалы, где их успели внедрить, выработали свой ресурс и были выведены из эксплуатации. А жаль. Возможно, получи проект продолжение, в следующей версии данного устройства недоработки были бы устранены, а сам девайс стал бы ещё лучше.
Такие дела.

Ссылки

Автор: Лев

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js