#
# This file is autogenerated, do not edit manually. Instead,
# edit gen/CANifier_data.yml
#

import typing

from hal_impl.data import hal_data, NotifyDict

from .ctre_sim_enums import ErrorCode


class CANifier:

    def __init__(self):
        self.create_called = False

    def _create1(self, deviceNumber: int) -> None:
        assert isinstance(deviceNumber, int)
        assert deviceNumber not in hal_data['CAN']
        self.hal_data = NotifyDict({
            'type': 'canifier',
            
            'bus_voltage': 12.0,
            
            'general_pin_outputs': 0x00,
            'general_pin_inputs': 0x00,
            'general_pin_is_output': 0x00,
            
            'led_a': 0.0,
            'led_b': 0.0,
            'led_c': 0.0,
            
            'last_error': ErrorCode.OK,
            
            'quad_position': 0,
            'quad_velocity': 0,
            
            'reset_occurred': False,
        })

        for i in range(4):
          self.hal_data.update({
            'pwm_%d' % i: 0.0042,
            'pwm_%d_en' % i: False,
            'pwm_%d_period' % i: 0.0042, # What's the default?
          })

        self._ledmap = {
          self.LEDChannel.A: 'led_a',
          self.LEDChannel.B: 'led_b',
          self.LEDChannel.C: 'led_c'
        }

        self._statusMap = {
          self.StatusFrame.Status_1_General: 'status_1_period',
          self.StatusFrame.Status_2_General: 'status_2_period',
          self.StatusFrame.Status_3_PwmInputs0: 'status_3_period',
          self.StatusFrame.Status_4_PwmInputs1: 'status_4_period',
          self.StatusFrame.Status_5_PwmInputs2: 'status_5_period',
          self.StatusFrame.Status_6_PwmInputs3: 'status_6_period',
          self.StatusFrame.Status_8_Misc: 'status_8_period',
        }

        for v in self._statusMap.values():
          self.hal_data[v] = 0.001 # What's the default?

        self._controlMap = {
          self.ControlFrame.CANifier_Control_1_General: 'control_1',
          self.ControlFrame.CANifier_Control_2_PwmOutput: 'control_2',
        }
          
        for v in self._controlMap.values():
          self.hal_data[v] = 0.001 # What's the default?

        hal_data['CAN'][deviceNumber] = self.hal_data

    def setLEDOutput(self, dutyCycle: int, ledChannel: int) -> ErrorCode:
        '''Sets the LED Output

        :param percentOutput: Output duty cycle expressed as percentage.
        :param ledChannel: Channel to set the output of.

        '''
        assert isinstance(dutyCycle, int) and dutyCycle < 4294967296 and dutyCycle >= 0
        assert isinstance(ledChannel, int) and ledChannel < 4294967296 and ledChannel >= 0
        retval = ErrorCode.OK
        self.hal_data[self._ledmap[ledChannel]] = dutyCycle / 1023
        assert isinstance(retval, ErrorCode)
        return retval

    def setGeneralOutputs(self, outputsBits: int, isOutputBits: int) -> ErrorCode:
        '''Sets the output of all General Pins

        :param outputBits: A bit mask of all the output states.  LSB->MSB is in the order of the #GeneralPin enum.
        :param isOutputBits: A boolean bit mask that sets the pins to be outputs or inputs.  A bit of 1 enables output.

        '''
        assert isinstance(outputsBits, int) and outputsBits < 4294967296 and outputsBits >= 0
        assert isinstance(isOutputBits, int) and isOutputBits < 4294967296 and isOutputBits >= 0
        retval = ErrorCode.OK
        self.hal_data['general_pin_outputs'] = outputsBits
        self.hal_data['general_pin_is_output'] = isOutputBits
        assert isinstance(retval, ErrorCode)
        return retval

    def setGeneralOutput(self, outputPin: int, outputValue: bool, outputEnable: bool) -> ErrorCode:
        '''Sets the output of a General Pin

        :param outputPin: The pin to use as output.
        :param outputValue: The desired output state.
        :param outputEnable: Whether this pin is an output. "True" enables output.

        '''
        assert isinstance(outputPin, int) and outputPin < 4294967296 and outputPin >= 0
        assert isinstance(outputValue, bool)
        assert isinstance(outputEnable, bool)
        retval = ErrorCode.OK
        go = self.hal_data['general_pin_outputs']
        goe = self.hal_data['general_pin_is_output']
        pin = (1 if outputValue else 0) << outputPin
        en = (1 if outputEnable else 0) << outputPin
        self.hal_data['general_pin_outputs'] = (go & ~(1 << outputPin)) | pin
        self.hal_data['general_pin_is_output'] = (goe & ~(1 << outputPin)) | en
        assert isinstance(retval, ErrorCode)
        return retval

    def setPWMOutput(self, pwmChannel: int, dutyCycle: int) -> ErrorCode:
        '''Sets the PWM Output
        Currently supports PWM 0, PWM 1, and PWM 2

        :param pwmChannel: Index of the PWM channel to output.
        :param dutyCycle: Duty Cycle (0 to 1) to output.  Default period of the signal is 4.2 ms.

        '''
        assert isinstance(pwmChannel, int) and pwmChannel < 4294967296 and pwmChannel >= 0
        assert isinstance(dutyCycle, int) and dutyCycle < 4294967296 and dutyCycle >= 0
        retval = ErrorCode.OK
        self.hal_data['pwm_%d' % pwmChannel] = dutyCycle / 1023.0
        assert isinstance(retval, ErrorCode)
        return retval

    def enablePWMOutput(self, pwmChannel: int, bEnable: bool) -> ErrorCode:
        '''Enables PWM Outputs
        Currently supports PWM 0, PWM 1, and PWM 2

        :param pwmChannel: Index of the PWM channel to enable.
        :param bEnable: enables output on the pwm channel.

        '''
        assert isinstance(pwmChannel, int) and pwmChannel < 4294967296 and pwmChannel >= 0
        assert isinstance(bEnable, bool)
        retval = ErrorCode.OK
        self.hal_data['pwm_%d_en' % pwmChannel] = bEnable
        assert isinstance(retval, ErrorCode)
        return retval

    def getGeneralInput(self, inputPin: int) -> bool:
        '''Gets the state of the specified pin

        :param inputPin: The index of the pin.
        :returns: The state of the pin.

        '''
        assert isinstance(inputPin, int) and inputPin < 4294967296 and inputPin >= 0
        retval = bool(self.hal_data['general_pin_inputs'] & (1 << inputPin))
        assert isinstance(retval, bool)
        return retval

    def getPWMInput(self, pwmChannel: int) -> typing.List[float]:
        '''Gets the PWM Input

        :param pwmChannel: PWM channel to get.
        :param dutyCycleAndPeriod: Double array to hold Duty Cycle [0] and Period [1].

        '''
        assert isinstance(pwmChannel, int) and pwmChannel < 4294967296 and pwmChannel >= 0
        retval = (self.hal_data['pwm_%d' % pwmChannel],
                  self.hal_data['pwm_%d_period' % pwmChannel])
        return retval

    def getLastError(self) -> ErrorCode:
        '''Call GetLastError() generated by this object.
        Not all functions return an error code but can
        potentially report errors.

        This function can be used to retrieve those error codes.

        :returns: The last ErrorCode generated.

        '''
        retval = ErrorCode.OK
        retval = self.hal_data['last_error']
        assert isinstance(retval, ErrorCode)
        return retval

    def getBusVoltage(self) -> float:
        '''Gets the bus voltage seen by the device.

        :returns: The bus voltage value (in volts).

        '''
        retval = self.hal_data['bus_voltage']
        assert isinstance(retval, (float))
        return retval

    def getQuadraturePosition(self) -> int:
        '''Gets the quadrature encoder's position

        :returns: Position of encoder

        '''
        retval = self.hal_data['quad_position']
        assert isinstance(retval, int)
        return retval

    def setQuadraturePosition(self, pos: int, timeoutMs: int) -> ErrorCode:
        '''Sets the quadrature encoder's position

        :param newPosition: Position to set

        :param timeoutMs:   Timeout value in ms. If nonzero, function will wait for
                            config success and report an error if it times out.
                            If zero, no blocking or checking is performed.

        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(pos, int)
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        self.hal_data['quad_position'] = pos
        assert isinstance(retval, ErrorCode)
        return retval

    def getQuadratureVelocity(self) -> int:
        '''Gets the quadrature encoder's velocity

        :returns: Velocity of encoder

        '''
        retval = self.hal_data['quad_velocity']
        assert isinstance(retval, int)
        return retval

    def getQuadratureSensor(self) -> typing.Tuple[int, int]:
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, tuple) and len(retval) == 2
        assert isinstance(retval[0], int)
        assert isinstance(retval[1], int)
        return retval

    def configVelocityMeasurementPeriod(self, period: int, timeoutMs: int) -> ErrorCode:
        '''Configures the period of each velocity sample.
        Every 1ms a position value is sampled, and the delta between that sample
        and the position sampled kPeriod ms ago is inserted into a filter.
        kPeriod is configured with this function.

        :param period:    Desired period for the velocity measurement. @see
                          #VelocityMeasPeriod

        :param timeoutMs: Timeout value in ms. If nonzero, function will wait for
                          config success and report an error if it times out.
                          If zero, no blocking or checking is performed.

        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(period, int)
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        pass
        assert isinstance(retval, ErrorCode)
        return retval

    def configVelocityMeasurementWindow(self, window: int, timeoutMs: int) -> ErrorCode:
        '''Sets the number of velocity samples used in the rolling average velocity
        measurement.

        :param windowSize: Number of samples in the rolling average of velocity
                           measurement. Valid values are 1,2,4,8,16,32. If another
                           value is specified, it will truncate to nearest support value.

        :param timeoutMs:  Timeout value in ms. If nonzero, function will wait for
                           config success and report an error if it times out.
                           If zero, no blockinxxg xxor checking is performed.

        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(window, int)
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        pass
        assert isinstance(retval, ErrorCode)
        return retval

    def setLastError(self, error: int) -> None:
        assert isinstance(error, int)
        self.hal_data['last_error'] = ErrorCode(error)

    def configSetParameter(self, param: int, value: float, subValue: int, ordinal: int, timeoutMs: int) -> ErrorCode:
        '''Sets a parameter. Generally this is not used.

        This can be utilized in

        - Using new features without updating API installation.
        - Errata workarounds to circumvent API implementation.
        - Allows for rapid testing / unit testing of firmware.

        :param param:
            Parameter enumeration.
        :param value:
            Value of parameter.
        :param subValue:
            Subvalue for parameter. Maximum value of 255.
        :param ordinal:
            Ordinal of parameter.
        :param timeoutMs:
            Timeout value in ms. If nonzero, function will wait for config
            success and report an error if it times out. If zero, no
            blocking or checking is performed.
        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(param, int)
        assert isinstance(value, (int, float))
        assert isinstance(subValue, int)
        assert isinstance(ordinal, int)
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, ErrorCode)
        return retval

    def configGetParameter(self, param: int, ordinal: int, timeoutMs: int) -> float:
        '''Gets a parameter. Generally this is not used.

        This can be utilized in

        - Using new features without updating API installation.
        - Errata workarounds to circumvent API implementation.
        - Allows for rapid testing / unit testing of firmware.

        :param param:
            Parameter enumeration.
        :param ordinal:
            Ordinal of parameter.
        :param timeoutMs:
            Timeout value in ms. If nonzero, function will wait for config
            success and report an error if it times out. If zero, no
            blocking or checking is performed.
        :returns: Value of parameter.

        '''
        assert isinstance(param, int)
        assert isinstance(ordinal, int)
        assert isinstance(timeoutMs, int)
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, (float))
        return retval

    def configSetCustomParam(self, newValue: int, paramIndex: int, timeoutMs: int) -> ErrorCode:
        '''Sets the value of a custom parameter. This is for arbitrary use.

        Sometimes it is necessary to save calibration/duty cycle/output
        information in the device. Particularly if the
        device is part of a subsystem that can be replaced.

        :param newValue:
            Value for custom parameter.
        :param paramIndex:
            Index of custom parameter [0-1].
        :param timeoutMs:
            Timeout value in ms. If nonzero, function will wait for config
            success and report an error if it times out. If zero, no
            blocking or checking is performed.
        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(newValue, int)
        assert isinstance(paramIndex, int)
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, ErrorCode)
        return retval

    def configGetCustomParam(self, paramIndex: int, timoutMs: int) -> int:
        '''Gets the value of a custom parameter. This is for arbitrary use.

        Sometimes it is necessary to save calibration/duty cycle/output
        information in the device. Particularly if the
        device is part of a subsystem that can be replaced.

        :param paramIndex:
            Index of custom parameter [0-1].
        :param timeoutMs:
            Timeout value in ms. If nonzero, function will wait for config
            success and report an error if it times out. If zero, no
            blocking or checking is performed.
        :returns: Value of the custom param.

        '''
        assert isinstance(paramIndex, int)
        assert isinstance(timoutMs, int)
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, int)
        return retval

    def getFaults(self) -> int:
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, int)
        return retval

    def getStickyFaults(self) -> int:
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, int)
        return retval

    def clearStickyFaults(self, timeoutMs: int) -> ErrorCode:
        '''Clears the Sticky Faults

        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        raise NotImplementedError("Not implemented in simulation (file a bug on github if you need it")
        assert isinstance(retval, ErrorCode)
        return retval

    def getFirmwareVersion(self) -> int:
        '''Gets the firmware version of the device.

        :returns: Firmware version of device.

        '''
        retval = 0
        assert isinstance(retval, int)
        return retval

    def hasResetOccurred(self) -> bool:
        '''Returns true if the device has reset since last call.

        :returns: Has a Device Reset Occurred?

        '''
        retval = self.hal_data['reset_occurred']
        self.hal_data['reset_occurred'] = False
        assert isinstance(retval, bool)
        return retval

    def setStatusFramePeriod(self, frame: int, periodMs: int, timeoutMs: int) -> ErrorCode:
        '''Sets the period of the given status frame.

        :param frame: Frame whose period is to be changed.
        :param periodMs: Period in ms for the given frame.
        :param timeoutMs: Timeout value in ms. If nonzero, function will wait for config
                          success and report an error if it times out. If zero, no
                          blocking or checking is performed.
        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(frame, int)
        assert isinstance(periodMs, int)
        assert isinstance(timeoutMs, int)
        retval = ErrorCode.OK
        self.hal_data[self._statusMap[frame]] = periodMs
        assert isinstance(retval, ErrorCode)
        return retval

    def getStatusFramePeriod(self, frame: int, timeoutMs: int) -> int:
        '''Gets the period of the given status frame.

        :param frame: Frame to get the period of.
        :param timeoutMs: Timeout value in ms. If nonzero, function will wait for config
                          success and report an error if it times out. If zero, no
                          blocking or checking is performed.
        :returns: Period of the given status frame.

        '''
        assert isinstance(frame, int)
        assert isinstance(timeoutMs, int)
        retval = self.hal_data[self._statusMap[frame]]
        assert isinstance(retval, int)
        return retval

    def setControlFramePeriod(self, frame: int, periodMs: int) -> ErrorCode:
        '''Sets the period of the given control frame.

        :param frame:
            Frame whose period is to be changed.
        :param periodMs:
            Period in ms for the given frame.
        :returns: Error Code generated by function. 0 indicates no error.

        '''
        assert isinstance(frame, int)
        assert isinstance(periodMs, int)
        retval = ErrorCode.OK
        self.hal_data[self._controlMap[frame]] = periodMs
        assert isinstance(retval, ErrorCode)
        return retval


