[Lcdproc] Re: lcdproc-0.5.1 and serialized HD44780 on k-data
wake-up 2.0 module
Markus Schorer
ms@plain.de
Thu Mar 1 18:08:02 2007
This is a multi-part message in MIME format.
--------------070907070901030500020802
Content-Type: text/plain; charset=ISO-8859-15; format=flowed
Content-Transfer-Encoding: 8bit
hi matteo,
i've merged my changes with your driver, the diff ist against
lcdproc_cvs (>0.5.1).
i'm not too glad about how i had to integrate my protocol into your code.
changes to hd44780:
- adding the infrastructure for backlight_brightness (on and off) and
contrast
- scankeypad uses select on the serial-port
- added new serial protocol "los2", my avr-based serial converter
> As you see, I'm a lot busy right now... I don't recall any property on
> the driver, I donated it to the lcdproc project ;-). Feel free to make
> changes you like, only Peter can decide to approve your patches or not :-D.
so you don't work on it anymore?
how can we get this into cvs?
@erik: i'm appending my firmware here. as is said earlier, this is not a
los. it uses another processor and other pins. but it shouldn't be hard
to port to any avr.
i'm sending both here for completeness. i hope to have it some web-pages
of its own soon.
i started this to learn avr and get my lcd's working, please do not
blame me if it's not working for you. ;-)
anyone interested in it at all? feedback?
markus
--
_______________________________________________________________________
plain GmbH | daiserstrasse 15 | 81371 münchen
fon 089.540.149.0 | fax 089.540.149.44 | http://www.plain.de
--------------070907070901030500020802
Content-Type: text/plain;
name="los2_display.asm"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="los2_display.asm"
;==================================================================================
;
;==================================================================================
;
; serial interface to a hd44780 lcd
;
; (c) markus schorer, ms@msite.de
;
; based on LoS code from Erik Brouwer (based on Bas Lummen)
;
; License: GPL
;
; v0.71: 20070301
;
;
;==================================================================================
.include "m16def.inc" ; include processor definitions
.def char =r0
.def temp =r16 ; temporary variable
.def temp1 =r17 ; temporary variable
.def buffer =r19
.def buffer2 =r20
.def code =r21
.def temp20 =r22
.def wt0 =r23
.def wt1 =r24
.def wt2 =r25
;----------------------------------------------------
.equ KEYBITMASK =$F0 ; upper nybble;
;.equ CLOCK =3686000 ; programmable clock on stk500
;.equ CLOCK =17850000 ; 12MHz in stk crystal for USB operation
.equ CLOCK =12000000 ; 12MHz external crystal-osc
.equ CYCLES_DLOOP =4
.equ CLOCKS_100U =(CLOCK / 10000) / CYCLES_DLOOP ; 100us as clock loops
.equ BAUDRATE =9600 ; Baudrate at 9600
.equ UBRRVAL =CLOCK/(BAUDRATE*16)-1 ; uart bitrate reg-value
.equ REP_RATE =100
;----------------------------------------------------
.equ RXD =PD0
.equ TXD =PD1
.equ E =PD2 ; E: latch data
.equ RS =PD3 ; adress bit
.equ RD =PD7 ; rd/wr
.equ DB0 =PB0
.equ DB1 =PB1
.equ DB2 =PB2
.equ DB3 =PB3
.equ DB4 =PB0
.equ DB5 =PB1
.equ DB6 =PB2
.equ DB7 =PB3
.equ PWM1B =PD4
.equ PWM1A =PD5
.equ LED0 =PD6 ; led1
;.equ LED1 =PD7 ; led2
.equ DATAMASK =$0F
.equ BUTTONMASK =$F0
;----------------------------------------------------
; function codes for protocol
.equ CODE_ESCAPE =$FE
.equ CODE_INSTR =$01
.equ CODE_BACKLIGHT =$02
.equ CODE_CONTRAST =$03
;----------------------------------------------------
; counter and keycode for key detection
.equ last_key =$80
.equ keys_off =$82
;----------------------------------------------------
; structs for ringbuffer's
.equ RB_RX =$90
.equ RB_TX =$94
;------------------------------------
; struct offsets for rb data
.equ RB_IN =0
.equ RB_ADRH =1
.equ RB_OUT =2
.equ RB_MASK =3
;----------------------------------------------------
;HD44780 commands
.equ HD44780_RESET =$03
.equ HD44780_4BIT =$02
.equ HD44780_CLEAR =$01
.equ HD44780_HOME =$02
;================================================================================
;================================================================================
; reserve ringbuffers
.dseg
.org $100
RX_BUF: .byte 64
TX_BUF: .byte 16
;================================================================================
; set interrupt table (for atmega16)
.cseg
.org $000 ; begin interrupt vector table
jmp RESET ; adress for reset routine
jmp noop ; irq0
jmp noop ; irq1
jmp noop ; timer2 compare
jmp noop ; timer2 overflow
jmp noop ; timer1 capture
jmp noop ; timer1 compareA
jmp noop ; timer1 compareB
jmp noop ; timer1 overflow
jmp noop ; timer0 overflow
jmp noop ; spi complete
jmp int_uart_rx ; usart rxc
jmp noop ; usart udre
jmp int_uart_tx ; usart txc
jmp noop ; adc complete
jmp noop ; eeprom ready
jmp noop ; analog comparator
jmp noop ; two wire
jmp noop ; irq2
jmp noop ; timer0 compare
jmp noop ; prog mem ready
noop: reti
;================================================================================
;================================================================================
; static data
.org $40
ID_STRING: .DB "LoS V0.71 bcki serial",0
INIT_SEQ: .DB $28,$0c,$06,HD44780_CLEAR,HD44780_HOME,$00
;================================================================================
;================================================================================
; processor initialisation
.org $060
RESET:
ldi temp,LOW(RAMEND)
out SPL,temp
ldi temp,HIGH(RAMEND)
out SPH,temp
ldi temp,DATAMASK ; set databits for output
out DDRB,temp
; set all pins for output exceptRXD
ldi temp,(1 << TXD)|(1 << E)|(1 << RS)|(1 << PWM1A)|(1 << PWM1B)|(1 << LED0)|(1 << RD) ;|(1 << LED1)
out DDRD,temp
// ldi temp,(1 << RXD) ;pull-ups on all inputs of port D (for key inputs)
// out PORTD,temp
ldi temp,(1<<TXCIE)|(1<<RXCIE)|(1<<TXEN)|(1<<RXEN) ; rxcie,rxen,txen
out UCSRB,temp ; enable rx/tx Complete Interrupt
ldi temp,$06 ; Asynchronous Operation Parity disable
out UCSRC,temp ; 1 stop bit
ldi temp,HIGH(UBRRVAL)
out UBRRH,temp
ldi temp,LOW(UBRRVAL)
out UBRRL,temp
ldi temp,0 ; Set Output Comp Reg H to 0
out OCR1BH,temp
ldi temp,0 ; Set pulse width
out OCR1BL,temp
ldi temp,0 ; Set Output Comp Reg H to 0
out OCR1AH,temp
ldi temp,0 ; Set pulse width
out OCR1AL,temp
ldi temp, 0b10100001 ; Set Timer/Counter1 as an 8-bit PWM
out TCCR1A, temp
;
ldi temp, 0b00001010 ; Start Timer/Counter1 , set PWM mode to clear OC1(PB3) at upcounting
out TCCR1B, temp
; setup rx ringbuffer
ldi YL, LOW(RB_RX)
ldi YH,HIGH(RB_RX)
ldi temp, LOW( RX_BUF) ; low has to be 0
std Y+RB_IN,temp ; reset in and out pointers
std Y+RB_OUT,temp
ldi temp, HIGH( RX_BUF) ; preset high-address
std Y+RB_ADRH,temp
ldi temp,0b00111111 ; set for 64-byte buffer
std Y+RB_MASK,temp
; setup rx ringbuffer
ldi YL,LOW(RB_TX)
ldi YH,HIGH(RB_TX)
ldi temp,LOW(TX_BUF) ; low has to be 0
std Y+RB_IN,temp
std Y+RB_OUT,temp ; reset in and out pointers
ldi temp,HIGH(TX_BUF) ; preset high adress
std Y+RB_ADRH,temp
ldi temp,0b00001111 ; adjust for 16-byte buffer
std Y+RB_MASK,temp
; sbi PORTD,LED0 ; signal empty
; cbi PORTD,LED1 ; signal empty
clr temp ; preset
out OCR1BL,temp ; clear backlight
out OCR1AL,temp ; clear contrast
sei ; enable interrupts
;================================================================================
;================================================================================
; setup LCD
begin:
/*
ldi temp,$00 ;long wait for LCD power-up
powerup:rcall wait2
dec temp
breq powerup
*/
cbi PORTD,RS ; clear adress for instruction
cbi PORTD,RD ; clear RD for write
ldi buffer,HD44780_RESET ; go through hd44780 reset sequence
out PORTB,buffer ; write 3 times
sbi PORTD,E
rcall delay_E
cbi PORTD,E
rcall delay_E
ldi buffer,45 ; wait for 4,5ms (=45 * 100us)
rcall delay_100u
sbi PORTD,E ; 2. write
rcall delay_E
cbi PORTD,E
rcall delay_E
ldi buffer,2 ; wait for 200u (=2 * 100us)
rcall delay_100u
sbi PORTD,E ; 3. write
rcall delay_E
cbi PORTD,E
rcall delay_E
ldi buffer,1 ; wait for 100u (=1 * 100us)
rcall delay_100u
ldi buffer,HD44780_4BIT ; switch to 4 bit mode
out PORTB,buffer
sbi PORTD,E
rcall delay_E
cbi PORTD,E
rcall delay_E
ldi buffer,1 ; wait for 100u (=1 * 100us)
rcall delay_100u
;-------------------------------------------------------------
; from now on, busy is valid
; loop through other setup codes
ldi ZL,LOW( INIT_SEQ*2) ; low pointer points to beginning of the table
ldi ZH,HIGH(INIT_SEQ*2) ; high pointer points to beginning table
init_loop:
lpm ; get char from table
mov buffer,char
cpi buffer,$0 ; zero-terminated table
breq init
rcall LCD_inst
inc ZL
rjmp init_loop
init: ; init display
loadscr:
ldi buffer,HD44780_CLEAR ; clear screen
rcall LCD_inst
ldi buffer,HD44780_HOME ; cursor to home
rcall LCD_inst
;-------------------------------------------------------------
; Welcome text on LCD and over serial
ser temp
out OCR1BL,temp
; cbi PORTD,LED0 ; turn on backlight first
ldi ZL, LOW(ID_STRING*2) ; low pointer points to beginning of the table
ldi ZH,HIGH(ID_STRING*2) ; high pointer points to beginning table
ldi YL,LOW(RB_TX)
tloop: lpm ; get char from table
mov temp,char
cpi temp,0 ; check if end-of-table reached
breq init_screen_done
mov buffer,char ;
rcall LCD_data ; write to screen
rcall uart_xmit ; write over serial
inc ZL ; next character
brne tloop ; next character
init_screen_done:
ldi buffer2, 80 ; wait 2 * 40 * 250*100us
init_screen_wait:
ldi buffer,$fa
rcall delay_100u
dec buffer2
brne init_screen_wait
; enter main loop
;==================================================================================
;==================================================================================
; sync to protocol, first esc after non-escapes is in sync
ldi YL,LOW(RB_RX)
; check if we jump in a stream
rcall avail_rb ; anything received yet?
breq clear_screen ; no: we are synced
; wait for first non-escape char
rd_first:
rcall peek_rb ; peek at first in rx
breq rd_first ; loop until not empty
cpi buffer,CODE_ESCAPE ; is is ESCAPE
brne rd_second ; no: gon on waiting for escape
rcall pop_rb ; consume ESCAPE from rx buffer
rjmp rd_first
; wait for escape char
rd_second:
rcall peek_rb ; peek at first in rx
breq rd_second ; loop until not empty
cpi buffer,CODE_ESCAPE ; is it ESCAPE
breq start ; yes: go on
rcall pop_rb ; consume non escapes
rjmp rd_second
;-----------------------------------------------------------------------------------
; clear screen after being synced
clear_screen:
ldi buffer,HD44780_CLEAR ; clear screen
rcall LCD_inst
ldi buffer,HD44780_HOME ; cursor to
rcall LCD_inst
;-----------------------------------------------------------------------------------
; main loop
start:
; read keys
in temp,PINB ; check if any key is pressed
andi temp,KEYBITMASK ;
cpi temp,KEYBITMASK ;
breq no_key ; if so then go read keys
ldi temp, 0 ; reset off counter
sts keys_off, temp
rcall keyread ; read keys
rjmp handle_commands
no_key: lds temp,keys_off
inc temp ; increment consecutive off-s counter
sts keys_off, temp
cpi temp,REP_RATE ; trigger reached
brpl handle_commands ; have we seen keys off for enough time?
ldi temp20, 0 ; clear last key button
sts last_key, temp20 ; reenable keyboard
handle_commands:
ldi YL,LOW(RB_RX)
rcall peek_rb ; try to read first char
brne check_rx_buffer ; skip if empty
do_sleep:
; set sleep flags ; nothing to do, wait for interrupt
; sleep
; clear sleep flags
rjmp start
check_rx_buffer:
cpi buffer,CODE_ESCAPE ; is first char escape?
breq wait_cmd
rcall pop_rb ; read data from buffer
rcall LCD_data ; write data to display
rjmp start ; loop again
wait_cmd:
rcall avail_rb ; check if we have 3 bytes
cpi buffer,3
brlo do_sleep ; if less, wait for more to arrive
rcall parsedata ; if so then go write it to the LCD
rjmp start
;----------------------------------------------------------------------------------
; parsing an escaped sequence
; 3 bytes should be available - equalling 1 command
; if escaped data, return after reading second byte
parsedata:
push buffer
push buffer2
push temp1
read_esc:
rcall pop_rb ; 1. read: escape
breq read_esc
cpi buffer,CODE_ESCAPE ; is it _really_ escape?
breq read_icode
rjmp parsing_done
read_icode:
rcall pop_rb ; 2. read: instruction code
breq read_icode
cpi buffer,CODE_ESCAPE ; another escape? ist stuffed data?
brne parse_cmds ;
rcall LCD_data ; write data and return
rjmp parsing_done
parse_cmds:
mov buffer2,buffer ; save command code to buffer2
read_param:
rcall pop_rb ; 3. read: parameter
breq read_param
cpi buffer2,CODE_INSTR ; check if it is an escapecode for LCD-instructions
brne parse_bl ; if so then treat next received byte as an instruction
// write instruction
mov temp1,buffer ; Filter for unwanted instructions
andi temp1,$F0 ;
cpi temp1,$30 ; check if one tries to set 8-bit mode
breq force4bit ; if so then go put it in 4-bit mode anyway
rcall LCD_inst ; Go write the received byte as instruction to LCD
rjmp parsing_done
force4bit:
andi buffer,$2F ; set 4-bit mode, 1/16 (2line), 5x10 dots ((not good!?))
rcall LCD_inst ; write this byte as instruction
rjmp parsing_done
// done: instruction
parse_bl:
cpi buffer2,CODE_BACKLIGHT ; check if it is an escapecode for the LCD-backlight
brne parse_contrast ; if so then treat next received byte as backlight control
// set the brightness level
out OCR1BL,buffer
rjmp parsing_done
// done: contrast
parse_contrast:
cpi buffer2,CODE_CONTRAST ; check if it is an escapecode for the LCD-backlight
brne parsing_done ; if so then treat next received byte as backlight control
// set the contrast value
out OCR1AL,buffer
; rjmp parsing_done
// done: contrast
parsing_done:
pop temp1
pop buffer2
pop buffer
ret
;------------------------------------------------------------------------------
; LCD routines
LCD_inst:
rcall wait_busy ; wait while LCD is busy
cbi PORTD,RS ; address 0 is instruction
rjmp LCD_write
LCD_data:
rcall wait_busy ; wait while LCD is busy
sbi PORTD,RS ; address 1 is data
LCD_write:
push buffer
push buffer2
mov buffer2,buffer ; save byte
lsr buffer ; get upper nibble in position
lsr buffer
lsr buffer
lsr buffer
andi buffer,$0F ; mask out data pins
out PORTB,buffer ; write to display
; transfer upper nybble
sbi PORTD,E ; enable E
rcall delay_E ; wait
cbi PORTD,E ; data is latched on falling E
rcall delay_E ; keep cycle time
rcall wait_busy ; wait while LCD is busy
; transfer lower nybble
andi buffer2,$0F ; mask out data pins
out PORTB,buffer2 ; write to display
sbi PORTD,E ; enable E
rcall delay_E ; wait
cbi PORTD,E ; data is latched on falling E
rcall delay_E ; keep cycle time
pop buffer2
pop buffer
ret ; return from this subroutine
;---------------------------------------------------------------------------
; read busy flag from display
wait_busy:
push temp
in temp,PORTD ; save control lines
cbi DDRB,DB7 ; switch DB7 to input
cbi PORTD,RS ; adress 0: instruction
sbi PORTD,RD ; read
;busy_loop:
sbi PORTD,E ; enable
busy_loop:
rcall delay_E
sbic PINB,DB7 ; busy bit cleared?
rjmp busy_loop ;
sbi DDRB,DB7 ; switch DB7 back to output
out PORTD,temp ; restore control lines
pop temp
ret
;-------------------------------------------------------------------------
; assure E cycle time of 1us
; rcall + ret uses 7cycles (enough for 14MHz)
; add additional NOPs for every 2MHz
delay_E:
.IF CLOCK > 14000000 ; add another cycle
nop
.ENDIF
.IF CLOCK > 16000000
nop
.ENDIF
.IF CLOCK > 18000000 ; works till 20MHz
nop
.ENDIF
ret
;--------------------------------------------------------------
; delay for multiples of 100us
delay_100u:
push XL
push XH
d100u_outer:
ldi XL, LOW(CLOCKS_100U)
ldi XH,HIGH(CLOCKS_100U)
d100u_inner:
sbiw X,1 ; 4 clocks for 1 loop
brne d100u_inner
dec buffer
brne d100u_outer
pop XH
pop XL
ret
;====================================================================================
; Keyboard routine
keyread:
push temp20
push temp
push buffer
ldi buffer,100
rcall delay_100U
; rcall wait ; wait for debounce
in temp20,PINB ; read portd (rows of the keyboard)
andi temp20,KEYBITMASK ; use bits 4/5/6/7
cpi temp20,KEYBITMASK ;
brne key_pressed ; do a little debouncing
rjmp keyread_done
key_pressed:
ldi temp,$F0 ; pressing pulls low
eor temp20,temp ; invert it to get presses as 1
lds temp,last_key
cp temp,temp20 ; dont send a key twice
brne send_new_char
rjmp keyread_done
send_new_char:
sts last_key, temp20 ; save key for repeat detection
ldi temp,$10 ; get mask bit
ldi buffer,1 ; preset row count
keycount_loop:
mov char,temp ; get mask
and char,temp20 ; and with input
breq not_set ; skip if not set
push buffer ; save row counter
ldi buffer,$FE ; send escape
rcall uart_xmit
pop buffer ; restore row counter
rcall uart_xmit ; buffer is preset with row count
not_set:
inc buffer ; inc row counter
lsl temp ; shift row-mask
brne keycount_loop ; done if bit shifted out
keyread_done:
pop buffer
pop temp
pop temp20
ret
;=========================================================================================
; usart int handlers
;---------------------------------------------------------------------------
; rx interrupt
int_uart_rx:
push buffer
push temp20
in temp20,SREG
; sbis UCSRA,RXC ; check if rxbuf is full
; jmp spurious_rx ; no: spurious int
in buffer,UDR ; get the byte
ldi YL,LOW(RB_RX)
call push_rb
spurious_rx:
out SREG,temp20
pop temp20
pop buffer
reti
;---------------------------------------------------------------------------
; tx interrupt
int_uart_tx:
push buffer
push temp20
in temp20,SREG
; sbis UCSRA,UDRE ; check if rxbuf is full
; jmp tx_buffer_empty ; no: spurious int
ldi YL,LOW(RB_TX) ; set pointer to tx buffer
call pop_rb ; try to read ring-buffer
breq tx_buffer_empty ; if empty Z is set
out UDR,buffer ; get the byte
tx_buffer_empty:
out SREG,temp20
pop temp20
pop buffer
reti
;----------------------------------------------------------------------------
; send char
; queue or send directly if queue empty
uart_xmit:
ldi YL,LOW(RB_TX) ; set pointer to tx rb
call isempty_rb ; anything in ringbuffer?
brne tx_not_empty ; no: queue char
sbis UCSRA,UDRE ; is uart ready?
rjmp tx_not_empty ; no: queue char
out UDR, buffer ; buffer empty, send directly
rjmp xmit_done
tx_not_empty:
call push_rb
xmit_done:
ret
;==============================================================================================
; ring buffer routines
; adress of rb-structure is expected in Y
;---------------------------------------------------------------------------
; return chars available in buffer
avail_rb: ; returns available chars in buffer
push temp
ldd buffer,Y+RB_IN ; get offset, lower byte from pointer
ldd temp, Y+RB_OUT ; get out-pointer
cp buffer,temp
brsh rb_no_inv ; same or higher
com temp ; wrap pointer round
rb_no_inv:
sub buffer,temp
pop temp
ret
;---------------------------------------------------------------------------
; return chars available in buffer
isempty_rb: ; returns available chars in buffer
push temp
push buffer
ldd buffer,Y+RB_IN ; get offset, lower byte from pointer
ldd temp, Y+RB_OUT ; get out-pointer
cp buffer,temp ; if in==out it is empty
pop buffer
pop temp
ret
;---------------------------------------------------------------------------
; return first char in buffer
peek_rb: ; return first char in buffer
push XL
push XH
push temp
ldd XL,Y+RB_OUT ; get pointer as low-byte
ldd XH,Y+RB_ADRH ; get high-byte
ldd temp,Y+RB_IN ; get in-pointer
cp temp,XL
brne rb_not_empty1 ; are we filled?
sez ; set zero if empty
rjmp rb_pop_quit1
rb_not_empty1:
ld buffer, X ; read data
clz ; clear zero if full
rb_pop_quit1:
pop temp
pop XH
pop XL
ret
;---------------------------------------------------------------------------
; push char in buffer
push_rb: ; pushes "char" into receive buffer
push XL
push XH
push temp
ldd XL,Y+RB_IN ; get offset, lower byte from pointer
ldd XH,Y+RB_ADRH ; higher byte from buffer offset
st X+,buffer ; write byte, postincrement pointer
ldd buffer,Y+RB_MASK ; wrap buffer with mask
and XL, buffer
std Y+RB_IN,XL ; store pointer
ldd temp,Y+RB_OUT ; get out-pointer
cp temp,XL
brne rb_no_over ; not equal: didn't fill up
; sbi PORTD,LED0 ; signale overrun
inc temp ; increment out-pointer
std Y+RB_OUT,temp ; write
rb_no_over:
pop temp
pop XH
pop XL
ret
;---------------------------------------------------------------------------
; pop first char off buffer
pop_rb: ; pops char from rx-buf, return in char
push XL
push XH
push temp
ldd XL,Y+RB_OUT ; get pointer as low-byte
ldd XH,Y+RB_ADRH ; get high-byte
ldd temp,Y+RB_IN ; get in-pointer
cp temp,XL
brne rb_not_empty ; are we filled?
sez ; set zero if empty
; cbi PORTD,LED0 ; signal empty
rjmp rb_pop_quit
rb_not_empty:
ld buffer, X+ ; read data with postincrement
ldd temp,Y+RB_MASK ; wrap buffer with mask
and XL, temp
std Y+RB_OUT,XL ; write out-pointer
clz ; clear zero if full
rb_pop_quit:
pop temp
pop XH
pop XL
ret
;==================================================================================
;==================================================================================
--------------070907070901030500020802
Content-Type: text/plain;
name="los2.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="los2.diff"
diff -Nur lcdproc_cvs/server/drivers/hd44780-drivers.h lcdproc_msite/server/drivers/hd44780-drivers.h
--- lcdproc_cvs/server/drivers/hd44780-drivers.h 2007-01-29 21:37:50.000000000 +0100
+++ lcdproc_msite/server/drivers/hd44780-drivers.h 2007-03-01 18:42:50.000000000 +0100
@@ -42,6 +42,7 @@
{"picanlcd", hd_init_serial, "\tnone\n"},
{"lcdserializer", hd_init_serial, "\tnone\n"},
{"los-panel", hd_init_serial, "\tnone\n"},
+ {"los2", hd_init_serial, "\tnone\n"},
{"vdr-lcd", hd_init_serial, "\tnone\n"},
{"vdr-wakeup", hd_init_serial, "\tnone\n"},
/* End serial connectiontypes */
diff -Nur lcdproc_cvs/server/drivers/hd44780-serial.c lcdproc_msite/server/drivers/hd44780-serial.c
--- lcdproc_cvs/server/drivers/hd44780-serial.c 2007-02-21 17:19:22.000000000 +0100
+++ lcdproc_msite/server/drivers/hd44780-serial.c 2007-03-01 18:08:26.000000000 +0100
@@ -37,6 +37,7 @@
#include <stdio.h>
#include <sys/types.h>
+#include <sys/time.h>
#include <fcntl.h>
#include <termios.h>
@@ -116,10 +117,12 @@
return 1;
}
-static int lastdisplayID;
-
void serial_HD44780_senddata (PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch);
void serial_HD44780_backlight (PrivateData *p, unsigned char state);
+void serial_HD44780_set_brightness (PrivateData *p, unsigned char state, int promille);
+int serial_HD44780_get_brightness (PrivateData *p, unsigned char state);
+void serial_HD44780_set_contrast (PrivateData *p, int promille);
+int serial_HD44780_get_contrast (PrivateData *p);
unsigned char serial_HD44780_scankeypad (PrivateData *p);
void serial_HD44780_close (PrivateData *p);
@@ -139,18 +142,18 @@
char conf_serialif[SERIALIF_NAME_LENGTH];
strncpy(conf_serialif, drvthis->config_get_string(drvthis->name, "connectiontype", 0, ""), SERIALIF_NAME_LENGTH);
- conf_serialif[SERIALIF_NAME_LENGTH-1] = '\0';
- p->serial_type = 0;
- for (counter = 0; counter < (sizeof(serial_interfaces)/sizeof(SerialInterface)); counter++) {
+ conf_serialif[SERIALIF_NAME_LENGTH-1]='\0';
+ p->serial_type=0;
+ for (counter=0; counter<(sizeof(serial_interfaces)/sizeof(SerialInterface)); counter++) {
if (strcasecmp(conf_serialif, serial_interfaces[counter].name) == 0) {
- p->serial_type = counter;
+ p->serial_type=counter;
break;
}
}
if (p->serial_type != counter) {
report(RPT_ERR, "HD44780: serial: serial interface %s unknown", conf_serialif);
report(RPT_ERR, "HD44780: serial: available interfaces:");
- for (counter = 0; counter < (sizeof(serial_interfaces)/sizeof(SerialInterface)); counter++)
+ for (counter=0; counter<(sizeof(serial_interfaces)/sizeof(SerialInterface)); counter++)
report(RPT_ERR, " %s", serial_interfaces[counter].name);
return -1;
}
@@ -163,19 +166,27 @@
report (RPT_ERR, "HD44780: serial: check your configuration file and disable it");
return -1;
}
- if (p->have_backlight && !(SERIAL_IF.backlight)) {
- report (RPT_ERR, "HD44780: serial: backlight control is not supported by %s", SERIAL_IF.name);
- report (RPT_ERR, "HD44780: serial: check your configuration file and disable it");
- return -1;
+ if (p->have_backlight) {
+ if ( !(SERIAL_IF.backlight)) {
+ report (RPT_ERR, "HD44780: serial: backlight control is not supported by %s", SERIAL_IF.name);
+ report (RPT_ERR, "HD44780: serial: check your configuration file and disable it");
+ return -1;
+ }
+ p->backbright_on = drvthis->config_get_int(drvthis->name, "OnBrightness", 0, 1000);
+ p->backbright_off = drvthis->config_get_int(drvthis->name, "OffBrightness", 0, 300);
+ report(RPT_ERR, "HD44780: serial: brightness on:%d off:%d.\n",p->backbright_on,p->backbright_off);
}
+ p->contrast = drvthis->config_get_int(drvthis->name, "Contrast", 0, 0);
+ report(RPT_ERR, "HD44780: serial: contrast:%d .\n",p->contrast);
+
/* Get bitrate */
unsigned int conf_bitrate;
size_t bitrate;
- conf_bitrate = drvthis->config_get_int(drvthis->name, "Speed", 0, SERIAL_IF.default_bitrate);
- if (conf_bitrate==0)
- conf_bitrate = SERIAL_IF.default_bitrate;
+ conf_bitrate=atoi( drvthis->config_get_string(drvthis->name, "Speed", 0, "0") );
+ if (conf_bitrate==0)
+ conf_bitrate=SERIAL_IF.default_bitrate;
if (convert_bitrate(conf_bitrate, &bitrate)) {
report(RPT_ERR, "HD44780: serial: invalid configured bitrate speed");
return -1;
@@ -218,22 +229,31 @@
/* Set TCSANOW mode of serial device */
tcsetattr(p->fd, TCSANOW, &portset);
- lastdisplayID = -1;
-
/* Assign functions */
p->hd44780_functions->senddata = serial_HD44780_senddata;
- p->hd44780_functions->backlight = serial_HD44780_backlight;
+
+ if ( p->have_backlight) {
+ p->hd44780_functions->backlight = serial_HD44780_backlight;
+
+ p->hd44780_functions->get_brightness = serial_HD44780_get_brightness;
+ p->hd44780_functions->set_brightness = serial_HD44780_set_brightness;
+ }
+
+ p->hd44780_functions->get_contrast = serial_HD44780_get_contrast;
+ p->hd44780_functions->set_contrast = serial_HD44780_set_contrast;
+
if (p->have_keypad)
p->hd44780_functions->scankeypad = serial_HD44780_scankeypad;
- p->hd44780_functions->close = serial_HD44780_close;
-
+ report (RPT_INFO,"HD44780: serial: %d", p->have_keypad);
+ p->hd44780_functions->close = serial_HD44780_close;
+
/* Do initialization */
if (SERIAL_IF.if_bits == 8) {
- report(RPT_INFO,"HD44780: serial: initializing with 8 bits interface");
- common_init(p, IF_8BIT);
+ report (RPT_INFO,"HD44780: serial: initializing with 8 bits interface");
+ common_init (p, IF_8BIT);
} else {
report (RPT_INFO,"HD44780: serial: initializing with 4 bits interface");
- common_init(p, IF_4BIT);
+ common_init (p, IF_4BIT);
}
return 0;
@@ -243,67 +263,174 @@
void
serial_HD44780_senddata (PrivateData *p, unsigned char displayID, unsigned char flags, unsigned char ch)
{
- /* Filter illegally sent escape characters (for interfaces without data escape) */
- if (flags == RS_DATA && SERIAL_IF.data_escape == 0 && ch == SERIAL_IF.instruction_escape)
- ch='?';
-
+ static int lastdisplayID = -1;
+ unsigned char sbuffer[3];
+ int i=0;
+
if (flags == RS_DATA) {
- /* Do we need a DATA indicator byte? */
- if ((SERIAL_IF.data_escape != '\0') &&
- (ch >= SERIAL_IF.data_escape_min) &&
- (ch < SERIAL_IF.data_escape_max) ||
- (SERIAL_IF.multiple_displays && displayID != lastdisplayID)) {
- write(p->fd, &SERIAL_IF.data_escape + displayID, 1);
+/*
+ // Filter illegally sent escape characters (for interfaces without data escape)
+ if ( SERIAL_IF.data_escape == 0) {
+ // stuff escape with escape
+ if ( ch == 0xfe ) write( p->fd, &ch, 1 );
+ } else {
+ // Do we need a DATA indicator byte?
+ if ( ch < SERIAL_IF.data_escape_max ) {
+ write( p->fd, &SERIAL_IF.data_escape, 1 );
+ }
}
- write(p->fd, &ch, 1);
+*/
+ if ( ((SERIAL_IF.data_escape != '\0') &&
+ (ch >= SERIAL_IF.data_escape_min) &&
+ (ch < SERIAL_IF.data_escape_max)) ||
+ (SERIAL_IF.multiple_displays && displayID != lastdisplayID)) {
+ sbuffer[ i++] = SERIAL_IF.data_escape + displayID;
+ } else {
+ // byte stuff escape in data
+ if ( ch == SERIAL_IF.instruction_escape ) {
+ if ( SERIAL_IF.byte_stuff) sbuffer[ i++] = ch;
+ else ch = '?';
+ }
+ }
+ // copy data to buffer
}
else {
- write(p->fd, &SERIAL_IF.instruction_escape, 1);
- write(p->fd, &ch, 1);
- }
- lastdisplayID = displayID;
+ // send escape
+ sbuffer[ i++] = SERIAL_IF.instruction_escape;
+
+ // is there a instruction code?
+ if ( SERIAL_IF.instruction_code != 0) sbuffer[ i++] = SERIAL_IF.instruction_code;
+
+ // send instruction
+ }
+ sbuffer[ i++] = ch;
+ write( p->fd, sbuffer, i);
+
+ lastdisplayID = displayID;
}
void
-serial_HD44780_backlight (PrivateData *p, unsigned char state)
-{
- if (p->have_backlight) {
- if (SERIAL_IF.backlight_escape) {
- unsigned char send[2];
- send[0] = SERIAL_IF.backlight_escape;
- send[1] = state ? 0 : 0xFF;
- write(p->fd, &send, 2);
- }
- else {
- unsigned char send[1];
- send[0] = state ? SERIAL_IF.backlight_on : SERIAL_IF.backlight_off;
- write(p->fd, &send, 1);
- }
+serial_HD44780_backlight (PrivateData *p, unsigned char state) {
+
+ unsigned char sbuffer[3];
+ int i = 0;
+
+ /* TODO */
+ if ( p->have_backlight) {
+ if (SERIAL_IF.backlight_escape) {
+ // write escape
+ sbuffer[ i++] = SERIAL_IF.backlight_escape;
+
+ // write function-code if appropriate
+ if ( SERIAL_IF.backlight_code != 0) sbuffer[ i++] = SERIAL_IF.backlight_code;
+
+ // send scaled brightness
+ sbuffer[ i++] = (( state ? p->backbright_on : p->backbright_off) / 4) & 0xff;
+ }
+ else {
+ sbuffer[ i++] = state ? SERIAL_IF.backlight_on : SERIAL_IF.backlight_off;
+ }
+
+ write( p->fd, sbuffer, i);
+// report (RPT_INFO,"HD44780: serial: backlight @ %d", state);
+ } else {
+// report (RPT_INFO,"HD44780: serial: can't set backlight @ %d", state);
}
+ // track backlight state, so we can do live-update for set_brightness
+ p->backlight_bit = state;
+}
+
+void
+serial_HD44780_set_brightness (PrivateData *p, unsigned char state, int promille) {
+ // clip values to 0...1000
+ if ( promille > 1000) promille = 1000;
+ if ( promille < 0) promille = 0;
+
+ if ( state) p->backbright_on = promille;
+ else p->backbright_off = promille;
+
+ // do a live update
+ if ( p->backlight_bit == state) serial_HD44780_backlight( p, state);
+}
+
+int
+serial_HD44780_get_brightness (PrivateData *p, unsigned char state) {
+ return ( state ? p->backbright_on : p->backbright_off);
+}
+
+void
+serial_HD44780_set_contrast (PrivateData *p, int promille) {
+ unsigned char sbuffer[3];
+ int i = 0;
+
+ // clip value
+ if ( promille > 1000) promille = 1000;
+ if ( promille < 0) promille = 0;
+
+ p->contrast = promille;
+
+ // send escape
+ sbuffer[ i++] = SERIAL_IF.instruction_escape;
+
+ // send function code CONTRAST
+ sbuffer[ i++] = SERIAL_IF.contrast_code;
+
+ // send contrast value
+ sbuffer[ i++] = ( promille / 4) & 0xff;
+ write( p->fd, sbuffer, i);
+}
+
+int
+serial_HD44780_get_contrast (PrivateData *p) {
+ return p->contrast;
}
unsigned char
serial_HD44780_scankeypad (PrivateData *p)
{
- unsigned char buffer = 0;
- char hangcheck = 100;
+ static int keyesc = 0;
+ char buffer = 0;
- read(p->fd, &buffer, 1);
- if (buffer == SERIAL_IF.keypad_escape) {
- while (hangcheck > 0) {
- /* Check if I can read another byte */
- if (read(p->fd, &buffer, 1) == 1) {
- return buffer;
- }
- hangcheck--;
- }
+ fd_set rfds;
+ struct timeval timeout;
+ int retval;
+
+ // wait/sleep for 10000us = 10ms
+ FD_ZERO(&rfds);
+ FD_SET( p->fd, &rfds);
+ timeout.tv_sec = 0;
+ timeout.tv_usec = 10000;
+ retval = select( p->fd + 1, &rfds, NULL, NULL, &timeout);
+
+ // any descriptor ready?
+ if ( retval <= 0) return 0;
+
+ // get char
+ read( p->fd, &buffer, 1);
+
+ // use key escape mode to skip power-on-message
+
+ // was previous char key esc?
+ if ( keyesc == 1) {
+ // yes: buffer contains key-code, leave key-esc mode
+ keyesc = 0;
+ } else {
+ // no, received key-esc?
+ if ( buffer == SERIAL_IF.keypad_escape) keyesc = 1;
+
+ // swallow escape, return "nothing"
+ buffer = 0;
}
- return 0;
+
+ return buffer;
}
void
serial_HD44780_close (PrivateData *p)
{
+ // switch backlight off
+ serial_HD44780_backlight( p, 0);
+
if (SERIAL_IF.end_code)
write(p->fd, &SERIAL_IF.end_code, 1);
close(p->fd);
diff -Nur lcdproc_cvs/server/drivers/hd44780-serial.h lcdproc_msite/server/drivers/hd44780-serial.h
--- lcdproc_cvs/server/drivers/hd44780-serial.h 2007-02-02 17:46:07.000000000 +0100
+++ lcdproc_msite/server/drivers/hd44780-serial.h 2007-03-01 17:52:55.000000000 +0100
@@ -10,7 +10,9 @@
typedef struct SerialInterface {
char name[SERIALIF_NAME_LENGTH];
char instruction_escape;
+ char instruction_code; /* code sent after instr-esc (if != 0) */
char data_escape;
+ char byte_stuff; /* byte stuff if instr-escape is in data (if != 0)*/
char data_escape_min; /* escaped data lower limit */
char data_escape_max; /* escaped data upper limit */
unsigned int default_bitrate;
@@ -19,23 +21,32 @@
char keypad_escape;
char backlight;
char backlight_escape; /* leave to 0 is the interface uses on/off codes */
+ char backlight_code; /* code sent after backlight-esc (if != 0) */
char backlight_off;
char backlight_on; /* leave these two to 0 is backlight_escape is set */
+ char contrast_code; /* code sent after instr-esc (if != 0) */
char multiple_displays;
char end_code; /* code to send on shutdown */
} SerialInterface;
/* List of connectiontypes managed by this driver, if you change
something here, remember also to change hd44780-drivers.h */
+
+ /*
+ * needed to add "instruction codes" for intruction/backlight/contrast
+ * added byte_stuffed
+ */
static const SerialInterface serial_interfaces[] = {
- /* name instr data v ^ bitrate bits K esc B Besc Boff Bon Multi End */
- { "picanlcd", 0x11, 0x12, 0x00, 0x20, 9600, 8, 0, 0x00, 0, 0, 0, 0, 0, 0 },
- { "lcdserializer", 0xFE, 0, 0x00, 0x00, 9600, 8, 0, 0x00, 0, 0, 0, 0, 0, 0 },
- { "los-panel", 0xFE, 0, 0x00, 0x00, 9600, 4, 1, 0xFE, 1, 0xFF, 0, 0, 0, 0 },
- { "vdr-lcd", 0xFE, 0, 0x00, 0x00, 9600, 4, 0, 0x00, 0, 0, 0, 0, 0, 0 },
- { "vdr-wakeup", 0xC0, 0xC4, 0xC0, 0xD0, 9600, 4, 0, 0x00, 1, 0, 0xC9, 0xC8, 1, 0xCF }
+ /* name instr ic data stuff v ^ bitrate bits K esc B Besc Bcode Boff Bon ctrst Multi End */
+ { "picanlcd", 0x11, 0, 0x12, 0, 0x00, 0x20, 9600, 8, 0, 0x00, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { "lcdserializer", 0xFE, 0, 0, 0, 0x00, 0x00, 9600, 8, 0, 0x00, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { "los-panel", 0xFE, 0, 0, 0, 0x00, 0x00, 9600, 4, 1, 0xFE, 1, 0xFF, 0, 0, 0, 0, 0, 0 },
+ { "los2", 0xFE, 1, 0, 1, 0x00, 0x00, 9600, 4, 1, 0xFE, 1, 0xFE, 2, 0, 0, 3, 0, 0 },
+ { "vdr-lcd", 0xFE, 0, 0, 0, 0x00, 0x00, 9600, 4, 0, 0x00, 0, 0, 0, 0, 0, 0, 0, 0 },
+ { "vdr-wakeup", 0xC0, 0, 0xC4, 0, 0xC0, 0xD0, 9600, 4, 0, 0x00, 1, 0, 0,0xC9, 0xC8, 0, 1, 0xCF }
};
+
/* initialize this particular driver */
int hd_init_serial (Driver *drvthis);
diff -Nur lcdproc_cvs/server/drivers/hd44780.c lcdproc_msite/server/drivers/hd44780.c
--- lcdproc_cvs/server/drivers/hd44780.c 2007-02-04 13:26:55.000000000 +0100
+++ lcdproc_msite/server/drivers/hd44780.c 2007-03-01 18:40:42.000000000 +0100
@@ -634,6 +633,46 @@
}
/////////////////////////////////////////////////////////////////
+// Sets the backlight brightness according to state
+//
+MODULE_EXPORT void
+HD44780_set_brightness(Driver *drvthis, int on, int promille)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ p->hd44780_functions->set_brightness(p, on, promille);
+}
+
+/////////////////////////////////////////////////////////////////
+// Retrieves backlight brightness according to state
+//
+MODULE_EXPORT int
+HD44780_get_brightness(Driver *drvthis, int on)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ return p->hd44780_functions->get_brightness(p, on);
+}
+
+/////////////////////////////////////////////////////////////////
+// Sets the contrast
+//
+MODULE_EXPORT void
+HD44780_set_contrast(Driver *drvthis, int promille)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ p->hd44780_functions->set_contrast(p, promille);
+}
+
+/////////////////////////////////////////////////////////////////
+// Retrieves contrast
+//
+MODULE_EXPORT int
+HD44780_get_contrast(Driver *drvthis)
+{
+ PrivateData *p = (PrivateData *) drvthis->private_data;
+ return p->hd44780_functions->get_contrast(p);
+}
+
+/////////////////////////////////////////////////////////////////
// Draws a vertical bar...
//
MODULE_EXPORT void
@@ -737,10 +776,9 @@
}
// Lib_adv_bignum does everything needed to show the bignumbers.
- lib_adv_bignum(drvthis, x, num, 0, do_init);
+ lib_adv_bignum(drvthis, x, num, do_init, NUM_CCs);
}
-
/**
* Get number of custom characters available.
* \param drvthis Pointer to driver structure.
@@ -749,12 +787,10 @@
MODULE_EXPORT int
HD44780_get_free_chars(Driver *drvthis)
{
-//PrivateData *p = drvthis->private_data;
-
- return NUM_CCs;
+ //PrivateData *p = drvthis->private_data;
+ return NUM_CCs;
}
-
-
+
/////////////////////////////////////////////////////////////////
// Sets a custom character from 0-7...
//
@@ -976,7 +1012,10 @@
gettimeofday(&curr_time,NULL);
scancode = p->hd44780_functions->scankeypad(p);
+
if ( scancode ) {
+// report(RPT_INFO, "HD44780_get_key: Key pressed: %02x (%d,%d)",
+// scancode, scancode&0x0F, (scancode&0xF0)>>4 );
if ( scancode & 0xF0 ) {
keystr = p->keyMapMatrix[((scancode&0xF0)>>4)-1][(scancode&0x0F)-1];
}
diff -Nur lcdproc_cvs/server/drivers/hd44780.h lcdproc_msite/server/drivers/hd44780.h
--- lcdproc_cvs/server/drivers/hd44780.h 2006-10-15 12:45:47.000000000 +0200
+++ lcdproc_msite/server/drivers/hd44780.h 2007-03-01 17:48:16.000000000 +0100
@@ -35,9 +35,17 @@
MODULE_EXPORT int HD44780_icon (Driver *drvthis, int x, int y, int icon);
MODULE_EXPORT void HD44780_set_char (Driver *drvthis, int n, unsigned char *dat);
MODULE_EXPORT int HD44780_get_free_chars(Driver *drvthis);
+// added for los2
MODULE_EXPORT void HD44780_backlight (Driver *drvthis, int on);
+
+MODULE_EXPORT void HD44780_set_brightness (Driver *drvthis, int state, int level);
+MODULE_EXPORT int HD44780_get_brightness (Driver *drvthis, int state);
+
+MODULE_EXPORT void HD44780_set_contrast (Driver *drvthis, int level);
+MODULE_EXPORT int HD44780_get_contrast (Driver *drvthis);
+// end adding
+
MODULE_EXPORT void HD44780_output (Driver *drvthis, int state);
MODULE_EXPORT const char * HD44780_get_key (Driver *drvthis);
--------------070907070901030500020802--