Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
X
x393
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Commits
Open sidebar
Elphel
x393
Commits
514c0372
Commit
514c0372
authored
Sep 15, 2015
by
Andrey Filippov
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
added code to generate complete jpeg files viewable with the web browser
parent
8555bdd3
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
287 additions
and
43 deletions
+287
-43
x393_cmprs_afi.py
py393/x393_cmprs_afi.py
+127
-2
x393_jpeg.py
py393/x393_jpeg.py
+57
-0
x393_mem.py
py393/x393_mem.py
+30
-16
x393_sens_cmprs.py
py393/x393_sens_cmprs.py
+73
-25
No files found.
py393/x393_cmprs_afi.py
View file @
514c0372
...
...
@@ -34,10 +34,10 @@ __status__ = "Development"
#import pickle
from
x393_mem
import
X393Mem
import
x393_axi_control_status
import
x393_sens_cmprs
import
x393_utils
#
import time
import
time
import
vrlg
class
X393CmprsAfi
(
object
):
DRY_MODE
=
True
# True
...
...
@@ -82,6 +82,131 @@ class X393CmprsAfi(object):
vrlg
.
CMPRS_AFIMUX_STATUS_CNTRL
,
mode
,
seq_num
)
def
afi_mux_get_image_pointer
(
self
,
port_afi
,
channel
):
"""
Returns image pointer in bytes inside the circbuf. Status autoupdate should be already set up, mode = 0
@param port_afi - AFI port (0/1), currently only 0
@param channel - AFI input channel (0..3) - with 2 AFIs - 0..1 only
@return - displacement to current image pointer in bytes
"""
# print ("status reg = 0x%x"%(((vrlg.CMPRS_AFIMUX_REG_ADDR0, vrlg.CMPRS_AFIMUX_REG_ADDR1)[port_afi]+channel) ))
# print ("status reg data = 0x%x"%(self.x393_axi_tasks.read_status((vrlg.CMPRS_AFIMUX_REG_ADDR0, vrlg.CMPRS_AFIMUX_REG_ADDR1)[port_afi]+channel) ))
if
(
self
.
DRY_MODE
):
return
None
return
32
*
(
self
.
x393_axi_tasks
.
read_status
((
vrlg
.
CMPRS_AFIMUX_REG_ADDR0
,
vrlg
.
CMPRS_AFIMUX_REG_ADDR1
)[
port_afi
]
+
channel
)
&
0x3ffffff
)
def
afi_mux_get_image_meta
(
self
,
port_afi
,
channel
,
cirbuf_start
=
0x27a00000
,
circbuf_len
=
0x1000000
,
verbose
=
1
):
"""
Returns image metadata (start, length,timestamp) or null
@param port_afi - AFI port (0/1), currently only 0
@param channel - AFI input channel (0..3) - with 2 AFIs - 0..1 only
@return - memory segments (1 or two) with image data, timestamp in numeric and string format
"""
print
(
"x393_sens_cmprs.GLBL_WINDOW = "
,
x393_sens_cmprs
.
GLBL_WINDOW
)
if
(
self
.
DRY_MODE
):
return
None
CCAM_MMAP_META
=
12
# extra bytes included at the end of each frame (last aligned to 32 bytes)
CCAM_MMAP_META_LENGTH
=
4
# displacement to length frame length data from the end of the 32-byte aligned frame slot
CCAM_MMAP_META_USEC
=
8
# // (negative) displacement to USEC data - 20 bits (frame timestamp)
CCAM_MMAP_META_SEC
=
12
# // (negative) displacement to SEC data - 32 bits (frame timestamp)
# offs_len32 = 0x20 - CCAM_MMAP_META_LENGTH # 0x1c #from last image 32-byte chunk to lower of 3-byte image length (MSB == 0xff)
next_image
=
self
.
afi_mux_get_image_pointer
(
port_afi
=
port_afi
,
channel
=
channel
)
last_image_chunk
=
next_image
-
0x40
if
last_image_chunk
<
0
:
last_image_chunk
+=
circbuf_len
len32
=
self
.
x393_mem
.
read_mem
(
cirbuf_start
+
last_image_chunk
+
(
0x20
-
CCAM_MMAP_META_LENGTH
))
markerFF
=
len32
>>
24
if
(
markerFF
!=
0xff
):
print
(
"Failed to get 0xff marker at offset 0x
%08
x - length word = 0x
%08
x)"
%
(
cirbuf_start
+
last_image_chunk
+
(
0x20
-
CCAM_MMAP_META_LENGTH
)
+
3
,
len32
))
return
None
len32
&=
0xffffff
inserted_bytes
=
(
32
-
(((
len32
%
32
)
+
CCAM_MMAP_META
)
%
32
))
%
32
img_start
=
last_image_chunk
+
32
-
CCAM_MMAP_META
-
inserted_bytes
-
len32
if
img_start
<
0
:
img_start
+=
circbuf_len
sec
=
self
.
x393_mem
.
read_mem
(
cirbuf_start
+
last_image_chunk
+
(
0x20
-
CCAM_MMAP_META_SEC
))
usec
=
self
.
x393_mem
.
read_mem
(
cirbuf_start
+
last_image_chunk
+
(
0x20
-
CCAM_MMAP_META_USEC
))
fsec
=
sec
+
usec
/
1000000.0
tstr
=
time
.
strftime
(
"
%
b
%
d
%
Y
%
H:
%
M:
%
S"
,
time
.
gmtime
(
fsec
))
segments
=
((
cirbuf_start
+
img_start
,
len32
),)
if
(
img_start
+
len32
)
>
circbuf_len
:
# split in two segments
segments
=
((
cirbuf_start
+
img_start
,
circbuf_len
-
img_start
),
(
cirbuf_start
,
len32
-
(
circbuf_len
-
img_start
)))
result
=
{
"timestamp"
:
fsec
,
"timestring"
:
tstr
,
"segments"
:
segments
}
if
verbose
>
0
:
print
(
"Inserted bytes after image before meta = 0x
%
x"
%
(
inserted_bytes
))
print
(
"Image start (relative to cirbuf) = 0x
%
x"
%
(
img_start
))
print
(
"Image time stamp =
%
s (
%
f)"
%
(
tstr
,
fsec
))
for
s
in
segments
:
print
(
"start_address = 0x
%
x, length = 0x
%
x"
%
(
s
[
0
],
s
[
1
]))
return
result
"""
>>> hex (0x3dacb * 32)
'0x7b5960'
>>> hex (0x3dacb * 32 + 0x27a00000)
'0x281b5960'
print time.strftime("
%
b
%
d
%
Y
%
H:
%
M:
%
S", time.gmtime(1442344402.605793))
#define CCAM_MMAP_META 12 // extra bytes included at the end of each frame (last aligned to 32 bytes)
#define CCAM_MMAP_META_LENGTH 4 // displacement to length frame length data from the end of the 32-byte aligned frame slot
#define CCAM_MMAP_META_USEC 8 // (negative) displacement to USEC data - 20 bits (frame timestamp)
#define CCAM_MMAP_META_SEC 12 // (negative) displacement to SEC data - 32 bits (frame timestamp)
**
* @brief Locate area between frames in the circular buffer
* @return pointer to interframe parameters structure
*/
inline struct interframe_params_t* updateIRQ_interframe(void) {
int circbuf_size=get_globalParam (G_CIRCBUFSIZE)>>2;
int alen = JPEG_wp-9; if (alen<0) alen+=circbuf_size;
int jpeg_len=ccam_dma_buf_ptr[alen] & 0xffffff;
set_globalParam(G_FRAME_SIZE,jpeg_len);
int aframe_params=(alen & 0xfffffff8)-
(((jpeg_len + CCAM_MMAP_META + 3) & 0xffffffe0)>>2) /// multiple of 32-byte chunks to subtract
-8; /// size of the storage area to be filled before the frame
if(aframe_params < 0) aframe_params += circbuf_size;
struct interframe_params_t* interframe= (struct interframe_params_t*) &ccam_dma_buf_ptr[aframe_params];
/// should we use memcpy as before here?
interframe->frame_length=jpeg_len;
interframe->signffff=0xffff;
#if ELPHEL_DEBUG_THIS
set_globalParam (0x306,get_globalParam (0x306)+1);
#endif
return interframe;
}
/**
* @brief Fill exif data with the current frame data, save pointer to Exif page in the interframe area
"""
# def read_mem (self,addr,quiet=1):
# '''
# Read 32-bit word from physical memory
# @param addr physical byte address
# @param quiet - reduce output
#self.x393_mem
#0x27a00000
# parameter CMPRS_AFIMUX_REG_ADDR0= 'h18, // Uses 4 locations
# parameter CMPRS_AFIMUX_REG_ADDR1= 'h1c, // Uses 4 locations
def
afi_mux_reset
(
self
,
port_afi
,
...
...
py393/x393_jpeg.py
View file @
514c0372
...
...
@@ -38,6 +38,8 @@ from x393_mem import X393Mem
import
x393_axi_control_status
import
x393_utils
#import time
import
x393_sens_cmprs
import
x393_cmprs_afi
import
vrlg
STD_QUANT_TBLS
=
{
"Y_landscape"
:(
16
,
11
,
10
,
16
,
24
,
40
,
51
,
61
,
...
...
@@ -158,12 +160,16 @@ class X393Jpeg(object):
x393_mem
=
None
x393_axi_tasks
=
None
#x393X393AxiControlStatus
x393_utils
=
None
x393_cmprs_afi
=
None
verbose
=
1
def
__init__
(
self
,
debug_mode
=
1
,
dry_mode
=
True
,
saveFileName
=
None
):
self
.
DEBUG_MODE
=
debug_mode
self
.
DRY_MODE
=
dry_mode
self
.
x393_mem
=
X393Mem
(
debug_mode
,
dry_mode
)
self
.
x393_axi_tasks
=
x393_axi_control_status
.
X393AxiControlStatus
(
debug_mode
,
dry_mode
)
self
.
x393_cmprs_afi
=
x393_cmprs_afi
.
X393CmprsAfi
(
debug_mode
,
dry_mode
)
self
.
x393_utils
=
x393_utils
.
X393Utils
(
debug_mode
,
dry_mode
,
saveFileName
)
# should not overwrite save file path
try
:
self
.
verbose
=
vrlg
.
VERBOSE
...
...
@@ -564,6 +570,57 @@ class X393Jpeg(object):
return
{
"header"
:
buf
,
"quantization"
:
qtables
[
"fpga"
],
"huffman"
:
self
.
huff_tables
[
FPGA_HUFFMAN_TABLE
]}
def
jpeg_write
(
self
,
file_path
=
"/www/pages/img.jpeg"
,
channel
=
0
,
y_quality
=
100
,
#80,
c_quality
=
None
,
portrait
=
False
,
color_mode
=
0
,
byrshift
=
0
,
verbose
=
1
):
"""
Create JPEG image from the latest acquired in the camera
@param file_path - camera file system path
@param channel - compressor channel
@param y_quality - 1..100 - quantization quality for Y component
@param c_quality - 1..100 - quantization quality for color components (None - use y_quality)
@param portrait - False - use normal order, True - transpose for portrait mode images
@param color_mode - one of the image formats (jpeg, jp4,)
@param byrshift - Bayer shift
@param verbose - verbose level
"""
jpeg_data
=
self
.
jpegheader_create
(
y_quality
=
y_quality
,
c_quality
=
c_quality
,
portrait
=
portrait
,
height
=
x393_sens_cmprs
.
GLBL_WINDOW
[
"height"
],
width
=
x393_sens_cmprs
.
GLBL_WINDOW
[
"width"
],
color_mode
=
color_mode
,
byrshift
=
byrshift
,
verbose
=
verbose
-
1
)
meta
=
self
.
x393_cmprs_afi
.
afi_mux_get_image_meta
(
port_afi
=
0
,
channel
=
channel
,
cirbuf_start
=
x393_sens_cmprs
.
GLBL_CIRCBUF_STARTS
[
channel
],
circbuf_len
=
x393_sens_cmprs
.
GLBL_CIRCBUF_CHN_SIZE
,
verbose
=
1
)
print
(
"meta = "
,
meta
)
for
s
in
meta
[
"segments"
]:
print
(
"start_address = 0x
%
x, length = 0x
%
x"
%
(
s
[
0
],
s
[
1
]))
with
open
(
file_path
,
"w+b"
)
as
bf
:
bf
.
write
(
jpeg_data
[
"header"
])
for
s
in
meta
[
"segments"
]:
print
(
"start_address = 0x
%
x, length = 0x
%
x"
%
(
s
[
0
],
s
[
1
]))
self
.
x393_mem
.
_mem_write_to_file
(
bf
=
bf
,
start_addr
=
s
[
0
],
length
=
s
[
1
])
bf
.
write
(
bytearray
((
0xff
,
0xd9
)))
def
jpegheader_write
(
self
,
file_path
=
"jpeg"
,
y_quality
=
80
,
...
...
py393/x393_mem.py
View file @
514c0372
...
...
@@ -155,22 +155,36 @@ class X393Mem(object):
if
self
.
DRY_MODE
:
print
(
"Write memory to file is not implemented in non-target mode"
)
return
with
open
(
filename
,
"w+b"
)
as
sf
:
with
open
(
"/dev/mem"
,
"r+b"
)
as
f
:
first_page
=
start_addr
//
self
.
PAGE_SIZE
last_page
=
(
start_addr
+
length
-
1
)
//
self
.
PAGE_SIZE
for
page_num
in
range
(
first_page
,
last_page
+
1
):
start_offset
=
0
if
page_num
==
first_page
:
start_offset
=
start_addr
-
self
.
PAGE_SIZE
*
page_num
end_offset
=
self
.
PAGE_SIZE
if
page_num
==
last_page
:
end_offset
=
start_addr
+
length
-
self
.
PAGE_SIZE
*
page_num
page_addr
=
page_num
*
self
.
PAGE_SIZE
if
(
page_addr
>=
0x80000000
):
page_addr
-=
(
1
<<
32
)
mm
=
mmap
.
mmap
(
f
.
fileno
(),
self
.
PAGE_SIZE
,
offset
=
page_addr
)
sf
.
write
(
mm
[
start_offset
:
end_offset
])
with
open
(
filename
,
"w+b"
)
as
bf
:
self
.
_mem_write_to_file
(
bf
=
bf
,
start_addr
=
start_addr
,
length
=
length
)
def
_mem_write_to_file
(
self
,
bf
,
start_addr
,
length
):
'''
Save physical memory content to a file
@param bf - file open in write mode
@param start_addr physical byte start address
@param length - number of bytes to save
'''
if
self
.
DRY_MODE
:
print
(
"Write memory to file is not implemented in non-target mode"
)
return
with
open
(
"/dev/mem"
,
"r+b"
)
as
f
:
first_page
=
start_addr
//
self
.
PAGE_SIZE
last_page
=
(
start_addr
+
length
-
1
)
//
self
.
PAGE_SIZE
for
page_num
in
range
(
first_page
,
last_page
+
1
):
start_offset
=
0
if
page_num
==
first_page
:
start_offset
=
start_addr
-
self
.
PAGE_SIZE
*
page_num
end_offset
=
self
.
PAGE_SIZE
if
page_num
==
last_page
:
end_offset
=
start_addr
+
length
-
self
.
PAGE_SIZE
*
page_num
page_addr
=
page_num
*
self
.
PAGE_SIZE
if
(
page_addr
>=
0x80000000
):
page_addr
-=
(
1
<<
32
)
mm
=
mmap
.
mmap
(
f
.
fileno
(),
self
.
PAGE_SIZE
,
offset
=
page_addr
)
bf
.
write
(
mm
[
start_offset
:
end_offset
])
def
mem_clear
(
self
,
start_addr
,
length
,
word32
):
'''
...
...
py393/x393_sens_cmprs.py
View file @
514c0372
...
...
@@ -60,6 +60,14 @@ BUFFER_PAGES_NAME = 'buffer_pages'
BUFFER_ADDRESS
=
None
# in bytes
BUFFER_LEN
=
None
# in bytes
GLBL_CIRCBUF_CHN_SIZE
=
None
GLBL_CIRCBUF_STARTS
=
None
GLBL_CIRCBUF_END
=
None
GLBL_MEMBRIDGE_START
=
None
GLBL_MEMBRIDGE_END
=
None
GLBL_BUFFER_END
=
None
GLBL_WINDOW
=
None
class
X393SensCmprs
(
object
):
DRY_MODE
=
True
# True
DEBUG_MODE
=
1
...
...
@@ -470,6 +478,47 @@ class X393SensCmprs(object):
repet_mode
=
True
,
# Normal mode, single trigger - just for debugging TODO: re-assign?
trig
=
False
)
return
True
def
specify_window
(
self
,
window_width
=
2592
,
# 2592
window_height
=
1944
,
# 1944
window_left
=
0
,
# 0
window_top
=
0
,
# 0? 1?
):
global
GLBL_WINDOW
GLBL_WINDOW
=
{
"width"
:
window_width
,
"height"
:
window_height
,
"left"
:
window_left
,
"top"
:
window_top
}
def
specify_phys_memory
(
self
,
circbuf_chn_size
=
0x1000000
,
verbose
=
1
):
"""
@param circbuf_chn_size - circular buffer size for each channel, in bytes
"""
global
GLBL_CIRCBUF_CHN_SIZE
,
GLBL_CIRCBUF_STARTS
,
GLBL_CIRCBUF_END
,
GLBL_MEMBRIDGE_START
,
GLBL_MEMBRIDGE_END
,
GLBL_BUFFER_END
circbuf_start
=
self
.
get_circbuf_byte_start
()
GLBL_BUFFER_END
=
self
.
get_circbuf_byte_end
()
GLBL_CIRCBUF_CHN_SIZE
=
circbuf_chn_size
GLBL_CIRCBUF_STARTS
=
[]
for
i
in
range
(
16
):
GLBL_CIRCBUF_STARTS
.
append
(
circbuf_start
+
i
*
circbuf_chn_size
)
GLBL_CIRCBUF_END
=
circbuf_start
+
4
*
GLBL_CIRCBUF_CHN_SIZE
GLBL_MEMBRIDGE_START
=
GLBL_CIRCBUF_END
GLBL_MEMBRIDGE_END
=
GLBL_BUFFER_END
if
verbose
>
0
:
print
(
"compressor system memory buffers:"
)
print
(
"circbuf start 0 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
0
]))
print
(
"circbuf start 1 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
1
]))
print
(
"circbuf start 2 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
2
]))
print
(
"circbuf start 3 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
3
]))
print
(
"circbuf end = 0x
%
x"
%
(
GLBL_BUFFER_END
))
print
(
"membridge start = 0x
%
x"
%
(
GLBL_MEMBRIDGE_START
))
print
(
"membridge end = 0x
%
x"
%
(
GLBL_MEMBRIDGE_END
))
print
(
"membridge size =
%
d bytes"
%
(
GLBL_MEMBRIDGE_END
-
GLBL_MEMBRIDGE_START
))
print
(
"memory buffer end = 0x
%
x"
%
(
GLBL_BUFFER_END
))
def
setup_all_sensors
(
self
,
setup_membridge
=
False
,
exit_step
=
None
,
...
...
@@ -532,38 +581,37 @@ class X393SensCmprs(object):
@parame verbose - verbose level
@return True if all done, False if exited prematurely by exit_step
"""
global
GLBL_CIRCBUF_CHN_SIZE
,
GLBL_CIRCBUF_STARTS
,
GLBL_CIRCBUF_END
,
GLBL_MEMBRIDGE_START
,
GLBL_MEMBRIDGE_END
,
GLBL_BUFFER_END
,
GLBL_WINDOW
# camsync_setup (
# 4'hf ); # sensor_mask); #
circbuf_start
=
self
.
get_circbuf_byte_start
()
mem_end
=
self
.
get_circbuf_byte_end
()
#circbuf_chn_size
circbuf_starts
=
[]
for
i
in
range
(
16
):
circbuf_starts
.
append
(
circbuf_start
+
i
*
circbuf_chn_size
)
circbuf_end
=
circbuf_start
+
4
*
circbuf_chn_size
membridge_start
=
circbuf_end
membridge_end
=
mem_end
self
.
specify_phys_memory
(
circbuf_chn_size
=
circbuf_chn_size
)
self
.
specify_window
(
window_width
=
window_width
,
window_height
=
window_height
,
window_left
=
window_left
,
window_top
=
window_top
)
#TODO: calculate addresses/lengths
"""
AFI mux is programmed in 32-byte chunks
"""
afi_cmprs0_sa
=
circbuf_starts
[
0
]
//
32
afi_cmprs1_sa
=
circbuf_starts
[
1
]
//
32
afi_cmprs2_sa
=
circbuf_starts
[
2
]
//
32
afi_cmprs3_sa
=
circbuf_starts
[
3
]
//
32
afi_cmprs_len
=
circbuf_chn_size
//
32
afi_cmprs0_sa
=
GLBL_CIRCBUF_STARTS
[
0
]
//
32
afi_cmprs1_sa
=
GLBL_CIRCBUF_STARTS
[
1
]
//
32
afi_cmprs2_sa
=
GLBL_CIRCBUF_STARTS
[
2
]
//
32
afi_cmprs3_sa
=
GLBL_CIRCBUF_STARTS
[
3
]
//
32
afi_cmprs_len
=
GLBL_CIRCBUF_CHN_SIZE
//
32
if
verbose
>
0
:
print
(
"compressor system memory buffers:"
)
print
(
"circbuf start 0 = 0x
%
x"
%
(
circbuf_starts
[
0
]))
print
(
"circbuf start 1 = 0x
%
x"
%
(
circbuf_starts
[
1
]))
print
(
"circbuf start 2 = 0x
%
x"
%
(
circbuf_starts
[
2
]))
print
(
"circbuf start 3 = 0x
%
x"
%
(
circbuf_starts
[
3
]))
print
(
"circbuf end = 0x
%
x"
%
(
circbuf_end
))
print
(
"membridge start = 0x
%
x"
%
(
membridge_start
))
print
(
"membridge end = 0x
%
x"
%
(
membridge_end
))
print
(
"membridge size =
%
d bytes"
%
(
membridge_end
-
membridge_start
))
print
(
"memory buffer end = 0x
%
x"
%
(
mem_end
))
print
(
"circbuf start 0 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
0
]))
print
(
"circbuf start 1 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
1
]))
print
(
"circbuf start 2 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
2
]))
print
(
"circbuf start 3 = 0x
%
x"
%
(
GLBL_CIRCBUF_STARTS
[
3
]))
print
(
"circbuf end = 0x
%
x"
%
(
GLBL_BUFFER_END
))
print
(
"membridge start = 0x
%
x"
%
(
GLBL_MEMBRIDGE_START
))
print
(
"membridge end = 0x
%
x"
%
(
GLBL_MEMBRIDGE_END
))
print
(
"membridge size =
%
d bytes"
%
(
GLBL_MEMBRIDGE_END
-
GLBL_MEMBRIDGE_START
))
print
(
"memory buffer end = 0x
%
x"
%
(
GLBL_BUFFER_END
))
self
.
program_status_debug
(
3
,
0
)
if
setup_membridge
:
...
...
@@ -573,8 +621,8 @@ class X393SensCmprs(object):
window_height
=
window_height
,
window_left
=
window_left
,
window_top
=
window_top
,
membridge_start
=
membridge_start
,
membridge_end
=
membridge_end
,
membridge_start
=
GLBL_MEMBRIDGE_START
,
membridge_end
=
GLBL_MEMBRIDGE_END
,
verbose
=
verbose
)
if
sensor_mask
&
3
:
# Need power for sens1 and sens 2
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment