Commit 514c0372 authored by Andrey Filippov's avatar Andrey Filippov
Browse files

added code to generate complete jpeg files viewable with the web browser

parent 8555bdd3
Loading
Loading
Loading
Loading
+127 −2
Original line number Diff line number Diff line
@@ -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%08x - length word = 0x%08x)"%(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,
+57 −0
Original line number Diff line number Diff line
@@ -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,
+30 −16
Original line number Diff line number Diff line
@@ -155,7 +155,21 @@ 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(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
@@ -170,7 +184,7 @@ class X393Mem(object):
                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])
                bf.write(mm[start_offset:end_offset])

    def mem_clear (self, start_addr, length, word32):
        '''
+73 −25
Original line number Diff line number Diff line
@@ -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