Типовая задача — 2

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

Я пишу большую прогу, реально большую. Для ее отладки появилась необходимость написать еще одну маленькую программку. Эта программка должна эмулировать поведение аппаратуры.

Смысл задачи вот в чем.

Линукс: всё — есть файл. (с)

Аппаратура (которую нужно сэмулировать) посылает в большую программу поток данных. Поток данных представляет собой пакеты. Каждый пакет — это обычная текстовая строка, состоящая из чисел, разделенных пробелами. Я не однократно об этом писал ранее.

Вот пример:


0 0 1216 702 0 1226 2068 2070 2040 2068 4095 3165 3185 3190 3166 3188 3189 3165 3190 3189 3165 3192 3188 3165 3192 3187 3166 3193 3188 3168 3193 3188 3169 3195 3189 3168 3195 3188 3170 3196 3187 3170 3200 3188 3172 3200 3188 3171 3200 3188 3170 3200 3189 3172 3200 3190 3172 3200 3189 3166 3166 3168 3187 3196 3172 3193 3194 3173 3194 3196 3173 3195 3195 3172 3200 3195 3173 3200 3192 3172 3200 3192 3174 3200 3192 3173 3200 3193 3174 3200 3192 3175 3201 3191 3176 3200 3190 3172 3202 3190 3174 3201 3190 3174 3202 3189 3172 3201 3188 3174 1820 2072 2050 2064 2079 2050 2064 2078 2048 2060 2077 2048 2061 2079 2050 2063 2080 2050 2062 2078 2048 2061 2080 2048 2061 2077 2049 2061 2076 2049 2060 2077 2048 2060 2078 2049 2065 2077 2048 2058 2074 2048 2058 2077 2048 2059 2078 2048 2066 2077 2048 2061 2077 2048 2057 2077 2049 2060 2079 2048 2059 2078 2048 2061 2075 2048 2060 2074 2048 2060 2076 2048 2059 2075 2048 2056 2076 2048 2061 2077 2048 2059 2076 2048 2058 2076 2048 2057 2076 2048 2060 2078 2048 2062 2076 2048 2057 2076 2048 2055 55 946 914 928 937 912 931 937 912 932 937 911 935 937 910 935 935 910 935 936 912 936 935 911 939 934 911 940 934 912 941 933 913 941 933 913 941 933 912 940 933 912 942 932 914 943 932 915 943 934 915 943 932 915 944 932 915 944 933 916 944 932 917 942 933 916 944 933 915 945 932 915 945 933 916 945 932 917 943 934 916 943 931 915 945 930 915 943 932 914 943 932 914 943 932 915 943 929 914 942 2772 2048 2062 2075 2048 2054 2074 2048 2056 2073 2048 2056 2074 2048 2054 2072 2048 2056 2073 2048 2054 2072 2048 2054 2074 2048 2056 2073 2048 2054 2070 2048 2055 2073 2048 2054 2076 2048 2053 2072 2048 2056 2073 2048 2051 2070 2048 2056 2075 2048 2054 2072 2040 2052 2071 2048 2055 2073 2040 2054 2073 2048 2056 2074 2048 2054 2072 2048 2056 2075 2048 2057 2076 2048 2052 2071 2048 2053 2074 2048 2054 2072 2048 2056 2072 2048 2059 2072 2048 2051 2074 2048 2059 2075 2048 2055 2073 2048 2056 2072 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1217 702 0 1226 2059 2074 2048 2060 4095 3161 3180 3190 3166 3187 3189 3165 3187 3189 3166 3190 3189 3165 3191 3190 3165 3192 3188 3168 3194 3189 3167 3195 3189 3168 3196 3189 3168 3196 3188 3169 3200 3187 3171 3200 3188 3172 3200 3187 3173 3200 3188 3172 3200 3188 3172 3200 3188 3169 3169 3166 3189 3193 3172 3194 3194 3173 3195 3194 3174 3196 3194 3172 3200 3194 3172 3200 3193 3174 3200 3192 3175 3200 3193 3173 3202 3192 3174 3200 3190 3174 3201 3190 3174 3201 3189 3175 3200 3190 3174 3200 3190 3175 3202 3188 3175 3201 3187 3174 1821 2072 2048 2066 2078 2051 2064 2078 2052 2061 2077 2048 2060 2078 2050 2063 2079 2048 2063 2080 2048 2064 2078 2050 2060 2077 2048 2059 2077 2051 2062 2080 2048 2063 2077 2049 2061 2076 2048 2064 2077 2048 2060 2079 2048 2060 2076 2048 2060 2075 2048 2060 2076 2050 2057 2077 2048 2059 2077 2048 2058 2077 2048 2063 2078 2048 2062 2077 2048 2057 2077 2048 2059 2078 2048 2060 2077 2048 2060 2075 2048 2058 2077 2048 2058 2078 2048 2058 2076 2048 2059 2080 2048 2060 2076 2048 2060 2078 2048 2060 55 945 914 928 938 912 930 936 911 933 936 911 933 936 911 936 935 911 937 934 910 937 934 911 939 933 911 939 934 912 941 934 912 940 934 911 942 933 911 941 931 914 943 933 914 942 932 914 943 933 913 944 932 915 945 931 916 943 931 917 944 933 916 944 932 916 944 931 916 945 931 917 944 932 916 944 933 917 945 932 917 944 931 917 943 930 918 943 931 916 942 931 916 943 930 915 943 929 915 941 2774 2048 2062 2072 2048 2054 2073 2048 2057 2073 2048 2056 2074 2048 2056 2073 2048 2058 2073 2048 2056 2073 2048 2056 2071 2048 2056 2072 2048 2054 2073 2048 2057 2072 2048 2055 2072 2048 2054 2074 2048 2057 2076 2048 2055 2073 2048 2056 2072 2048 2055 2071 2048 2054 2072 2048 2056 2073 2039 2053 2071 2048 2055 2073 2048 2053 2072 2048 2054 2072 2048 2054 2076 2048 2054 2073 2048 2056 2073 2048 2053 2073 2048 2054 2073 2048 2056 2074 2048 2053 2073 2048 2055 2073 2048 2055 2074 2048 2057 2073 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 1218 703 0 1232 2048 2069 2069 2048 4095 3179 3171 3197 3180 3171 3200 3180 3173 3200 3182 3170 3200 3182 3172 3200 3182 3172 3197 3182 3171 3200 3183 3172 3200 3184 3172 3200 3183 3171 3200 3184 3173 3200 3184 3172 3200 3185 3174 3200 3184 3174 3201 3186 3174 3200 3186 3173 3200 3202 3202 3191 3194 3172 3194 3194 3172 3196 3193 3172 3200 3193 3172 3200 3192 3174 3200 3192 3174 3201 3192 3174 3200 3190 3175 3201 3192 3176 3200 3190 3175 3201 3192 3174 3202 3190 3175 3202 3190 3176 3201 3189 3176 3201 3190 3174 3202 3189 3175 3202 1858 2052 2058 2078 2052 2062 2079 2051 2065 2079 2050 2064 2077 2050 2059 2077 2049 2060 2078 2050 2063 2078 2049 2064 2077 2050 2064 2077 2048 2061 2076 2050 2062 2078 2048 2061 2080 2049 2061 2076 2048 2060 2077 2048 2058 2078 2048 2059 2075 2048 2058 2079 2048 2062 2077 2048 2060 2076 2048 2057 2075 2048 2059 2075 2048 2060 2077 2048 2059 2074 2048 2059 2076 2048 2058 2076 2048 2058 2076 2048 2057 2076 2048 2059 2078 2048 2063 2077 2048 2057 2075 2048 2057 2076 2048 2059 2078 2048 2060 2076 69 917 931 938 913 934 938 912 933 937 912 936 937 911 936 935 910 937 935 910 938 934 911 939 934 911 940 936 912 940 932 912 940 934 912 942 933 912 940 933 913 940 933 913 941 934 914 943 932 915 943 932 916 941 931 916 943 931 914 942 932 915 945 932 916 946 931 917 945 933 918 945 931 915 945 931 918 946 929 917 945 930 918 944 931 916 944 930 916 945 928 917 944 931 916 944 931 916 942 930 2740 2073 2071 2040 2061 2075 2048 2056 2072 2048 2056 2073 2048 2055 2073 2048 2056 2072 2048 2054 2072 2048 2057 2072 2048 2055 2073 2048 2056 2073 2048 2057 2074 2048 2053 2072 2048 2056 2074 2048 2055 2074 2048 2055 2072 2048 2055 2072 2048 2053 2072 2048 2056 2072 2048 2055 2073 2048 2054 2072 2048 2056 2075 2048 2054 2073 2048 2057 2073 2048 2054 2071 2048 2054 2072 2048 2057 2074 2048 2051 2072 2048 2056 2076 2048 2056 2073 2048 2056 2071 2048 2054 2074 2048 2053 2075 2048 2059 2073 2048 0 0 0 0 0 0 0 0 0 0 0 0 0

«Большая программа» — это реально большая графическая прога, которая будет отображать получаемые в реальном времени данные в виде графиков.

К слову сказать, ее рабочее название — «Каротажник». Если не будет особых возражений, с этим именем она и пойдет по жизни. Ну, это так между делом.

Так вот, писать «Каротажника» и для его тестирования использовать реальный комплект аппаратуры получается не совсем удобно. Это — лишние провода, минус пространство рабочего стола, дополнительная забота о включении-выключении этой аппаратуры, ну и так далее. В общем — суета, которая отвлекает.

Поэтому, было бы разумнее написать небольшую прогу, которая эмулировала бы это всё хозяйство. Ведь, по сути — «Каротажнику» всё равно откуда получать информационный поток: из USB-порта или из канала (pipe).

С точки зрения «Каротажника» это одно и то же:

$ cat /dev/ttyUSB0 > carotageman
$ emulator prk-2015.06.04-00.48.text > carotageman

Здесь prk-2015.06.04-00.48.text — это имя файла с данными, откуда эмулятор будет считывать и посылать ежесекундно строки.

В программе-эмуляторе нужно предусмотреть возможность изменять период передачи строк: от 0.1 до 1 секунды; и возможность циклической передачи. (То есть когда закончится файл, его нужно начать передавать с начала.)

Выглядеть это должно так:

$ emulator -r -d 250 prk-2015.06.04-00.48.text > carotageman

здесь -r — включение рекурсии, -d 250 — установка периода 250 мс. Если период не задан, то нужно установить период равный 1 секунде.

На чем будет создана программа — рояли не играет!

Ну вот, вроде бы всё!

UPDATE 04.06.2015

Руслан первый написал код программы. Поэтому публикую его код первым.

import argparse
import time
import sys


def read_by_line(input, delay, is_recourse):
    while True:
        input.seek(0)
        for line in input:
            sys.stdout.write(line)
            time.sleep(delay/1000.0)
        if not is_recourse:
            break


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Sends a given file to stdout in per line manner.')
    parser.add_argument('-r', action='store_true', default=False, dest='is_recourse',
                        help='send the file lines again and again.')
    parser.add_argument('-d', action='store', default=250, dest='delay', type=int,
                        help='delay in milliseconds, by default 250ms.')
    parser.add_argument('input', type=file, help='source file')
    args = parser.parse_args()

    try:
        read_by_line(args.input, args.delay, args.is_recourse)
    except KeyboardInterrupt:
        pass

    sys.exit(0)

Код программы Руслана лежит на Гитхабе:
https://gist.github.com/RaD/e4c0c1ecb94b7571dd4d

А вот мой вариант (уточнённый и подправленный после пробной эксплуатации):

#!/usr/bin/env python3
#coding:utf-8


'''
prk-emulator -- программа-эмулятор ПРК.

Прога читает текстовый файл, заданный в командной строке, раз в секунду выводит
из него одну строку на стандартный вывод.

Пример использования:
$ prk-emulator.py -r -p 250 file.prk

-r       -- вывод строк рекурсивно
-p 250   -- период вывода = 250 мс
file.prk -- текстовый файл
'''


import argparse, time, sys


################################################################################
def line_generator(df, period):
  for line in df:
    print(line, end='')
    time.sleep(period / 1000.0)

################################################################################
if __name__ == '__main__':
  parser = argparse.ArgumentParser(description=
    'Эмулятор сигналов ПРК выводит строки из файла с заданной периодичностью')
  parser.add_argument('--recursive', '-r', action='store_true', help=u'рекурсивное выполнение')
  parser.add_argument('--period', '-p', type=int, default=1000, help=u'период повторения (мс)')
  parser.add_argument('file', type=argparse.FileType('r'), help=u'файл с данными')
  args = parser.parse_args()

  '''
  # Фрагмент кода для отладки
  if args.recursive:
    print(u'рекурсивное выполнение')
  else:
    print(u'без рекурсии')
    
  print('Период = {} мс'.format(args.period))
  print('Файл с данными:', args.file.name)
  '''
  
  try:
    if args.recursive:
      # Бесконечный вывод (рекурсивный). Остановка рекурсии по Ctrl-C
      while True:        
        line_generator(args.file, args.period)
        args.file.seek(0)
    else:
      # Вывели содержимое файла и закончили работу
      line_generator(args.file, args.period)
  except KeyboardInterrupt:
    sys.stderr.write('\n')

Я пока не сравнивал эти две версии программ, просто выложил как есть.

Реклама

7 responses to “Типовая задача — 2

  1. Хочу взамен своё имя в суб-со-авторах 🙂

  2. Вот ссылка на скрипт

  3. Комментарии по вашей версии скрипта:
    1) не надо переоткрывать файл, argparse уже возвращает готовый объект файла;
    2) если печатать через sys.stdout.write, то strip() не нужен;
    3) откуда «-p», по ТЗ было «-d» 🙂
    4) скрипт должен возвращать 0, поэтому sys.exit(0) нужен.

    Комментарии по моей версии скрипта:
    1) можно переделать цикл в read_by_line в вариант do-while для повышения читаемости.

    • 1. Да, я это уже понял, когда начал работать, но пока решил не трогать. Потом подправлю.

      2. Это было быстрое решение. Уже поправил: print(line, end=»)

      3. Это не принципиально!
      Хотя, надо сказать, что это моя вина — я не очень тщательно продумал ТЗ. Походу дела выяснилось, что период лучше обозначить не через ‘d’, а через ‘p’. Но еще раз — это не имеет значения. Мне кажется, что «период повторения» звучит логичнее и понятнее, чем время «задержка».

      Спасибо за Ваши замечания!

  4. Блин, забыл, что в Python нет do-while 🙂

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s