raw.py 5.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#!/usr/bin/env python

from __future__ import division
from __future__ import print_function

# test and code samples related getting to raw pixels values

__author__ = "Elphel"
__copyright__ = "Copyright 2018, Elphel, Inc."
__license__ = "GPL"
__version__ = "3.0+"
__maintainer__ = "Oleg K Dzhimiev"
__email__ = "oleg@elphel.com"
__status__ = "Development"

import mmap
import struct
import os
import sys
import subprocess
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
21 22 23 24
import time
import xml.etree.ElementTree as ET

import elphel_framepars as EF
25

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
26
MMAP_DATA = True
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
27
#MMAP_DATA = False
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
28

29
# globals
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
30
VPATH = "/sys/devices/soc0/elphel393-videomem@0"
31

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
32 33 34
MEM_PRE     = VPATH+"/membridge_start"
VFRAME_PRE  = VPATH+"/video_frame_number"
RAWINFO_PRE = VPATH+"/raw_frame_info"
35 36

# not used here
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
37
MEMSTATUS  = VPATH+"/membridge_status"
38

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
39
#frameparsPaths = ("/dev/frameparsall0","/dev/frameparsall1","/dev/frameparsall2","/dev/frameparsall3")
40 41

BUF_SIZE = 4096
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
42
PAGE_SIZE = 4096
43 44 45 46

# sbuf - buffer in system memory = cpu RAM
# vbuf - buffer in fpga memory = video memory

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
47 48 49 50 51
# buffer size in 4k pages
#   4096 equals 16MB
# or recalculate based on image dimensions
def set_sbuf_size(port,size):
  cmd = "echo "+str(size)+" > /sys/devices/soc0/elphel393-mem@0/buffer_pages_raw_chn"+str(port)
52 53 54 55 56 57 58 59 60 61 62
  subprocess.call(cmd,shell=True)

def set_vbuf_position(port,pos):
  cmd = "echo "+str(pos)+" > "+VFRAME_PRE
  subprocess.call(cmd,shell=True)

def copy_vbuf_to_sbuf(port,frame_number):
  cmd = "echo "+str(frame_number)+" > "+MEM_PRE+str(port)
  subprocess.call(cmd,shell=True)

def save_pixel_array(port,fname):
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
63
  cmd = "cat /dev/image_raw"+str(port)+" > "+fname
64 65 66
  subprocess.call(cmd,shell=True)
  print("Memory dumped into "+fname)

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
67
def mmap_pixel_array(port,size):
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
68
  with open("/dev/image_raw"+str(port),"r+b") as fp:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
69 70 71 72 73 74 75 76 77 78 79
      data = mmap.mmap(fp.fileno(), size, offset = 0) # mmap all data
  return data

def get_byte(data,i):
  return struct.unpack_from(">B",data[i])[0]

def get_byte_str(data,i):
  res = get_byte(data,i)
  #return str(hex(res))
  return "{:02x}".format(res)
  #return format(get_byte(data,i),'#02x')
80

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
# normally meta is 1 frame behind but can be read after
# membridge transfer is done
def get_timestamp_from_meta(port,frame_number):
  tmpfile = "/tmp/meta.xml"
  cmd = "wget -qO- 'http://127.0.0.1:"+str(IMGSRV_BASE_PORT+port)+"/meta' > "+tmpfile
  subprocess.call(cmd,shell=True)

  e = ET.parse(tmpfile).getroot()

  for i in e.iter('DateTimeOriginal'):
    #run once
    ts = i.text.strip("\"")
    break

  for i in e.iter('ImageNumber'):
    #run once
    inf = int(i.text.strip("\""))
    break

  for i in e.iter('currentSensorFrame'):
    #run once
    csf = int(i.text.strip("\""))
    break

  print("REF: "+str(frame_number)+"    ImageNumber: "+str(inf)+"    currentSensorFrame:"+str(csf))

  os.remove(tmpfile)

  return ts

111
# MAIN
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
112

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
113
IMGSRV_BASE_PORT = 2323
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
114
mmap_data = []
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
sensors = []

# First detect how many sensor ports are there
for i in range(4):
  path = "/sys/devices/soc0/elphel393-detect_sensors@0/sensor"+str(i)+"0"
  if os.path.isfile(path):
    with open(path) as f:
      if (f.read().strip()!="none"):
        sensors.append(i)

print("Available sensors: "+str(sensors))


# Now get which one is the master (from the 1st available sensor)
p = EF.Pars("/dev/frameparsall"+str(sensors[0]))
tmp_frame_num = p.get_frame_number()
trig_master = p.value(p.P_TRIG_MASTER,tmp_frame_num)
trig_master_port = IMGSRV_BASE_PORT+int(trig_master)
trig_period = p.value(p.P_TRIG_PERIOD,tmp_frame_num)
print("TRIG MASTER = "+str(trig_master))
print("TRIG PERIOD = "+str(trig_period)+" us")


# Stop master trigger (not needed)
#cmd = "wget -qO- 'http://127.0.0.1:"+str(trig_master_port)+"/trig/pointers' &> /dev/null"
#print("Stop trigger:")
#subprocess.call(cmd,shell=True)

#
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
144
# First set the buffer size and mmap once
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
145 146 147 148 149
#
for i in sensors:
  size = BUF_SIZE
  set_sbuf_size(i,size)
  if MMAP_DATA:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
150
    print("mmap buffer "+str(i))
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
151 152 153 154
    mmap_data.append(mmap_pixel_array(i,BUF_SIZE*PAGE_SIZE))

#
# Get pixel data to from fpga(=video) memory to system memory
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
155
# repeat if needed
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
156 157 158 159 160
#
for i in sensors:

  # Master port (if not overriden)
  p = EF.Pars("/dev/frameparsall"+str(i))
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
161

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
162 163 164 165
  print("Port "+str(i)+":")

  #frame_num = p.get_frame_number()+1
  #print("    frame number: "+str(frame_num))
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
166

167
  set_vbuf_position(i,0)
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
168 169 170 171 172 173
  # waiting for frame is built-in in the driver
  copy_vbuf_to_sbuf(i,tmp_frame_num+1)

  # get timestamp
  #ts = get_timestamp_from_meta(i,0)
  #print("    timestamp: "+ts)
174

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
175 176 177 178 179

#
# Save/print after all needed ports are done
#
for i in sensors:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
180
  if MMAP_DATA:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
181 182
    # print the first 16 bytes for test purposes
    print("test output: " +" ".join("{:02x}".format(get_byte(mmap_data[i],c)) for c in range(16)))
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
183 184 185 186
    # test: hexdump -C /dev/image_raw0
  else:
    save_pixel_array(i,"/tmp/port"+str(i)+".raw")

Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203
# Restore trigger
#print("Restore trigger")
#cmd = "wget -qO- 'http://127.0.0.1/parsedit.php?sensor_port="+str(trig_master)+"&immediate&TRIG_PERIOD="+str(trig_period)+"*1' &> /dev/null"
#subprocess.call(cmd,shell=True)


# debug info (might be useful for some standard raw format headers)
print("Debug, stored raw frames parameters:")
# read raw frames parameters
for i in sensors:
  with open(RAWINFO_PRE+str(i)) as f:
    print("Port "+str(i)+": ")
    # insert 4 spaces before each line of text
    print("\n".join("    "+c for c in f.read().strip().split("\n")))



Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
204
if not MMAP_DATA:
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
205
  print("Now scp raw files to pc and run bayer2rgb")
Oleg Dzhimiev's avatar
Oleg Dzhimiev committed
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220