/* $Id: transmit.c,v 5.25 2007/02/20 07:11:10 lirc Exp $ */ /**************************************************************************** ** transmit.c ************************************************************** **************************************************************************** * * functions that prepare IR codes for transmitting * * Copyright (C) 1999-2004 Christoph Bartelmus * */ #ifdef HAVE_CONFIG_H # include #endif /* if the gap is lower than this value, we will concatenate the signals and send the signal chain at a single blow */ #define LIRCD_EXACT_GAP_THRESHOLD 10000 #include "lircd.h" #include "transmit.h" extern struct ir_remote *repeat_remote; struct sbuf send_buffer; static void send_signals(lirc_t *signals, int n); inline void set_bit(ir_code *code,int bit,int data) { (*code)&=~((((ir_code) 1)<0) { send_buffer.pendingp+=data; } else { if(send_buffer.pendings>0) { add_send_buffer(send_buffer.pendings); send_buffer.pendings=0; } send_buffer.pendingp=data; } } inline void send_space(lirc_t data) { if(send_buffer.wptr==0 && send_buffer.pendingp==0) { LOGPRINTF(1,"first signal is a space!"); return; } if(send_buffer.pendings>0) { send_buffer.pendings+=data; } else { if(send_buffer.pendingp>0) { add_send_buffer(send_buffer.pendingp); send_buffer.pendingp=0; } send_buffer.pendings=data; } } static inline int bad_send_buffer(void) { if(send_buffer.too_long!=0) return(1); if(send_buffer.wptr==WBUF_SIZE && send_buffer.pendingp>0) { return(1); } return(0); } static inline void flush_send_buffer(void) { if(send_buffer.pendingp>0) { add_send_buffer(send_buffer.pendingp); send_buffer.pendingp=0; } if(send_buffer.pendings>0) { add_send_buffer(send_buffer.pendings); send_buffer.pendings=0; } } static inline void sync_send_buffer(void) { if(send_buffer.pendingp>0) { add_send_buffer(send_buffer.pendingp); send_buffer.pendingp=0; } if(send_buffer.wptr>0 && send_buffer.wptr%2==0) send_buffer.wptr--; } inline void send_header(struct ir_remote *remote) { if(has_header(remote)) { send_pulse(remote->phead); send_space(remote->shead); } } inline void send_foot(struct ir_remote *remote) { if(has_foot(remote)) { send_space(remote->sfoot); send_pulse(remote->pfoot); } } inline void send_lead(struct ir_remote *remote) { if(remote->plead!=0) { send_pulse(remote->plead); } } inline void send_trail(struct ir_remote *remote) { if(remote->ptrail!=0) { send_pulse(remote->ptrail); } } inline void send_data(struct ir_remote *remote,ir_code data,int bits,int done) { int i; int all_bits = remote->pre_data_bits+ remote->bits+ remote->post_data_bits; ir_code mask; if(is_rcmm(remote)) { data=reverse(data,bits); mask=1<<(all_bits-1-done); if(bits%2 || done%2) { logprintf(LOG_ERR,"invalid bit number."); return; } for(i=0;i>=2) { switch(data&3) { case 0: send_pulse(remote->pzero); send_space(remote->szero); break; /* 2 and 1 swapped due to reverse() */ case 2: send_pulse(remote->pone); send_space(remote->sone); break; case 1: send_pulse(remote->ptwo); send_space(remote->stwo); break; case 3: send_pulse(remote->pthree); send_space(remote->sthree); break; } data=data>>2; } return; } data=reverse(data,bits); mask=((ir_code) 1)<<(all_bits-1-done); for(i=0;i>=1) { if(has_toggle_bit_mask(remote) && mask&remote->toggle_bit_mask) { data &= ~((ir_code) 1); if(remote->toggle_bit_mask_state&mask) { data |= (ir_code) 1; } } if(has_toggle_mask(remote) && mask&remote->toggle_mask && remote->toggle_mask_state%2) { data ^= 1; } if(data&1) { if(is_biphase(remote)) { if(mask&remote->rc6_mask) { send_space(2*remote->sone); send_pulse(2*remote->pone); } else { send_space(remote->sone); send_pulse(remote->pone); } } else if(is_space_first(remote)) { send_space(remote->sone); send_pulse(remote->pone); } else { send_pulse(remote->pone); send_space(remote->sone); } } else { if(mask&remote->rc6_mask) { send_pulse(2*remote->pzero); send_space(2*remote->szero); } else if(is_space_first(remote)) { send_space(remote->szero); send_pulse(remote->pzero); } else { send_pulse(remote->pzero); send_space(remote->szero); } } data=data>>1; } } inline void send_pre(struct ir_remote *remote) { if(has_pre(remote)) { send_data(remote,remote->pre_data,remote->pre_data_bits,0); if(remote->pre_p>0 && remote->pre_s>0) { send_pulse(remote->pre_p); send_space(remote->pre_s); } } } inline void send_post(struct ir_remote *remote) { if(has_post(remote)) { if(remote->post_p>0 && remote->post_s>0) { send_pulse(remote->post_p); send_space(remote->post_s); } send_data(remote,remote->post_data,remote->post_data_bits, remote->pre_data_bits+remote->bits); } } inline void send_repeat(struct ir_remote *remote) { send_lead(remote); send_pulse(remote->prepeat); send_space(remote->srepeat); send_trail(remote); } inline void send_code(struct ir_remote *remote,ir_code code, int repeat) { if(!repeat || !(remote->flags&NO_HEAD_REP)) send_header(remote); send_lead(remote); send_pre(remote); send_data(remote,code,remote->bits,remote->pre_data_bits); send_post(remote); send_trail(remote); if(!repeat || !(remote->flags&NO_FOOT_REP)) send_foot(remote); if(!repeat && remote->flags&NO_HEAD_REP && remote->flags&CONST_LENGTH) { send_buffer.sum-=remote->phead+remote->shead; } } static void send_signals(lirc_t *signals, int n) { int i; for(i=0; irepeat_countdown=remote->min_repeat; } else { repeat = 1; } init_send_loop: if(repeat && has_repeat(remote)) { if(remote->flags&REPEAT_HEADER && has_header(remote)) { send_header(remote); } send_repeat(remote); } else { if(!is_raw(remote)) { ir_code next_code; if(code->transmit_state == NULL) { next_code = code->code; } else { next_code = code->transmit_state->code; } send_code(remote, next_code, repeat); if(has_toggle_mask(remote)) { remote->toggle_mask_state++; if(remote->toggle_mask_state==4) { remote->toggle_mask_state=2; } } send_buffer.data=send_buffer._data; } else { if(code->signals==NULL) { logprintf(LOG_ERR, "no signals for raw send"); return 0; } if(send_buffer.wptr>0) { send_signals(code->signals, code->length); } else { send_buffer.data=code->signals; send_buffer.wptr=code->length; for(i=0; ilength; i++) { send_buffer.sum+=code->signals[i]; } } } } sync_send_buffer(); if(bad_send_buffer()) { logprintf(LOG_ERR,"buffer too small"); return(0); } if(has_repeat_gap(remote) && repeat && has_repeat(remote)) { remote->remaining_gap=remote->repeat_gap; } else if(is_const(remote)) { if(remote->gap>send_buffer.sum) { remote->remaining_gap=remote->gap -send_buffer.sum; } else { logprintf(LOG_ERR,"too short gap: %u",remote->gap); remote->remaining_gap=remote->gap; return(0); } } else { remote->remaining_gap=remote->gap; } /* update transmit state */ if(code->next != NULL) { if(code->transmit_state == NULL) { code->transmit_state = code->next; } else { code->transmit_state = code->transmit_state->next; } } if((remote->repeat_countdown>0 || code->transmit_state != NULL) && remote->remaining_gapnext == NULL || code->transmit_state == NULL) { remote->repeat_countdown--; } send_space(remote->remaining_gap); flush_send_buffer(); send_buffer.sum=0; repeat = 1; goto init_send_loop; } LOGPRINTF(3, "transmit buffer ready"); return(1); }