LINUX.ORG.RU

Два параллельных loop-a или...

 


0

1

Имеется одноплатный компьютер с Линухами на борту (дистриб archlinuxarm). К плате подключено 9 кнопок через GPIO. Хочется из этой железки сделать монитор ip-камер. Собственно накидал до безобразия простой скрипт следующего содержания:

#!/bin/sh
#
fbset -fb /dev/fb0 -xres 768 -yres 576 -vxres 768 -vyres 576


# Open the GPIO port
#
echo "4" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio4/direction

echo "17" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio17/direction

echo "21" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio21/direction

echo "22" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio22/direction

echo "18" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio18/direction

echo "23" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio23/direction

echo "24" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio24/direction

echo "25" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio25/direction

echo "8" > /sys/class/gpio/export
echo "in" > /sys/class/gpio/gpio8/direction

# Read forever

while [ "1" = "1" ]; do

  if [ "1" = `cat /sys/class/gpio/gpio4/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.1/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio17/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.2/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio21/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.3/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio22/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.4/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio18/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.5/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio23/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.6/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio24/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.7/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio25/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.8/mjpg/1/video.mjpg"&
  fi

  if [ "1" = `cat /sys/class/gpio/gpio8/value` ]; then
    killall -v mplayer
    mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.9/mjpg/1/video.mjpg"&
  fi
done

exit 0

Впринципе оно работает - видео оно показывает и по нажатию кнопок видеопотоки переключаются, но... частота опроса кнопок низковата - чтобы кнопка сработала нужно её 1-2 секунды удерживать. Пробовал в loop-e оставить только cat /sys/class/gpio/gpioХ/value - тогда цыферки очень быстро бегут и срабатывают они мгновенно, а тут... Видимо луп получился слишком тяженый и условия if по долгу обрабатываются.

В общем в голову приходит только вариант с двумя параллельно работающими loop-ами - один занимается опросом GPIO портов и записью состояния кнопок в какую-нибудь переменную, а второй читает эту переменную и запускает в нужный момент соответствующий mplayer. Но как это можно реализовать в bash-е (и можно ли вобще) я не знаю.

Посоветуйте как эту проблему лучше решить.


Во-первых,

dev[0]=4
url[0]=1

dev[1]=17
url[1]=2

dev[2]=21
url[2]=3

dev[3]=22
url[3]=4

dev[4]=18
url[4]=5

dev[5]=23
url[5]=6

dev[6]=24
url[6]=7

dev[7]=25
url[7]=8

dev[8]=8
url[8]=9

while true; do
  for i in $(seq 0 ${#dev[@]}); do
    if [ $(cat /sys/class/gpio/gpio${dev[$i]}/value) = '1' ]; then
      killall -v mplayer
      mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.${url[$i]}/mjpg/1/video.mjpg"&
    fi
  done
done

Во-вторых, советую писать обработчики на каком-нибудь си, на баше с этим сложно

derlafff ★★★★★
()
Последнее исправление: derlafff (всего исправлений: 1)

1) Заменить $(cat file) на $(<file).
2) Заменить [ «1» = «1» ] на :.
3) Сделайте проверки параллельными:

check_gpio_mplayer () {
while :; do
if [ «1» = «$(</sys/class/gpio/gpio${1}/value)» ]; then
killall -v mplayer
mplayer -loop 0 -really-quiet -framedrop -vo fbdev2 -demuxer lavf -lavfdopts probesize=32 "http://x.x.x.${2}/mjpg/1/video.mjpg"&
fi
sleep .1s # откаблировать по вкусу
done &
}
for cmd in «4 1» «17 2» «21 3» «22 4» «18 5» «23 6» «24 7» «25 8» «8 9»; do
check_gpio_mplayer $cmd
done


4) Не повторяйте код:
for gpio in 4 17 21 22 18 23 24 25 8; do
echo «$gpio» > /sys/class/gpio/export
echo «in» > /sys/class/gpio/gpio${gpio}/direction
done

Язык точно нельзя сменить на какой-нибудь C или Perl (его можно собрать с make -f Makefile.micro)?

AITap ★★★★★
()
Последнее исправление: AITap (всего исправлений: 2)

ну форкать процесс на баше проще простого ты это и так уже делаешь добавляя & в конце строки, кто мешает создать пару скриптов, запустить их в бэкграунде через & и связать через файлик или к примеру пайп, или вообще через конвеер '|' пробрасывать данные...

mm3 ★★★
()
Ответ на: комментарий от AITap

можно вместо циклического чтения из множества gpioXX/value(что может быть долго) проверять изменения их atime

набросок:

touch $flag
# цикл опроса
while 1 ; do
# список файлов которые поменялись
list=`find /sys/class/gpio -name 'gpio*/value' -type f -anewer $flag`
# если изменился хотя-бы один
if [ "A$list" -ne "A" ]; then
   # обновить флаг
   touch $flag
   # разобрать всё что изменилось,считать и принять меры
   ...
fi  
done

MKuznetsov ★★★★★
()
Ответ на: комментарий от AITap

AITap

1) Заменить $(cat file) на $(<file). 2) Заменить [ «1» = «1» ] на :. 3) Сделайте проверки параллельными: 4) Не повторяйте код: Язык точно нельзя сменить на какой-нибудь C или Perl (его можно собрать с make -f Makefile.micro)?

Попробовал ваш вариант - при sleep .1s кнопки работают идеально, но появилась другая беда - стал тормозить mplayer (даже с учётом того что в него всего 5 fps вливают). При sleep .3s более-менее можно работать - mplayer не сильно тормозит и кнопки более-менее отзывчивы, но всётаки не идеально :(

C или Perl это, конечно, хорошо, но мне хотелось бы иметь мультиплатформенность. При переносе на другой девайс (с другой архитектурой процессора и т.д.) программу придётся перекомпилировать заново. Да и не такая уж сложная задача - опрос кнопок - чтобы писать для неё отдельную программу. Ваши советы очень помогли. Думаю, если ещё немного оптимизировать скрипт то и в баше всё будет работать замечательно.

tERBO
() автор топика
Ответ на: комментарий от MKuznetsov

MKuznetsov

можно вместо циклического чтения из множества gpioXX/value(что может быть долго) проверять изменения их atime

Видимо, это то, что мне надо, но либо я такой нуб, либо временно критинизм в голове проснулся, но я не смог применить ваш пример к своему скрипту. Если не затруднит - напишите его полностью на основе того что я выложил в первом посте. Заранее благодарю.

tERBO
() автор топика
Ответ на: комментарий от tERBO

есть нюансы реализации в драйвере - такой подход может тоже не сработать с /sys :(

если реальное непосредственное чтение из порта происходит лишь при открытии файла на чтение - подход не сработает. И скорее всего именно так оно и есть, потому как это самая простая реализация.

проверьте : ls -l /sys/class/gpio/gpio4/value ; ls -lu /sys/class/gpio/gpio4/value; потом нажать соотв. кнопку и повторить. сравнить результаты. Если метки времени не изменились, то опаньки - не выйдет..

MKuznetsov ★★★★★
()
Ответ на: комментарий от tERBO

тогда только С :)

но это ничуть не сложно: вот на этой вот страничке (https://www.ridgerun.com/developer/wiki/index.php/How_to_use_GPIO_signals) которую вы наверняка уже видели, есть ссылочка на их тестовую программу (вот https://www.ridgerun.com/developer/wiki/index.php/Gpio-int-test.c) которую в свою очередь несложно адаптировать под ваши нужды.

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.