x393_cmprs.py 31.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
from __future__ import division
from __future__ import print_function

'''
# Copyright (C) 2015, Elphel.inc.
# Class to control JPEG/JP4 compressor  
# 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 <http:#www.gnu.org/licenses/>.

@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_utils

#import time
import vrlg
42
import x393_mcntrl
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
class X393Cmprs(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
    
61 62 63 64 65 66 67 68 69 70 71
    def program_status_compressor(self,
                                  cmprs_chn,
                                  mode,     # input [1:0] mode;
                                  seq_num): # input [5:0] seq_num;
        """
        Set status generation mode for selected compressor channel
        @param cmprs_chn - number of the compressor channel (0..3)
        @param mode -       status generation mode:
                                  0: disable status generation,
                                  1: single status request,
                                  2: auto status, keep specified seq number,
72
                                  3: auto, inc sequence number 
73 74 75 76 77 78 79 80
        @param seq_number - 6-bit sequence number of the status message to be sent
        """

        self.x393_axi_tasks.program_status (
                             vrlg.CMPRS_GROUP_ADDR  + cmprs_chn * vrlg.CMPRS_BASE_INC,
                             vrlg.CMPRS_STATUS_CNTRL,
                             mode,
                             seq_num)# //MCONTR_PHY_STATUS_REG_ADDR=          'h0,
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 111 112 113 114 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
    def func_compressor_format (self,
                                num_macro_cols_m1,
                                num_macro_rows_m1,
                                left_margin):
        """
        @param num_macro_cols_m1 - number of macroblock colums minus 1
        @param num_macro_rows_m1 - number of macroblock rows minus 1
        @param left_margin - left margin of the first pixel (0..31) for 32-pixel wide colums in memory access
        @return combined compressor format data word
        """
        data = 0;
        data |=(num_macro_cols_m1 & ((1 << vrlg.CMPRS_FRMT_MBCM1_BITS) - 1))  << vrlg.CMPRS_FRMT_MBCM1
        data |=(num_macro_rows_m1 & ((1 << vrlg.CMPRS_FRMT_MBRM1_BITS) - 1))  << vrlg.CMPRS_FRMT_MBRM1
        data |=(left_margin &       ((1 << vrlg.CMPRS_FRMT_LMARG_BITS) - 1))  << vrlg.CMPRS_FRMT_LMARG
        return data
        
    def func_compressor_color_saturation (self,
                                colorsat_blue,
                                colorsat_red):
        """
        @param colorsat_blue - color saturation for blue (10 bits), 0x90 for 100%
        @param colorsat_red -  color saturation for red (10 bits), 0xb6 for 100%
        @return combined compressor format data word
        """
        data = 0;
        data |=(colorsat_blue & ((1 << vrlg.CMPRS_CSAT_CB_BITS) - 1))  << vrlg.CMPRS_CSAT_CB
        data |=(colorsat_red &  ((1 << vrlg.CMPRS_CSAT_CR_BITS) - 1))  << vrlg.CMPRS_CSAT_CR
        return data
    def func_compressor_control (self,
                                 run_mode =    None,
                                 qbank =       None,
                                 dc_sub =      None,
                                 cmode =       None,
                                 multi_frame = None,
                                 bayer =       None,
                                 focus_mode =  None):
        """
        Combine compressor control parameters into a single word. None value preserves old setting for the parameter
        @param run_mode -    0 - reset, 2 - run single from memory, 3 - run repetitive
        @param qbank -       quantization table page (0..15)
        @param dc_sub -      True - subtract DC before running DCT, False - no subtraction, convert as is,
        @param cmode -       color mode:
                                CMPRS_CBIT_CMODE_JPEG18 =          0 - color 4:2:0
                                CMPRS_CBIT_CMODE_MONO6 =           1 - mono 4:2:0 (6 blocks)
                                CMPRS_CBIT_CMODE_JP46 =            2 - jp4, 6 blocks, original
                                CMPRS_CBIT_CMODE_JP46DC =          3 - jp4, 6 blocks, dc -improved
                                CMPRS_CBIT_CMODE_JPEG20 =          4 - mono, 4 blocks (but still not actual monochrome JPEG as the blocks are scanned in 2x2 macroblocks)
                                CMPRS_CBIT_CMODE_JP4 =             5 - jp4,  4 blocks, dc-improved
                                CMPRS_CBIT_CMODE_JP4DC =           6 - jp4,  4 blocks, dc-improved
                                CMPRS_CBIT_CMODE_JP4DIFF =         7 - jp4,  4 blocks, differential
                                CMPRS_CBIT_CMODE_JP4DIFFHDR =      8 - jp4,  4 blocks, differential, hdr
                                CMPRS_CBIT_CMODE_JP4DIFFDIV2 =     9 - jp4,  4 blocks, differential, divide by 2
                                CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 = 10 - jp4,  4 blocks, differential, hdr,divide by 2
                                CMPRS_CBIT_CMODE_MONO1 =          11 -  mono JPEG (not yet implemented)
                                CMPRS_CBIT_CMODE_MONO4 =          14 -  mono 4 blocks
        @param multi_frame -  False - single-frame buffer, True - multi-frame video memory buffer,
        @param bayer -        Bayer shift (0..3)
        @param focus_mode -   focus mode - how to combine image with "focus quality" in the result image 
        @return               combined data word
        """
        data = 0;
        if not run_mode is None:
143
            data |= (1 << vrlg.CMPRS_CBIT_RUN)
144 145 146
            data |= (run_mode & ((1 << vrlg.CMPRS_CBIT_RUN_BITS) - 1)) << (vrlg.CMPRS_CBIT_RUN - vrlg.CMPRS_CBIT_RUN_BITS)
                     
        if not qbank is None:
147
            data |= (1 << vrlg.CMPRS_CBIT_QBANK)
148 149 150
            data |= (qbank & ((1 << vrlg.CMPRS_CBIT_QBANK_BITS) - 1)) << (vrlg.CMPRS_CBIT_QBANK - vrlg.CMPRS_CBIT_QBANK_BITS)

        if not dc_sub is None:
151
            data |= (1 << vrlg.CMPRS_CBIT_DCSUB)
152 153 154
            data |= (dc_sub & ((1 << vrlg.CMPRS_CBIT_DCSUB_BITS) - 1)) << (vrlg.CMPRS_CBIT_DCSUB - vrlg.CMPRS_CBIT_DCSUB_BITS)

        if not cmode is None:
155
            data |= (1 << vrlg.CMPRS_CBIT_CMODE)
156 157 158
            data |= (cmode & ((1 << vrlg.CMPRS_CBIT_CMODE_BITS) - 1)) << (vrlg.CMPRS_CBIT_CMODE - vrlg.CMPRS_CBIT_CMODE_BITS)
                     
        if not multi_frame is None:
159
            data |= (1 << vrlg.CMPRS_CBIT_FRAMES)
160 161 162
            data |= (multi_frame & ((1 << vrlg.CMPRS_CBIT_FRAMES_BITS) - 1)) << (vrlg.CMPRS_CBIT_FRAMES - vrlg.CMPRS_CBIT_FRAMES_BITS)
                     
        if not bayer is None:
163
            data |= (1 << vrlg.CMPRS_CBIT_BAYER)
164 165 166
            data |= (bayer & ((1 << vrlg.CMPRS_CBIT_BAYER_BITS) - 1)) << (vrlg.CMPRS_CBIT_BAYER - vrlg.CMPRS_CBIT_BAYER_BITS)
                     
        if not focus_mode is None:
167
            data |= (1 << vrlg.CMPRS_CBIT_FOCUS)
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
            data |= (focus_mode & ((1 << vrlg.CMPRS_CBIT_FOCUS_BITS) - 1)) << (vrlg.CMPRS_CBIT_FOCUS - vrlg.CMPRS_CBIT_FOCUS_BITS)
        return data
    
    def compressor_format (self,
                           chn,
                           num_macro_cols_m1,
                           num_macro_rows_m1,
                           left_margin):
        """
        @param chn -               compressor channel number
        @param num_macro_cols_m1 - number of macroblock colums minus 1
        @param num_macro_rows_m1 - number of macroblock rows minus 1
        @param left_margin - left margin of the first pixel (0..31) for 32-pixel wide colums in memory access
        """
        data = self.func_compressor_format (num_macro_cols_m1 = num_macro_cols_m1,
                                            num_macro_rows_m1 = num_macro_rows_m1,
                                            left_margin =       left_margin)
185
        self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR +  chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_FORMAT,
186 187 188 189 190 191 192 193 194 195 196 197 198
                                                  data)

    def compressor_color_saturation (self,
                                     chn,
                                     colorsat_blue,
                                     colorsat_red):
        """
        @param chn -           compressor channel number
        @param colorsat_blue - color saturation for blue (10 bits), 0x90 for 100%
        @param colorsat_red -  color saturation for red (10 bits), 0xb6 for 100%
        """
        data = self.func_compressor_color_saturation (colorsat_blue = colorsat_blue,
                                                      colorsat_red = colorsat_red)
199
        self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR +  chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_COLOR_SATURATION,
200 201 202 203 204 205 206 207 208 209
                                                  data)

    def compressor_coring (self,
                           chn,
                           coring):
        """
        @param chn -    compressor channel number
        @param coring - coring value
        """
        data = coring & ((1 << vrlg.CMPRS_CORING_BITS) - 1)
210
        self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR +  chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_CORING_MODE,
211 212 213 214 215 216 217 218 219 220 221 222 223
                                                  data)

    def compressor_control (self,
                            chn,
                            run_mode =    None,
                            qbank =       None,
                            dc_sub =      None,
                            cmode =       None,
                            multi_frame = None,
                            bayer =       None,
                            focus_mode =  None):
        """
        Combine compressor control parameters into a single word. None value preserves old setting for the parameter
224
        @param chn -         compressor channel number, "a" or "all" - same for all 4 channels
225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
        @param run_mode -    0 - reset, 2 - run single from memory, 3 - run repetitive
        @param qbank -       quantization table page (0..15)
        @param dc_sub -      True - subtract DC before running DCT, False - no subtraction, convert as is,
        @param cmode -       color mode:
                                CMPRS_CBIT_CMODE_JPEG18 =          0 - color 4:2:0
                                CMPRS_CBIT_CMODE_MONO6 =           1 - mono 4:2:0 (6 blocks)
                                CMPRS_CBIT_CMODE_JP46 =            2 - jp4, 6 blocks, original
                                CMPRS_CBIT_CMODE_JP46DC =          3 - jp4, 6 blocks, dc -improved
                                CMPRS_CBIT_CMODE_JPEG20 =          4 - mono, 4 blocks (but still not actual monochrome JPEG as the blocks are scanned in 2x2 macroblocks)
                                CMPRS_CBIT_CMODE_JP4 =             5 - jp4,  4 blocks, dc-improved
                                CMPRS_CBIT_CMODE_JP4DC =           6 - jp4,  4 blocks, dc-improved
                                CMPRS_CBIT_CMODE_JP4DIFF =         7 - jp4,  4 blocks, differential
                                CMPRS_CBIT_CMODE_JP4DIFFHDR =      8 - jp4,  4 blocks, differential, hdr
                                CMPRS_CBIT_CMODE_JP4DIFFDIV2 =     9 - jp4,  4 blocks, differential, divide by 2
                                CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 = 10 - jp4,  4 blocks, differential, hdr,divide by 2
                                CMPRS_CBIT_CMODE_MONO1 =          11 -  mono JPEG (not yet implemented)
                                CMPRS_CBIT_CMODE_MONO4 =          14 -  mono 4 blocks
        @param multi_frame -  False - single-frame buffer, True - multi-frame video memory buffer,
        @param bayer -        Bayer shift (0..3)
        @param focus_mode -   focus mode - how to combine image with "focus quality" in the result image 
        """
246 247 248 249 250 251 252 253 254 255 256 257 258 259
        try:
            if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
                for chn in range(4):
                    self.compressor_control (chn =         chn,
                                             run_mode =    run_mode,
                                             qbank =       qbank,
                                             dc_sub =      dc_sub,
                                             cmode =       cmode,
                                             multi_frame = multi_frame,
                                             bayer =       bayer,
                                             focus_mode =  focus_mode)
                return
        except:
            pass
260 261 262 263 264 265 266 267
        data = self.func_compressor_control(
                            run_mode =    run_mode,
                            qbank =       qbank,
                            dc_sub =      dc_sub,
                            cmode =       cmode,
                            multi_frame = multi_frame,
                            bayer =       bayer,
                            focus_mode =  focus_mode)
268
        self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR +  chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_CONTROL_REG,
269
                                                  data)
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
        
    def compressor_interrupt_control (self,
                                      chn,
                                      cntrl = "clr"):
        """
        Control compressor interrupts
        @param chn -      compressor channel number, "a" or "all" - same for all 4 channels
        @param cntrl -    "clr" - clear, "en" - enable, "dis" - disable
        """
#        print("compressor_interrupt_control(",chn,", ",cntrl,")")
        try:
            if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
                for chn in range(4):
                    self.compressor_interrupt_control (chn =      chn,
                                                     cntrl =    cntrl)
                return
        except:
            pass
        if cntrl.lower() == "clr":
            data = 1
        elif cntrl.lower() == "dis":
            data = 2
        elif cntrl.lower() == "en":
            data = 3
        else:
            print ("compressor_interrupts(): invalid control mode: %s, only 'clr', 'en' and 'dis' are accepted"%(str(cntrl)))
            return
        self.x393_axi_tasks.write_control_register(vrlg.CMPRS_GROUP_ADDR +  chn * vrlg.CMPRS_BASE_INC + vrlg.CMPRS_INTERRUPTS,
                                                  data)        
    def compressor_interrupt_acknowledge (self, enabledOnly=True):
        """
        Clear (one of) raised compressor interrupts
        @param enabledOnly consider only channels with interrupts enabled
        @return number of cleared interrupt, None if none was set 
        """
        d = 0 if enabledOnly else 2
        for chn in range(4):
            if ((self.get_status_compressor(chn) | d) & 3) == 3: # both request and mask are set
                self.compressor_interrupt_control(chn, "clr")
                return chn
        return None    
        
    def get_status_compressor ( self,
                                chn="All"):
        """
        Read compressor status word
        @param chn - compressor port (0..3)
        @return status word
        """
        try:
            if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
                rslt = []
                for chn in range(4):
                    rslt.append(self.get_status_compressor (chn = chn))
                return rslt
        except:
            pass
        return self.x393_axi_tasks.read_status(
                    address=(vrlg.CMPRS_STATUS_REG_BASE + chn * vrlg.CMPRS_STATUS_REG_INC))       

    def get_highfreq_compressor ( self,
                                chn="All"):
        """
        Read total high frequency amount from the compressor
        @param chn - compressor port (0..3)
        @return status word
        """
        try:
            if (chn == all) or (chn[0].upper() == "A"): #all is a built-in function
                rslt = []
                for chn in range(4):
                    rslt.append(self.get_highfreq_compressor (chn = chn))
                return rslt
        except:
            pass
        return self.x393_axi_tasks.read_status(
                    address=(vrlg.CMPRS_HIFREQ_REG_BASE + num_sensor * vrlg.CMPRS_STATUS_REG_INC))       

348 349 350 351 352

    def control_compressor_memory(self,
                              num_sensor,
                              command,
                              reset_frame = False,
353
                              copy_frame = False,
354
                              abort_late = False,
355 356 357 358 359 360 361 362 363
                              verbose = 1):
        """
        Control memory access (write) of a sensor channel
        @param num_sensor - memory sensor channel (or all)
        @param command -    one of (case insensitive):
               reset       - reset channel, channel pointers immediately,
               stop        - stop at the end of the frame (if repetitive),
               single      - acquire single frame ,
               repetitive  - repetitive mode
364
        @param reset_frame - reset frame number
365 366
        @param copy_frame  - copy frame number from the master channel (non-persistent)
        @param abort_late  -  abort frame r/w at the next frame sync, if not finished. Wait for pending memory transfers
367 368 369 370 371 372 373 374 375
        @param vebose -      verbose level       
        """
        try:
            if (num_sensor == all) or (num_sensor[0].upper() == "A"): #all is a built-in function
                for num_sensor in range(4):
                    print ('num_sensor = ',num_sensor)
                    self.control_compressor_memory(num_sensor = num_sensor,
                                                   command =    command,
                                                   reset_frame = reset_frame,
376
                                                   copy_frame = copy_frame,
377
                                                   abort_late = abort_late,
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414
                                                   verbose =    verbose)
                return
        except:
            pass
        
        
        rpt =    False
        sngl =   False
        en =     False
        rst =    False
        byte32 = True
        if command[:3].upper() ==   'RES':
            rst = True
        elif command[:2].upper() == 'ST':
            pass
        elif command[:2].upper() == 'SI':
            sngl = True
            en =   True
        elif command[:3].upper() == 'REP':
            rpt =  True
            en =   True
        else:
            print ("Unrecognized command %s. Valid commands are RESET, STOP, SINGLE, REPETITIVE"%(command))
            return    
                                
        base_addr = vrlg.MCONTR_CMPRS_BASE + vrlg.MCONTR_CMPRS_INC * num_sensor;
        mode=   x393_mcntrl.func_encode_mode_scan_tiled(
                                   skip_too_late = True,                     
                                   disable_need = False,
                                   repetitive=    rpt,
                                   single =       sngl,
                                   reset_frame =  reset_frame,
                                   byte32 =       byte32,
                                   keep_open =    False,
                                   extra_pages =  0,
                                   write_mem =    False,
                                   enable =       en,
415
                                   chn_reset =    rst,
416 417
                                   copy_frame = copy_frame,
                                   abort_late =   abort_late)
418 419 420 421 422 423 424
        
        self.x393_axi_tasks.write_control_register(base_addr + vrlg.MCNTRL_TILED_MODE,  mode) 
        if verbose > 0 :
            print ("write_control_register(0x%08x, 0x%08x)"%(base_addr + vrlg.MCNTRL_TILED_MODE,  mode))



425
        
426 427 428 429 430 431 432 433 434 435 436 437
    def setup_compressor_memory (self,
                                 num_sensor,
                                 frame_sa,
                                 frame_sa_inc,
                                 last_frame_num,
                                 frame_full_width,
                                 window_width,
                                 window_height,
                                 window_left,
                                 window_top,
                                 byte32,
                                 tile_width,
438 439
                                 tile_vstep, # = 16
                                 tile_height, #= 18
440
                                 extra_pages,
441 442
                                 disable_need,
                                 abort_late = False):
443 444 445 446 447 448 449 450 451 452 453 454 455
        """
        Setup memory controller for a compressor channel
        @param num_sensor -       sensor port number (0..3)
        @param frame_sa -         22-bit frame start address ((3 CA LSBs==0. BA==0)
        @param frame_sa_inc -     22-bit frame start address increment  ((3 CA LSBs==0. BA==0)
        @param last_frame_num -   16-bit number of the last frame in a buffer
        @param frame_full_width - 13-bit Padded line length (8-row increment), in 8-bursts (16 bytes)
        @param window_width -     13-bit - in 8*16=128 bit bursts
        @param window_height -    16-bit window height (in scan lines)
        @param window_left -      13-bit window left margin in 8-bursts (16 bytes)
        @param window_top -       16-bit window top margin (in scan lines
        @param byte32 -           32-byte columns
        @param tile_width         tile width,
456 457
        @param tile_vstep         tile vertical step in pixel rows (JPEG18/jp4 = 16)
        @param tile_height        tile height: 18 for color JPEG, 16 fore JP$ flavors,
458
        @param extra_pages        extra pages needed (1)
459
        @param disable_need       disable need (preference to sensor channels - they can not wait
460
        @param abort_late         abort frame r/w at the next frame sync, if not finished. Wait for pending memory transfers
461
        """
462 463
#        tile_vstep = 16
#        tile_height= 18
464 465
        base_addr = vrlg.MCONTR_CMPRS_BASE + vrlg.MCONTR_CMPRS_INC * num_sensor;
        mode=   x393_mcntrl.func_encode_mode_scan_tiled(
466
                                   skip_too_late = False,
467 468 469
                                   disable_need = disable_need,
                                   repetitive=    True,
                                   single =       False,
470
                                   reset_frame =  True, # Now needed to propagate start address False,
471 472 473 474 475
                                   byte32 =       byte32,
                                   keep_open =    False,
                                   extra_pages =  extra_pages,
                                   write_mem =    False,
                                   enable =       True,
476 477
                                   chn_reset =    False,
                                   abort_late =   abort_late)
478
        self.x393_axi_tasks.write_control_register(
479 480
                                    base_addr + vrlg.MCNTRL_TILED_STARTADDR,
                                    frame_sa) # RA=80, CA=0, BA=0 22-bit frame start address (3 CA LSBs==0. BA==0)
481
        self.x393_axi_tasks.write_control_register(
482 483
                                    base_addr + vrlg.MCNTRL_TILED_FRAME_SIZE,
                                    frame_sa_inc)
484
        self.x393_axi_tasks.write_control_register(
485 486
                                    base_addr + vrlg.MCNTRL_TILED_FRAME_LAST,
                                    last_frame_num)
487
        self.x393_axi_tasks.write_control_register(
488 489
                                    base_addr + vrlg.MCNTRL_TILED_FRAME_FULL_WIDTH,
                                    frame_full_width)
490
        self.x393_axi_tasks.write_control_register(
491 492
                                    base_addr + vrlg.MCNTRL_TILED_WINDOW_WH,
                                    ((window_height & 0xffff) << 16) | (window_width & 0xffff)) #/WINDOW_WIDTH + (WINDOW_HEIGHT<<16));
493
        self.x393_axi_tasks.write_control_register(
494 495
                                    base_addr + vrlg.MCNTRL_TILED_WINDOW_X0Y0,
                                    ((window_top & 0xffff) << 16) | (window_left & 0xffff)) #WINDOW_X0+ (WINDOW_Y0<<16));
496
        self.x393_axi_tasks.write_control_register(
497 498
                                    base_addr + vrlg.MCNTRL_TILED_WINDOW_STARTXY,
                                    0)
499
        self.x393_axi_tasks.write_control_register(
500 501
                                    base_addr + vrlg.MCNTRL_TILED_TILE_WHS,
                                    ((tile_vstep & 0xff) <<16) | ((tile_height & 0xff) <<8) | (tile_width & 0xff)) #//(tile_height<<8)+(tile_vstep<<16));
502
        self.x393_axi_tasks.write_control_register(
503 504
                                    base_addr + vrlg.MCNTRL_TILED_MODE,
                                    mode); 
505 506 507 508 509 510 511 512 513 514 515
#    def compressor_run(self, # may use compressor_control with the same arguments
#                       num_sensor,
#                       run_mode):
#        """
#        Compressor reset.run/single (alias of compressor_control) 
#        @param num_sensor -       sensor port number (0..3)
#        @param run_mode -    0 - reset, 2 - run single from memory, 3 - run repetitive
#        """
#        self.compressor_control(
#            num_sensor = num_sensor,  # sensor channel number (0..3)
#            run_mode = run_mode)      #0 - reset, 2 - run single from memory, 3 - run repetitive
516 517
        
    def setup_compressor_channel (self,
518
                                  chn,
519 520 521 522 523 524 525 526 527 528 529 530 531 532
                                  qbank,
                                  dc_sub,
                                  cmode,
                                  multi_frame,
                                  bayer,
                                  focus_mode,
                                  num_macro_cols_m1,
                                  num_macro_rows_m1,
                                  left_margin,
                                  colorsat_blue,
                                  colorsat_red,
                                  coring,
                                  verbose=0):
        """
533
        @param chn -        compressor channel (0..3)
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562
        @param qbank -       quantization table page (0..15)
        @param dc_sub -      True - subtract DC before running DCT, False - no subtraction, convert as is,
        @param cmode -       color mode:
                                CMPRS_CBIT_CMODE_JPEG18 =          0 - color 4:2:0
                                CMPRS_CBIT_CMODE_MONO6 =           1 - mono 4:2:0 (6 blocks)
                                CMPRS_CBIT_CMODE_JP46 =            2 - jp4, 6 blocks, original
                                CMPRS_CBIT_CMODE_JP46DC =          3 - jp4, 6 blocks, dc -improved
                                CMPRS_CBIT_CMODE_JPEG20 =          4 - mono, 4 blocks (but still not actual monochrome JPEG as the blocks are scanned in 2x2 macroblocks)
                                CMPRS_CBIT_CMODE_JP4 =             5 - jp4,  4 blocks, dc-improved
                                CMPRS_CBIT_CMODE_JP4DC =           6 - jp4,  4 blocks, dc-improved
                                CMPRS_CBIT_CMODE_JP4DIFF =         7 - jp4,  4 blocks, differential
                                CMPRS_CBIT_CMODE_JP4DIFFHDR =      8 - jp4,  4 blocks, differential, hdr
                                CMPRS_CBIT_CMODE_JP4DIFFDIV2 =     9 - jp4,  4 blocks, differential, divide by 2
                                CMPRS_CBIT_CMODE_JP4DIFFHDRDIV2 = 10 - jp4,  4 blocks, differential, hdr,divide by 2
                                CMPRS_CBIT_CMODE_MONO1 =          11 -  mono JPEG (not yet implemented)
                                CMPRS_CBIT_CMODE_MONO4 =          14 -  mono 4 blocks
        @param multi_frame -  False - single-frame buffer, True - multi-frame video memory buffer,
        @param bayer -        Bayer shift (0..3)
        @param focus_mode -   focus mode - how to combine image with "focus quality" in the result image 
        @param num_macro_cols_m1 - number of macroblock colums minus 1
        @param num_macro_rows_m1 - number of macroblock rows minus 1
        @param left_margin - left margin of the first pixel (0..31) for 32-pixel wide colums in memory access
        @param colorsat_blue - color saturation for blue (10 bits), 0x90 for 100%
        @param colorsat_red -  color saturation for red (10 bits), 0xb6 for 100%
        @param coring - coring value
        @param verbose - verbose level
        """
        if verbose > 0:
            print("COMPRESSOR_SETUP")
563
            print (   "num_sensor = ",chn)
564 565 566 567 568 569 570
            print (   "qbank = ",qbank)
            print (   "dc_sub = ",dc_sub)
            print (   "cmode = ",cmode)
            print (   "multi_frame = ",multi_frame)
            print (   "bayer = ",bayer)
            print (   "focus_mode = ",focus_mode)
        self.compressor_control(
571
            chn =         chn,         # compressor channel number (0..3)
572 573 574 575 576
            qbank =       qbank,       # [6:3] quantization table page
            dc_sub =      dc_sub,      # [8:7] subtract DC
            cmode =       cmode,       #  [13:9] color mode:
            multi_frame = multi_frame, # [15:14] 0 - single-frame buffer, 1 - multiframe video memory buffer
            bayer =       bayer,       # [20:18] # Bayer shift
577
            focus_mode =  focus_mode)  # [23:21] Set focus mode
578 579
            
        self.compressor_format(
580
            chn =               chn,        # compressor channel number (0..3)
581 582 583 584 585
            num_macro_cols_m1 = num_macro_cols_m1, # number of macroblock colums minus 1
            num_macro_rows_m1 = num_macro_rows_m1, # number of macroblock rows minus 1
            left_margin =       left_margin)      # left margin of the first pixel (0..31) for 32-pixel wide colums in memory access
    
        self.compressor_color_saturation(
586
            chn =           chn,           # compressor channel number (0..3)
587
            colorsat_blue = colorsat_blue, # color saturation for blue (10 bits) #'h90 for 100%
588
            colorsat_red =  colorsat_red)  # color saturation for red (10 bits)   # 'b6 for 100%
589 590

        self.compressor_coring(
591
            chn =        chn,           # compressor channel number (0..3)
592 593 594
            coring =     coring);       # coring value