📄 led.c
字号:
/*
* Copyright 1999, 2000, 2001, 2002 Lucent Technologies Inc.
* All Rights Reserved.
* Information Sciences Research Center, Bell Labs.
*
* LUCENT TECHNOLOGIES DOES NOT CLAIM MERCHANTABILITY OF THIS SOFTWARE
* OR THE SUITABILITY OF THIS SOFTWARE FOR ANY PARTICULAR PURPOSE. The
* software is provided "as is" without expressed or implied warranty
* of any kind.
*
* These notices must be retained in any copies of any part of this
* software.
*
*/
/*
* combined LED, LCD, and BCR (board configuration register) driver
*
* Everything send to the LED is printed on the top line of the LCD display.
*
* In addition, can write a character anywhere on the LCD display.
*
* Runs in user mode with interrupts enabled.
*
* This driver is based in part on PMON sources from Algorithmics,
* which are in the public domain.
*/
#include "pebble.h"
#include "string.h"
#include "machine/cpu.h"
#ifndef Cobalt
#include "sbd.h"
#include "rtc.h"
#include "lcd.h"
#else
#include "qube.h"
#endif
#include "mem.h"
#include "time.h"
#include "synch.h"
#ifndef Cobalt /* presently not supported on Cobalt */
#define LED_START ((volatile uint *)(IO_BASE+LED_BASE))
#define LCD_START ((volatile uint *)(IO_BASE+LCD_BASE))
static volatile lcddev *lcd = (lcddev *)LCD_START;
static int lcd_present = 0;
static int lcd_sem, led_sem;
const char LCD_NOT_PRESENT[] = "LCD not present";
const char INVALID_LCD_ADDRESS[] = "invalid LCD row/column address";
/* first the board configuration register code */
/* portal implementation */
int
sys_bcr_clear(Thread *t, uint mask)
{
int i;
int *addr;
#ifdef P4032
/* first do the low bits */
addr = (int *) (IO_BASE + BCR_BASE);
for (i = 0; i < 8; ++i) {
if (mask & 01) {
*addr = 0;
}
addr++;
mask >>= 1;
}
#else
/* first do the low bits */
addr = (int *) (IO_BASE + BCR0_BASE);
for (i = 0; i < 8; ++i) {
if (mask & 01) {
*addr = 0;
}
addr++;
mask >>= 1;
}
addr = (int *) (IO_BASE + BCR1_BASE);
for (i = 0; i < 8; ++i) {
if (mask & 01) {
*addr = 0;
}
addr++;
mask >>= 1;
}
#endif
return(0);
}
/* portal implementation */
int
sys_bcr_set(Thread *t, uint mask)
{
int i;
int *addr;
#ifdef P4032
/* first do the low bits */
addr = (int *) (IO_BASE + BCR_BASE);
for (i = 0; i < 8; ++i) {
if (mask & 01) {
*addr = 1;
}
addr++;
mask >>= 1;
}
#else
/* first do the low bits */
addr = (int *) (IO_BASE + BCR0_BASE);
for (i = 0; i < 8; ++i) {
if (mask & 01) {
*addr = 1;
}
addr++;
mask >>= 1;
}
addr = (int *) (IO_BASE + BCR1_BASE);
for (i = 0; i < 8; ++i) {
if (mask & 01) {
*addr = 1;
}
addr++;
mask >>= 1;
}
#endif
return(0);
}
/*
* lcd driver code
*/
/* checks whether the LCD is busy. Takes at least one usec. */
static int
lcd_busy(void)
{
us_delay(1);
return (lcd->lcd_stat & LCD_STAT_BUSY) != 0;
}
/* waits until LCD is free again */
static int
lcd_wait(void)
{
int i;
int busy;
int iter = 2000; /* about 2msec. */
for (i = 0; ((busy = lcd_busy()) != 0) && (i < iter); i++)
;
return (busy)? -1 : 0;
}
static void
lcd_command(uchar cmd)
{
if (lcd_wait() < 0)
return;
lcd->lcd_cmd = cmd;
us_delay(40);
}
static uint
lcd_rdata(void)
{
uint data;
lcd_wait();
data = lcd->lcd_data & 0xff;
us_delay(40);
return data;
}
static void
lcd_wdata(char c)
{
if (lcd_wait() < 0)
return;
lcd->lcd_data = c;
us_delay(40);
}
static void
lcd_init(void)
{
/* test pattern for display data memory */
static const uchar tpat[4] = {0xaa, 0x55, 0xff, 0x00};
int i;
lcd_present = 0;
/* should we wait a little here? */
if (lcd_wait() < 0)
return;
lcd_command (LCD_CLEAR);
/* should be busy */
if (lcd_busy() == 0)
return;
/* initialize the display */
lcd_command (LCD_FUNC | LCD_FUNC_8BIT | LCD_FUNC_2LINE | LCD_FUNC_5x7);
lcd_command (LCD_CTRL | LCD_CTRL_DISPLAY);
lcd_command (LCD_MODE | LCD_MODE_INCR);
lcd_command (LCD_HOME);
/* store pattern into display memory */
lcd_command (LCD_SET_DDADDR | 0);
for (i = 0; i < sizeof(tpat); i++)
lcd_wdata (tpat[i]);
/* read back pattern */
lcd_command (LCD_SET_DDADDR | 0);
for (i = 0; i < sizeof(tpat); i++) {
/* check dd ram contents */
if (lcd_rdata () != tpat[i])
return;
}
lcd_present = 1;
}
/*
* write a NULL terminated string at specified position
* Only up to LCD_CHARS chars are printed from the string.
*
* The write to the LCD is protected with a semaphore against
* concurrent access. Note that we must not use mutex locks,
* since this is a slow operation and the LCD driver runs with
* interrupts enabled.
*/
int
lcd_write(int row, int col, const char *s)
{
int i;
int addr;
if (!lcd_present)
error(LCD_NOT_PRESENT);
if (row < 0 || row >= LCD_LINES || col < 0 || col >= LCD_CHARS)
error(INVALID_LCD_ADDRESS);
sem_wait(lcd_sem);
addr = row * 0x40 + col;
lcd_command(LCD_SET_DDADDR | addr);
for (i = 0; (col + i) < LCD_CHARS && s[i] != 0; i++)
lcd_wdata(s[i]);
sem_post(lcd_sem);
return i;
}
static void
lcd_write_top_line(const char *s, int len)
{
int i;
char line[LCD_CHARS];
for (i = 0; (i < len) && (i < LCD_CHARS); i++) {
line[i] = s[i];
if (line[i] < ' ') /* control characters */
line[i] = ' ';
}
/* fill the rest of the line with blanks */
for (; i < LCD_CHARS; i++)
line[i] = ' ';
if (lcd_present)
lcd_write(0, 0, line);
}
/*
* led driver code
*
* The write to the LED is protected with a semaphore against
* concurrent access. Note that we must not use mutex locks,
* since the LED driver runs with interrupts enabled.
*/
static int
led_write(char *str, int len)
{
int i = 0;
/* turn on LED */
sys_bcr_set(NULL, BCR_LED_ON);
/* show chars */
sem_wait(led_sem);
if (str != NULL)
for (i = 0; i < 4 && i < len && str[i] != '\0' && str[i] != '\n'; i++)
LED_START[3-i] = str[i] & 0xff;
/* blank unfilled spaces */
for (; i < 4; i++)
LED_START[3-i] = ' ';
sem_post(led_sem);
lcd_write_top_line(str, len);
return i;
}
/* writes string up to 4 chars of string s to LED */
int
sys_led_write(Thread *t, char *str, int len)
{
param_check(str, len, 0);
return led_write(str, len);
}
/* writes a string to LCD */
int
sys_lcd_write(Thread *t, int row, int col, const char *s)
{
param_check(s, LCD_CHARS, 0);
return lcd_write(row, col, s);
}
#else /* Cobalt - dummy functions */
static int lcd_present = 0;
static int lcd_sem, led_sem;
static void
lcd_init()
{
}
static int
led_write(char *str, int len)
{
return 0;
}
int
sys_bcr_clear(Thread *t, uint mask)
{
return 0;
}
int
sys_bcr_set(Thread *t, uint mask)
{
return 0;
}
int
sys_led_write(Thread *t, char *str, int len)
{
return 0;
}
int
sys_lcd_write(Thread *t, int row, int col, const char *s)
{
return 0;
}
#endif /* !Cobalt */
/*
* initialization
*/
/* driver initialization thread */
int main()
{
int x;
int lcd_id;
char *msg = "LED & LCD";
/* verify that we are running in user mode with interrupts enabled */
if (!check_psw(1,1)) {
printf("led: invalid processor status: %08lx\n", get_psw());
task_exit(1);
}
printf("LED and LCD initialization. asid=%d stack at %p\n",
get_asid(), &x);
if ((led_sem = sem_create(1)) < 0)
panic("sem_create of led_sem failed");
if ((lcd_sem = sem_create(1)) < 0)
panic("sem_create of lcd_sem failed");
lcd_init();
if (lcd_present)
printf("LCD initialized\n");
else
printf("LCD is missing\n");
/* cannot call sys_led_write, */
/* since it expects the argument to reside on system stack */
/* only first four characters will apprer on LED */
led_write(msg, strlen(msg));
if (portal_create(WRITE2PORT(3), "smtiii", 0, sys_led_write, 0) < 0)
panic("portal_create for led_write on standard error");
if (portal_create_pair("led", NULL, sys_led_write) < 0)
panic("portal_create_pair for led failed");
if (lcd_present) {
if ((lcd_id = portal_create(-1, "smtiii", 0, sys_lcd_write, 0))
< 0)
panic("portal_create for sys_lcd_write failed");
if (portal_name(lcd_id, "lcd", 1) < 0)
panic("portal_name for lcd_write failed");
}
if (portal_create(SYS_BCR_SET, "smtiii", 0, sys_bcr_set, 0) < 0)
panic("portal_create for bcr_set() failed\n");
if (portal_create(SYS_BCR_CLEAR, "smtiii", 0, sys_bcr_clear, 0) < 0)
panic("portal_create for bcr_clear() failed\n");
/*
* return to initialization code.
* cannot just "return", since the startup code (crt0.S) calls
* exit when main routine terminates.
*/
call_portal(SYS_RTN_RPC);
return(1);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -