290 lines
11 KiB
C
290 lines
11 KiB
C
/*!
|
|
\file rc5_encode.c
|
|
\brief the rc5 infrared encoder file
|
|
|
|
\version 2021-10-30, V1.0.0, firmware for GD32W51x
|
|
*/
|
|
|
|
/*
|
|
Copyright (c) 2021, GigaDevice Semiconductor Inc.
|
|
|
|
All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without modification,
|
|
are permitted provided that the following conditions are met:
|
|
|
|
1. Redistributions of source code must retain the above copyright notice, this
|
|
list of conditions and the following disclaimer.
|
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
this list of conditions and the following disclaimer in the documentation
|
|
and/or other materials provided with the distribution.
|
|
3. Neither the name of the copyright holder nor the names of its contributors
|
|
may be used to endorse or promote products derived from this software without
|
|
specific prior written permission.
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
|
|
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
|
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
|
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
|
OF SUCH DAMAGE.
|
|
*/
|
|
|
|
#include "rc5_encode.h"
|
|
#include "ir_decode.h"
|
|
|
|
/* rc5 high level definition*/
|
|
#define RC5_HIGH_STATE ((uint8_t)0x02)
|
|
/* rc5 low level definition*/
|
|
#define RC5_LOW_STATE ((uint8_t)0x01)
|
|
|
|
rc5_ctrl_enum rc5_ctrl1 = RC5_CTRL_RESET;
|
|
|
|
uint8_t rc5_real_frame_length = 14;
|
|
uint8_t rc5_global_frame_length = 64;
|
|
uint16_t rc5_frame_binary_format = 0;
|
|
uint32_t rc5_frame_manchester_format = 0;
|
|
uint8_t send_operation_ready = 0;
|
|
__IO uint8_t send_operation_completed = 1;
|
|
uint8_t bits_sent_counter = 0;
|
|
|
|
uint8_t address_index = 0;
|
|
uint8_t instruction_index = 0;
|
|
|
|
static uint16_t rc5_bin_frame_generation(uint8_t rc5_address, uint8_t rc5_instruction, rc5_ctrl_enum rc5_ctrl);
|
|
static uint32_t rc5_manchester_convert(uint16_t rc5_binary_frame_format);
|
|
|
|
/*!
|
|
\brief init hardware (ips used) for rc5 generation
|
|
\param[in] none
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void rc5_encode_init( void )
|
|
{
|
|
timer_oc_parameter_struct timer_ocintpara;
|
|
timer_parameter_struct timer_initpara;
|
|
|
|
rcu_timer_clock_prescaler_config(RCU_TIMER_PSC_MUL4);
|
|
|
|
/* TIMER15 clock enable */
|
|
rcu_periph_clock_enable(RCU_TIMER15);
|
|
/* TIMER16 clock enable */
|
|
rcu_periph_clock_enable(RCU_TIMER16);
|
|
|
|
{
|
|
/* IR_encode */
|
|
/* PB5 IR_OUT pin configuration: output */
|
|
gpio_af_set(GPIOB, GPIO_AF_0, GPIO_PIN_5);
|
|
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO_PIN_5);
|
|
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_25MHZ, GPIO_PIN_5);
|
|
}
|
|
|
|
{
|
|
{
|
|
/* deinit TIMER16 */
|
|
timer_deinit(TIMER16);
|
|
|
|
/* time base = 36Khz */
|
|
/* time base configuration for TIMER16 */
|
|
timer_initpara.prescaler = 0x01;
|
|
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
|
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
|
timer_initpara.period = 2499;
|
|
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
|
|
timer_initpara.repetitioncounter = 0;
|
|
timer_init(TIMER16,&timer_initpara);
|
|
|
|
/* prescaler configuration */
|
|
timer_prescaler_config(TIMER16,0x01,TIMER_PSC_RELOAD_NOW);
|
|
|
|
/* output compare timing mode configuration: channel 0N */
|
|
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
|
|
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
|
|
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
|
|
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_LOW;
|
|
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
|
|
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
|
|
timer_channel_output_config(TIMER16,TIMER_CH_0,&timer_ocintpara);
|
|
|
|
timer_channel_output_pulse_value_config(TIMER16,TIMER_CH_0,(2500/4-1));
|
|
timer_channel_output_mode_config(TIMER16,TIMER_CH_0,TIMER_OC_MODE_PWM1);
|
|
timer_channel_output_shadow_config(TIMER16,TIMER_CH_0,TIMER_OC_SHADOW_ENABLE);
|
|
|
|
/* TIMER16 enable */
|
|
timer_enable(TIMER16);
|
|
/* enable the TIMER16 channel1 output to be connected internly to the IRTIMER */
|
|
timer_primary_output_config(TIMER16,ENABLE);
|
|
}
|
|
|
|
{
|
|
/* deinit TIMER15 */
|
|
timer_deinit(TIMER15);
|
|
|
|
/* elementary period 889 us */
|
|
/* time base configuration for TIMER15 */
|
|
timer_initpara.prescaler = 4;
|
|
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
|
|
timer_initpara.counterdirection = TIMER_COUNTER_UP;
|
|
timer_initpara.period = 64008 /2 - 1;
|
|
timer_initpara.clockdivision = 0;
|
|
timer_initpara.repetitioncounter = 0;
|
|
timer_init(TIMER15,&timer_initpara);
|
|
|
|
/* duty cycle = 25% */
|
|
/* channel 1 configuration in timing mode */
|
|
timer_ocintpara.outputstate = TIMER_CCX_ENABLE;
|
|
timer_ocintpara.outputnstate = TIMER_CCXN_DISABLE;
|
|
timer_ocintpara.ocpolarity = TIMER_OC_POLARITY_HIGH;
|
|
timer_ocintpara.ocnpolarity = TIMER_OCN_POLARITY_HIGH;
|
|
timer_ocintpara.ocidlestate = TIMER_OC_IDLE_STATE_LOW;
|
|
timer_ocintpara.ocnidlestate = TIMER_OCN_IDLE_STATE_LOW;
|
|
timer_channel_output_config(TIMER15,TIMER_CH_0,&timer_ocintpara);
|
|
|
|
timer_channel_output_pulse_value_config(TIMER15,TIMER_CH_0,(64008 /2 /4));
|
|
timer_channel_output_mode_config(TIMER15,TIMER_CH_0,TIMER_OC_MODE_TIMING);
|
|
|
|
/* enable the TIMER15 interrupt */
|
|
// nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);
|
|
nvic_irq_enable(TIMER15_IRQn, 0, 0);
|
|
|
|
/* TIMER15 main output enable */
|
|
timer_primary_output_config(TIMER15,ENABLE);
|
|
/* TIMER15 INT disable */
|
|
timer_interrupt_disable(TIMER15,TIMER_INT_UP);
|
|
/* TIMER15 disable */
|
|
timer_disable(TIMER15);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief generate and send the rc5 frame
|
|
\param[in] rc5_address: the rc5 device destination
|
|
\param[in] rc5_instruction: the rc5 command instruction
|
|
\param[in] rc5_ctrl: the rc5 control bit
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void rc5_encode_send_frame(uint8_t rc5_address, uint8_t rc5_instruction, rc5_ctrl_enum rc5_ctrl)
|
|
{
|
|
uint16_t rc5_frame_binary_format = 0;
|
|
|
|
/* generate a binary format of the frame */
|
|
rc5_frame_binary_format = rc5_bin_frame_generation(rc5_address, rc5_instruction, rc5_ctrl);
|
|
|
|
/* generate a manchester format of the frame */
|
|
rc5_frame_manchester_format = rc5_manchester_convert(rc5_frame_binary_format);
|
|
|
|
/* set the send operation ready flag to indicate that the frame is ready to be sent */
|
|
send_operation_ready = 1;
|
|
|
|
/* TIMER15 INT enable */
|
|
timer_interrupt_enable(TIMER15,TIMER_INT_UP);
|
|
|
|
/* enable TIMER15 */
|
|
timer_enable(TIMER15);
|
|
}
|
|
|
|
/*!
|
|
\brief send by hardware manchester format rc5 frame
|
|
\param[in] rc5_manchester_frame_format: the rc5 frame in manchester format
|
|
\param[out] none
|
|
\retval none
|
|
*/
|
|
void rc5_encode_signal_generate( uint32_t rc5_manchester_frame_format )
|
|
{
|
|
uint8_t bit_msg = 0;
|
|
|
|
if((1 == send_operation_ready ) && ((rc5_global_frame_length * 2) >= bits_sent_counter)){
|
|
send_operation_completed = 0x00;
|
|
bit_msg = (uint8_t)((rc5_manchester_frame_format >> bits_sent_counter) & 1);
|
|
|
|
if(1 == bit_msg){
|
|
timer_channel_output_mode_config(TIMER15, TIMER_CH_0, TIMER_OC_MODE_HIGH);
|
|
}else{
|
|
timer_channel_output_mode_config(TIMER15, TIMER_CH_0, TIMER_OC_MODE_LOW);
|
|
}
|
|
bits_sent_counter++;
|
|
}else{
|
|
send_operation_completed = 0x01;
|
|
|
|
/* TIMER15 INT disable */
|
|
timer_interrupt_disable(TIMER15, TIMER_INT_UP);
|
|
timer_disable(TIMER15);
|
|
|
|
send_operation_ready = 0;
|
|
bits_sent_counter = 0;
|
|
timer_channel_output_mode_config(TIMER15, TIMER_CH_0, TIMER_OC_MODE_LOW);
|
|
}
|
|
}
|
|
|
|
/*!
|
|
\brief generate the binary format of the rc5 frame
|
|
\param[in] rc5_address: select the device adress
|
|
\param[in] rc5_instruction: select the device instruction
|
|
\param[in] rc5_ctrl: select the device control bit status
|
|
\param[out] none
|
|
\retval binary format of the rc5 frame
|
|
*/
|
|
static uint16_t rc5_bin_frame_generation(uint8_t rc5_address, uint8_t rc5_instruction, rc5_ctrl_enum rc5_ctrl)
|
|
{
|
|
uint16_t star1 = 0x2000;
|
|
uint16_t star2 = 0x1000;
|
|
uint16_t addr = 0;
|
|
|
|
while(0x00 == send_operation_completed);
|
|
|
|
/* check if instruction is 128-bit length */
|
|
if(64 <= rc5_instruction){
|
|
/* reset field bit: command is 7-bit length */
|
|
star2 = 0;
|
|
/* keep the lowest 6 bits of the command */
|
|
rc5_instruction &= 0x003F;
|
|
}
|
|
/* instruction is 64-bit length */
|
|
else{
|
|
/* set field bit: command is 6-bit length */
|
|
star2 = 0x1000;
|
|
}
|
|
|
|
send_operation_ready = 0;
|
|
rc5_frame_manchester_format = 0;
|
|
rc5_frame_binary_format = 0;
|
|
addr = ((uint16_t)(rc5_address))<<6;
|
|
rc5_frame_binary_format = (star1) | (star2) | (rc5_ctrl) | (addr) | (rc5_instruction);
|
|
return(rc5_frame_binary_format);
|
|
}
|
|
|
|
/*!
|
|
\brief convert the rc5 frame from binary to manchester format
|
|
\param[in] rc5_binary_frame_format: the rc5 frame in binary format
|
|
\param[out] none
|
|
\retval the rc5 frame in manchester format
|
|
*/
|
|
static uint32_t rc5_manchester_convert(uint16_t rc5_binary_frame_format)
|
|
{
|
|
uint8_t i=0;
|
|
uint16_t mask = 1;
|
|
uint16_t bit_format = 0;
|
|
uint32_t converted_msg =0;
|
|
|
|
for(i = 0; i < rc5_real_frame_length; i++){
|
|
bit_format = ((((uint16_t)(rc5_binary_frame_format))>>i)& mask)<<i;
|
|
converted_msg = converted_msg << 2;
|
|
|
|
if(0 != bit_format){
|
|
/* manchester 1 -|_ */
|
|
converted_msg |= RC5_HIGH_STATE;
|
|
}else{
|
|
/* manchester 0 _|- */
|
|
converted_msg |= RC5_LOW_STATE;
|
|
}
|
|
}
|
|
return(converted_msg);
|
|
}
|