from __future__ import division from __future__ import print_function ''' # Copyright (C) 2015, Elphel.inc. # Class to control 10353 GPIO port # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . @author: Andrey Filippov @copyright: 2015 Elphel, Inc. @license: GPLv3.0+ @contact: andrey@elphel.coml @deffield updated: Updated ''' __author__ = "Andrey Filippov" __copyright__ = "Copyright 2015, Elphel, Inc." __license__ = "GPL" __version__ = "3.0+" __maintainer__ = "Andrey Filippov" __email__ = "andrey@elphel.com" __status__ = "Development" #import sys #import pickle from x393_mem import X393Mem import x393_axi_control_status import x393_sens_cmprs import x393_utils import time import vrlg class X393CmprsAfi(object): DRY_MODE= True # True DEBUG_MODE=1 x393_mem=None x393_axi_tasks=None #x393X393AxiControlStatus x393_utils=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_utils= x393_utils.X393Utils(debug_mode,dry_mode, saveFileName) # should not overwrite save file path try: self.verbose=vrlg.VERBOSE except: pass def afi_mux_program_status (self, port_afi, chn_afi, mode, # input [1:0] mode; seq_num): # input [5:0] seq_num; """ Set status generation mode for AXI HP multiplexer for compressed data @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) configuration controlled by the code. currently both AFI are used: ch0 - cmprs_afi_mux_1.0, ch1 - cmprs_afi_mux_1.1, ch2 - cmprs_afi_mux_2.0, ch3 - cmprs_afi_mux_2. May be changed to (actually already done) ch0 - cmprs_afi_mux_1.0, ch1 -cmprs_afi_mux_1.1, ch2 - cmprs_afi_mux_1.2, ch3 - cmprs_afi_mux_1.3 @param chn_afi - numer of the afi_mux input port (0..3) @param mode - status generation mode: 0: disable status generation, 1: single status request, 2: auto status, keep specified seq number, 3: auto, inc sequence number @param seq_number - 6-bit sequence number of the status message to be sent """ self.x393_axi_tasks.program_status ( vrlg.CMPRS_GROUP_ADDR + (vrlg.CMPRS_AFIMUX_RADDR0,vrlg.CMPRS_AFIMUX_RADDR1)[port_afi] + chn_afi, 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 == True: 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, num_lines_print = 20): """ Returns image metadata (start, length,timestamp) or null @param port_afi - AFI port (0/1), currently only 0, or file path template for simulated mode @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 """ def read_mem(addr): if ba_data: return ba_data[addr + 0] + (ba_data[addr + 1] << 8) + (ba_data[addr + 2] << 16) + (ba_data[addr + 3] << 24) else: return self.x393_mem.read_mem(addr) if isinstance(port_afi, (unicode,str)): data_file = port_afi%channel # for simulated mode ba_data=bytearray() try: with open(data_file) as f: for l in f: line = l.strip() if line: dl = [] for item in line.split(): dl.append(int(item,16)) ba_data += bytearray(dl) if verbose > 0: print ("Read simulated sensor JPEG data from %s data file"%(data_file)) except: print("Failed to read data from ", data_file) return cirbuf_start = 0 circbuf_len = len(ba_data) print ("len(ba) = %d"%(len(ba_data))) if verbose > 1: for i in range(len(ba_data)): if not (i%16): print("\n%04x:"%(i),end="") print ("%02x "%(ba_data[i]),end="") else: ba_data = None if verbose > 0: print ("\n------------ channel %d --------------"%(channel)) 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) if ba_data: next_image = len(ba_data) else: next_image = self.afi_mux_get_image_pointer(port_afi = port_afi, channel = channel) # Bug - got 0x20 more than start of the new image 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)) len32 = 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, next_image = 0x%08x)"% (cirbuf_start + last_image_chunk + (0x20 - CCAM_MMAP_META_LENGTH) + 3,len32,next_image)) if verbose >0: for a in range ( next_image - (0x10 * num_lines_print), next_image + (0x10 * num_lines_print), 4): ## d = self.x393_mem.read_mem(cirbuf_start + a) d = read_mem(cirbuf_start + a) if (a % 16) == 0: print ("\n%08x: "%(a),end ="" ) print("%02x %02x %02x %02x "%(d & 0xff, (d >> 8) & 0xff, (d >> 16) & 0xff, (d >> 24) & 0xff), end = "") #Try noticed (but not yet identified) bug - reduce afi_mux_get_image_pointer result by 1 next_image -= 0x20 if next_image < 0: next_image += circbuf_len 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)) len32 = 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 CORRECTED offset 0x%08x - length word = 0x%08x, next_image = 0x%08x)"% (cirbuf_start + last_image_chunk + (0x20 - CCAM_MMAP_META_LENGTH) + 3,len32,next_image)) return None if verbose >0: print ("\n-----------reduced next frame byte pointer by 0x20 -------------") len32 &= 0xffffff # inserted_bytes = (32 - (((len32 % 32) + CCAM_MMAP_META) % 32)) % 32 #adjusting to actual... # ADJUSTMENT = 2 ADJUSTMENT = 4 # ??? inserted_bytes = ((32 - (((len32 % 32) + CCAM_MMAP_META) % 32) - ADJUSTMENT) % 32 ) + ADJUSTMENT img_start = last_image_chunk + 32 - CCAM_MMAP_META - inserted_bytes - len32 if img_start < 0: img_start += circbuf_len if verbose >0: for a in range ( img_start, img_start + (0x10 * num_lines_print), 4): ## d = self.x393_mem.read_mem(cirbuf_start + a) d = read_mem(cirbuf_start + a) if (a % 16) == 0: print ("\n%08x: "%(a),end ="" ) print("%02x %02x %02x %02x "%(d & 0xff, (d >> 8) & 0xff, (d >> 16) & 0xff, (d >> 24) & 0xff), end = "") print("\n...",end="") for a0 in range ( last_image_chunk - (0x10 * num_lines_print), last_image_chunk + 0x20, 4): a = a0 if (a < 0): a -=circbuf_len ## d = self.x393_mem.read_mem(cirbuf_start + a) d = read_mem(cirbuf_start + a) if (a % 16) == 0: print ("\n%08x: "%(a),end ="" ) print("%02x %02x %02x %02x "%(d & 0xff, (d >> 8) & 0xff, (d >> 16) & 0xff, (d >> 24) & 0xff), end = "") print() ## sec = self.x393_mem.read_mem(cirbuf_start + last_image_chunk + (0x20 - CCAM_MMAP_META_SEC)) sec = 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)) usec = read_mem(cirbuf_start + last_image_chunk + (0x20 - CCAM_MMAP_META_USEC)) fsec=sec + usec/1000000.0 try: tstr = time.strftime("%b %d %Y %H:%M:%S", time.gmtime(fsec)) except: tstr = "%f (0x%x, 0x%x)"%(fsec, sec,usec) print ("**** Bad timestamp = ",tstr) 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 ba_data: result["bindata"] = ba_data if verbose >0 : print ("Inserted bytes after image before meta = 0x%x"%(inserted_bytes)) print ("Image start (relative to cirbuf) = 0x%x, image length = 0x%x"%(img_start, len32 )) print ("Image time stamp = %s (%f)"%(tstr, fsec)) for i,s in enumerate(segments): print ("segment %d: start_address = 0x%x, length = 0x%x"%(i, 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, rst_chn): """ Reset selected input channels of selected AFI multiplexer @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) @param rst_chn - bit mask of channels to reset (persistent, needs release) """ self.x393_axi_tasks.write_control_register( vrlg.CMPRS_GROUP_ADDR + (vrlg.CMPRS_AFIMUX_RADDR0,vrlg.CMPRS_AFIMUX_RADDR1)[port_afi] + vrlg.CMPRS_AFIMUX_RST, rst_chn) def afi_mux_enable_chn (self, port_afi, en_chn, en): """ Enable/disable selected input channel of the selecte AFI multiplexer @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) @param en_chn - number of afi input channel to enable/disable (0..3) @param en - number enable (True) or disable (False) selected AFI input """ self.x393_axi_tasks.write_control_register( vrlg.CMPRS_GROUP_ADDR + (vrlg.CMPRS_AFIMUX_RADDR0,vrlg.CMPRS_AFIMUX_RADDR1)[port_afi] + vrlg.CMPRS_AFIMUX_EN, (2,3)[en] << (2 * en_chn)) def afi_mux_enable (self, port_afi, en): """ Enable/disable selected AFI multiplexer @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) @param en_chn - number of afi input channel to enable/disable (0..3) @param en - number enable (True) or disable (False) selected AFI input """ self.x393_axi_tasks.write_control_register( vrlg.CMPRS_GROUP_ADDR + (vrlg.CMPRS_AFIMUX_RADDR0,vrlg.CMPRS_AFIMUX_RADDR1)[port_afi] + vrlg.CMPRS_AFIMUX_EN, (2,3)[en] << (2 * 4)) def afi_mux_mode_chn (self, port_afi, chn, mode): """ Set mode of selected input channel of the selected AFI multiplexer @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) @param chn - number of afi input channel to program @param mode - readback mode: mode == 0 - show EOF pointer, internal mode == 1 - show EOF pointer, confirmed written to the system memory mode == 2 - show current pointer, internal mode == 3 - show current pointer, confirmed written to the system memory """ self.x393_axi_tasks.write_control_register( vrlg.CMPRS_GROUP_ADDR + (vrlg.CMPRS_AFIMUX_RADDR0,vrlg.CMPRS_AFIMUX_RADDR1)[port_afi] + vrlg.CMPRS_AFIMUX_MODE, (4 + (mode & 3)) << (4 * chn)) def afi_mux_chn_start_length(self, port_afi, chn, sa, length): """ Set mode of selected input channel of the selected AFI multiplexer @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) @param chn - number of afi input channel to program @param sa - start address in 32-byte chunks @param length - channel buffer length in 32-byte chunks """ reg_addr = vrlg.CMPRS_GROUP_ADDR + (vrlg.CMPRS_AFIMUX_RADDR0,vrlg.CMPRS_AFIMUX_RADDR1)[port_afi] + vrlg.CMPRS_AFIMUX_SA_LEN + chn self.x393_axi_tasks.write_control_register( reg_addr, sa) self.x393_axi_tasks.write_control_register( reg_addr + 4, length) def afi_mux_setup (self, port_afi, chn_mask, status_mode, # = 3, report_mode, # = 0, afi_cmprs0_sa, afi_cmprs0_len, afi_cmprs1_sa, afi_cmprs1_len, afi_cmprs2_sa, afi_cmprs2_len, afi_cmprs3_sa, afi_cmprs3_len, reset = False, verbose = 1): """ Set mode of selected input channel of the selected AFI multiplexer @param port_afi - number of AFI port (0 - afi 1, 1 - afi2) @param chn - number of afi input channel to program @param status_mode - status mode (3 for auto) @param report_mode - readback mode: mode == 0 - show EOF pointer, internal mode == 1 - show EOF pointer, confirmed written to the system memory mode == 2 - show current pointer, internal mode == 3 - show current pointer, confirmed written to the system memory @param afi_cmprs0_sa - input channel 0 start address in 32-byte chunks @param afi_cmprs0_len - input channel 0 buffer length in 32-byte chunks @param afi_cmprs1_sa - input channel 0 start address in 32-byte chunks @param afi_cmprs1_len - input channel 0 buffer length in 32-byte chunks @param afi_cmprs2_sa - input channel 0 start address in 32-byte chunks @param afi_cmprs2_len - input channel 0 buffer length in 32-byte chunks @param afi_cmprs3_sa - input channel 0 start address in 32-byte chunks @param afi_cmprs3_len - input channel 0 buffer length in 32-byte chunks @param reset - reset all channels @param verbose - verbose level """ if verbose >0 : print ("afi_mux_setup:") print ("AFI port (0/1) = ",port_afi) print ("AFI channel mask = 0x%x"%(chn_mask)) print ("status mode = ",status_mode) print ("report mode = ",report_mode) print ("channel 0 : 0x%08x/0x%08x"%(afi_cmprs0_sa * 32, afi_cmprs0_len * 32)) print ("channel 1 : 0x%08x/0x%08x"%(afi_cmprs1_sa * 32, afi_cmprs1_len * 32)) print ("channel 2 : 0x%08x/0x%08x"%(afi_cmprs2_sa * 32, afi_cmprs2_len * 32)) print ("channel 3 : 0x%08x/0x%08x"%(afi_cmprs3_sa * 32, afi_cmprs3_len * 32)) sa = (afi_cmprs0_sa, afi_cmprs1_sa, afi_cmprs2_sa, afi_cmprs3_sa) length = (afi_cmprs0_len, afi_cmprs1_len, afi_cmprs2_len, afi_cmprs3_len) for i in range(4): if (chn_mask >> i) & 1 : self.afi_mux_program_status (port_afi = port_afi, chn_afi = i, mode =status_mode, seq_num = 0) if reset: # reset all channels self.afi_mux_reset( port_afi = port_afi, rst_chn = 0xf) # reset all channels # release resets self.afi_mux_reset( port_afi = port_afi, rst_chn = 0) # release reset on all channels # set report mode (pointer type) - per status for i in range(4): if (chn_mask >> i) & 1 : self.afi_mux_mode_chn (port_afi = port_afi, chn = i, mode = report_mode) for i in range(4): if (not sa[i] is None) and (not length[i] is None): self.afi_mux_chn_start_length (port_afi = port_afi, chn = i, sa = sa[i], length = length[i]) # enable selected channels for i in range(4): if (chn_mask >> i) & 1 : self.afi_mux_enable_chn (port_afi = port_afi, en_chn = i, en = True) # enable the whole afi_mux module self.afi_mux_enable (port_afi = port_afi, en = True)