<commit_before>#!/usr/bin/env python3
#
# Copyright (c) 2014, <NAME>, LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import re
import time
from itertools import islice
from . import led_driver     # c extension that controls led matrices and contains framebuffer
import copy
import subprocess

# global variables for use
BITS_PER_PIXEL = 4     # 4 bits to represent color
DIM_OF_MATRIX = 8     # 8x8 led matrix elements
initialized = False   # flag to indicate if LED has been initialized
spi_initialized = False  # flag to indicate if SPI bus as been initialized
container_width = 0    # indicates the maximum width and height of the LEDContainer
container_height = 0
container_math_coords = True


def _init_check():
    """Checks that init_matrices has been called and throws an error if not
    @raise RuntimeError: If matrices have not been initialized."""
    global initialized
    if not initialized:
        raise RuntimeError("Matrices must be initialized first.")
    

def _valid_color(color):
    """Checks if given color is number between 0-16 if an int or 0-f, or - if string
    @param color: A color to check that is valid
    @type color: string or int
    """
    if type(color) == int:
        if color < 0x0 or color > 0x10:
            return False
        return True
    elif type(color) == str:
        if not re.match(r'^[A-Za-z0-9-]$', color):
            return False
        return True
    return False

def _convert_color(color):
    """Converts the given color to an int.
    @param color: A color to be converted
    @type color: string or int
    
    @raise ValueError: Fails L{_valid_color} check
    
    @return: Either the same int back again if color was an int or the int of a converted string
    @rtype: int
    """
    if not _valid_color(color):
        raise ValueError("Invalid Color: must be a string between 0-f or '-'" +  \
            " or a number 0-16 with 16 being transparent")
    if type(color) == int:
        return color
    elif type(color) == str:
        if color == '-':
            return 0x10
        return int(color, 16)
    raise RuntimeError("Invalid color")
    
def _convert_to_std_coords(x, y):
    """Converts given math coordinates to standard programming coordinates
    @param x: x coordinate in math coordinates
    @param y: y coordinate in math coordinates
    @rtype: tuple
    @return: (x,y) coordinates in standard programming coordinates"""
    return (x, (container_height - 1 - y))
    
def width():
    """
    @rtype: int
    @return: The number of pixels wide the led matrix display is.
    """
    return container_width
    
def height():
    """
    @rtype: int
    @return: The number of pixels hight the led matrix display is.
    """
    return container_height
    
def display_on_terminal():
    """Toggles on and off the terminal display of the led matrix on show()"""
    led_driver.display_on_terminal()

def init_matrices(mat_list=[(0,0,0)], math_coords=True, spi_speed=500000, spi_port=0):
    """Creates a chain of led matrices set at particular offsets into the frame buffer
    The order of the led matrices in the list indicate the order they are
    physically hooked up with the first one connected to Pi.
    
    @param mat_list: list of tuples that contains led matrix and offset
        ex: [(0,0,0),(7,0,90)]
    @type mat_list: list of size 2 or 3 tuples (mix or match)
    @param math_coords: True to use math coordinates, False to use programming coordinates
    @type math_coords: Boolean
    """
    global initialized
    global container_width
    global container_height
    global container_math_coords
    if initialized: # free previous memory before attempting to do it again
        cleanup()
                
    container_width = max([matrix[0] for matrix in mat_list]) + DIM_OF_MATRIX
    container_height = max([matrix[1] for matrix in mat_list]) + DIM_OF_MATRIX
    container_math_coords = math_coords
    if container_math_coords:
        for i in range(len(mat_list)):
            # convert y's to be standard programming coordinates
            # and also move origin from bottom left to top left of matrix
            if len(mat_list[i]) > 2:
                mat_list[i] = (mat_list[i][0], (container_height-1 - mat_list[i][1]) - (DIM_OF_MATRIX-1), mat_list[i][2])
            else:
                mat_list[i] = (mat_list[i][0], (container_height-1 - mat_list[i][1]) - (DIM_OF_MATRIX-1))
    led_driver.init_matrices(mat_list, len(mat_list), \
        container_width, container_height) # flatten out tuple
        
    # initialize spi bus
    global spi_initialized
    if not spi_initialized:
        led_driver.init_SPI(spi_speed, spi_port)
        spi_initialized = True
    
    initialized = True
    
def init_grid(num_rows=None, num_cols=None, angle=0, math_coords=True, spi_speed=500000, spi_port=0):
    """Initiallizes led matrices in a grid pattern with either a given number
    of rows and columns.
    If num_rows and num_cols is not given, it will detect the number of matrices you have
    and automatically set up a grid pattern with a max number of columns of 4.
    
    @param num_rows: Number of rows the grid is in (when angle == 0)
    @param num_cols: Number of columns the gird is in (when angle == 0)
    @param math_coords: True to use math coordinates, False to use programming coordinates
    @type math_coords: Boolean
    @param angle: Angle to rotate the coordinate system once initialized. (must be 90 degree multiple)
    @type angle: int
    
    @raise ValueError: num_rows*num_cols != number of matrices
    @raise ValueError: angle is not a multiple of 90
    """
    # initialize spi bus right away because we need it for led_driver.detect()
    global spi_initialized
    if not spi_initialized:
        led_driver.init_SPI(spi_speed, spi_port)
        spi_initialized = True
    
    # num_rows, and num_cols are before rotation
    # auto detect number of columns if none given
    num_matrices = led_driver.detect()
    if num_cols is None:
        if num_rows is None:
            # if number of rows not given assume max of 4 columns per row
            for cols in reversed(range(5)):  # should never hit zero
                rows = float(num_matrices)/cols
                if rows.is_integer():
                    num_rows = int(rows)
                    num_cols = cols
                    break
        else:
            num_cols = num_matrices/num_rows
    elif num_rows is None:
        raise ValueError("If you are providing num_cols you must also provide num_rows.")
    
    if num_cols*num_rows != num_matrices:  # safety check
        raise ValueError("Invalid number of rows and columns")
    
    if angle % 90 != 0:
        raise ValueError("Angle must be a multiple of 90.")<commit_msg>added support for large number of matrices if the user manually provides number of rows and columns<commit_after>#!/usr/bin/env python3
#
# Copyright (c) 2014, <NAME>, LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#       http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import os
import re
import time
from itertools import islice
from . import led_driver     # c extension that controls led matrices and contains framebuffer
import copy
import subprocess

# global variables for use
BITS_PER_PIXEL = 4     # 4 bits to represent color
DIM_OF_MATRIX = 8     # 8x8 led matrix elements
initialized = False   # flag to indicate if LED has been initialized
spi_initialized = False  # flag to indicate if SPI bus as been initialized
container_width = 0    # indicates the maximum width and height of the LEDContainer
container_height = 0
container_math_coords = True


def _init_check():
    """Checks that init_matrices has been called and throws an error if not
    @raise RuntimeError: If matrices have not been initialized."""
    global initialized
    if not initialized:
        raise RuntimeError("Matrices must be initialized first.")
    

def _valid_color(color):
    """Checks if given color is number between 0-16 if an int or 0-f, or - if string
    @param color: A color to check that is valid
    @type color: string or int
    """
    if type(color) == int:
        if color < 0x0 or color > 0x10:
            return False
        return True
    elif type(color) == str:
        if not re.match(r'^[A-Za-z0-9-]$', color):
            return False
        return True
    return False

def _convert_color(color):
    """Converts the given color to an int.
    @param color: A color to be converted
    @type color: string or int
    
    @raise ValueError: Fails L{_valid_color} check
    
    @return: Either the same int back again if color was an int or the int of a converted string
    @rtype: int
    """
    if not _valid_color(color):
        raise ValueError("Invalid Color: must be a string between 0-f or '-'" +  \
            " or a number 0-16 with 16 being transparent")
    if type(color) == int:
        return color
    elif type(color) == str:
        if color == '-':
            return 0x10
        return int(color, 16)
    raise RuntimeError("Invalid color")
    
def _convert_to_std_coords(x, y):
    """Converts given math coordinates to standard programming coordinates
    @param x: x coordinate in math coordinates
    @param y: y coordinate in math coordinates
    @rtype: tuple
    @return: (x,y) coordinates in standard programming coordinates"""
    return (x, (container_height - 1 - y))
    
def width():
    """
    @rtype: int
    @return: The number of pixels wide the led matrix display is.
    """
    return container_width
    
def height():
    """
    @rtype: int
    @return: The number of pixels hight the led matrix display is.
    """
    return container_height
    
def display_on_terminal():
    """Toggles on and off the terminal display of the led matrix on show()"""
    led_driver.display_on_terminal()

def init_matrices(mat_list=[(0,0,0)], math_coords=True, spi_speed=500000, spi_port=0):
    """Creates a chain of led matrices set at particular offsets into the frame buffer
    The order of the led matrices in the list indicate the order they are
    physically hooked up with the first one connected to Pi.
    
    @param mat_list: list of tuples that contains led matrix and offset
        ex: [(0,0,0),(7,0,90)]
    @type mat_list: list of size 2 or 3 tuples (mix or match)
    @param math_coords: True to use math coordinates, False to use programming coordinates
    @type math_coords: Boolean
    """
    global initialized
    global container_width
    global container_height
    global container_math_coords
    if initialized: # free previous memory before attempting to do it again
        cleanup()
                
    container_width = max([matrix[0] for matrix in mat_list]) + DIM_OF_MATRIX
    container_height = max([matrix[1] for matrix in mat_list]) + DIM_OF_MATRIX
    container_math_coords = math_coords
    if container_math_coords:
        for i in range(len(mat_list)):
            # convert y's to be standard programming coordinates
            # and also move origin from bottom left to top left of matrix
            if len(mat_list[i]) > 2:
                mat_list[i] = (mat_list[i][0], (container_height-1 - mat_list[i][1]) - (DIM_OF_MATRIX-1), mat_list[i][2])
            else:
                mat_list[i] = (mat_list[i][0], (container_height-1 - mat_list[i][1]) - (DIM_OF_MATRIX-1))
    led_driver.init_matrices(mat_list, len(mat_list), \
        container_width, container_height) # flatten out tuple
        
    # initialize spi bus
    global spi_initialized
    if not spi_initialized:
        led_driver.init_SPI(spi_speed, spi_port)
        spi_initialized = True
    
    initialized = True
    
def init_grid(num_rows=None, num_cols=None, angle=0, math_coords=True, spi_speed=500000, spi_port=0):
    """Initiallizes led matrices in a grid pattern with either a given number
    of rows and columns.
    If num_rows and num_cols is not given, it will detect the number of matrices you have
    and automatically set up a grid pattern with a max number of columns of 4.
    
    @param num_rows: Number of rows the grid is in (when angle == 0)
    @param num_cols: Number of columns the gird is in (when angle == 0)
    @param math_coords: True to use math coordinates, False to use programming coordinates
    @type math_coords: Boolean
    @param angle: Angle to rotate the coordinate system once initialized. (must be 90 degree multiple)
    @type angle: int
    
    @raise ValueError: num_rows*num_cols != number of matrices
    @raise ValueError: angle is not a multiple of 90
    """
    # initialize spi bus right away because we need it for led_driver.detect()
    global spi_initialized
    if not spi_initialized:
        led_driver.init_SPI(spi_speed, spi_port)
        spi_initialized = True
    

    if num_cols is None:
        # num_rows, and num_cols are before rotation
        # auto detect number of columns if none given
        num_matrices = led_driver.detect()
        if num_rows is None:
            # if number of rows not given assume max of 4 columns per row
            for cols in reversed(range(5)):  # should never hit zero
                rows = float(num_matrices)/cols
                if rows.is_integer():
                    num_rows = int(rows)
                    num_cols = cols
                    break
        else:
            num_cols = num_matrices/num_rows
            
        if num_cols*num_rows != num_matrices:  # safety check
          raise ValueError("Invalid number of rows and columns")
    
    elif num_rows is None:
        raise ValueError("If you are providing num_cols you must also provide num_rows.")
    

    if angle % 90 != 0:
        raise ValueError("Angle must be a multiple of 90.")
{'fraction_non_alphanumeric': 0.07238405649487337, 'fraction_numerical': 0.012494058531948123, 'mean_word_length': 2.805684754521964, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1656722', 'n_tokens_mistral': 4257, 'n_tokens_neox': 4138, 'n_words': 1719}