rockbox/apps/plugins/matrix.c
Thomas Martitz 249bba03f1 Initial commit of the Samsung YP-R0 port.
This port is a hybrid native/RaaA port. It runs on a embedded linux system,
but is the only application. It therefore can implement lots of stuff that
native targets also implement, while leveraging the underlying linux kernel.

The port is quite advanced. User interface, audio playback, plugins work
mostly fine. Missing is e.g. power mangement and USB (see SamsungYPR0 wiki page).

Included in utils/ypr0tools are scripts and programs required to generate
a patched firmware. The patched firmware has the rootfs modified to load
Rockbox. It includes a early/safe USB mode.

This port needs a new toolchain, one that includes glibc headers and libraries.
rockboxdev.sh can generate it, but e.g. codesourcey and distro packages may
also work.

Most of the initial effort is done by Lorenzo Miori and others (on ABI),
including reverse engineering and patching of the original firmware,
initial drivers, and more. Big thanks to you.

Flyspray: FS#12348
Author: Lorenzo Miori, myself

Merry christmas to ypr0 owners! :)

git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31415 a1c6a512-1295-4272-9138-f99709370657
2011-12-24 11:56:46 +00:00

417 lines
13 KiB
C

/***************************************************************************
* __________ __ ___.
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
* \/ \/ \/ \/ \/
* $Id$
*
* Copyright (C) 1999 Chris Allegretta
* Copyright (C) 2005 Alastair S - ported to podzilla
* Copyright (C) 2005 Jonas Häggqvist - ported to rockbox
*
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
****************************************************************************/
/*
* TODO:
* - The font is a bit large, create smaller one
* - For colour/greyscale displays, the font from the xscreensaver xmatrix
* should be converted and used
* BUGS:
* - The animation "dies" after a few seconds, not sure why. Works in sim.
* Symtom Fixed Oct 2007 GRaTT (Gerritt Gonzales)
*/
#include "plugin.h"
/* Images */
#include "pluginbitmaps/matrix_bold.h"
#include "pluginbitmaps/matrix_normal.h"
#define MAXCHARS 27 - 1
#define COL_W 14
#define COL_H 15
#define COLS LCD_WIDTH/COL_W
#define ROWS LCD_HEIGHT/COL_H
#define LEFTMARGIN (LCD_WIDTH-(COLS*COL_W))/2
#define TOPMARGIN (LCD_HEIGHT-(ROWS*COL_H))/2
#if (CONFIG_KEYPAD == IPOD_4G_PAD) || \
(CONFIG_KEYPAD == IPOD_3G_PAD) || \
(CONFIG_KEYPAD == IPOD_1G2G_PAD)
#define MATRIX_EXIT BUTTON_MENU
#define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
#define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
#define MATRIX_PAUSE BUTTON_PLAY
#elif (CONFIG_KEYPAD == IRIVER_H100_PAD) || \
(CONFIG_KEYPAD == IRIVER_H300_PAD)
#define MATRIX_EXIT BUTTON_OFF
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_SELECT
#elif (CONFIG_KEYPAD == IRIVER_H10_PAD)
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_SCROLL_UP|BUTTON_REPEAT
#define MATRIX_SLEEP_LESS BUTTON_SCROLL_DOWN|BUTTON_REPEAT
#define MATRIX_PAUSE BUTTON_PLAY
#elif (CONFIG_KEYPAD == IAUDIO_X5M5_PAD)
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif (CONFIG_KEYPAD == GIGABEAT_PAD)
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_SELECT
#elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
(CONFIG_KEYPAD == SANSA_CONNECT_PAD)
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
#define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
#define MATRIX_PAUSE BUTTON_SELECT
#elif CONFIG_KEYPAD == SANSA_FUZE_PAD
#define MATRIX_EXIT (BUTTON_HOME|BUTTON_REPEAT)
#define MATRIX_SLEEP_MORE BUTTON_SCROLL_BACK|BUTTON_REPEAT
#define MATRIX_SLEEP_LESS BUTTON_SCROLL_FWD|BUTTON_REPEAT
#define MATRIX_PAUSE BUTTON_SELECT
#elif CONFIG_KEYPAD == SANSA_C200_PAD
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_SELECT
#elif (CONFIG_KEYPAD == GIGABEAT_S_PAD) || \
(CONFIG_KEYPAD == SAMSUNG_YPR0_PAD)
#define MATRIX_EXIT BUTTON_BACK
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_SELECT
#elif CONFIG_KEYPAD == IAUDIO_M3_PAD
#define MATRIX_EXIT BUTTON_RC_REC
#define MATRIX_SLEEP_MORE BUTTON_RC_VOL_UP
#define MATRIX_SLEEP_LESS BUTTON_RC_VOL_DOWN
#define MATRIX_PAUSE BUTTON_RC_PLAY
#elif (CONFIG_KEYPAD == COWON_D2_PAD)
#define MATRIX_EXIT BUTTON_POWER
#elif CONFIG_KEYPAD == IAUDIO67_PAD
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_VOLUP
#define MATRIX_SLEEP_LESS BUTTON_VOLDOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == CREATIVEZVM_PAD
#define MATRIX_EXIT BUTTON_BACK
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_SELECT
#elif (CONFIG_KEYPAD == PHILIPS_HDD6330_PAD) || \
(CONFIG_KEYPAD == PHILIPS_SA9200_PAD)
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif (CONFIG_KEYPAD == ONDAVX747_PAD) || \
CONFIG_KEYPAD == ONDAVX777_PAD || \
CONFIG_KEYPAD == MROBE500_PAD
#define MATRIX_EXIT BUTTON_POWER
#elif CONFIG_KEYPAD == SAMSUNG_YH_PAD
#define MATRIX_EXIT BUTTON_REC
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
#define MATRIX_EXIT BUTTON_REC
#define MATRIX_SLEEP_MORE BUTTON_PREV
#define MATRIX_SLEEP_LESS BUTTON_NEXT
#define MATRIX_PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == MPIO_HD200_PAD
#define MATRIX_EXIT (BUTTON_REC|BUTTON_PLAY)
#define MATRIX_SLEEP_MORE BUTTON_VOL_UP
#define MATRIX_SLEEP_LESS BUTTON_VOL_DOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == MPIO_HD300_PAD
#define MATRIX_EXIT (BUTTON_REC|BUTTON_REPEAT)
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_PLAY
#elif CONFIG_KEYPAD == SANSA_FUZEPLUS_PAD
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_PLAYPAUSE
#elif CONFIG_KEYPAD == SANSA_CLIP_PAD
#define MATRIX_EXIT BUTTON_POWER
#define MATRIX_SLEEP_MORE BUTTON_UP
#define MATRIX_SLEEP_LESS BUTTON_DOWN
#define MATRIX_PAUSE BUTTON_SELECT
#else
#error Unsupported keypad
#endif
#ifdef HAVE_TOUCHSCREEN
#ifndef MATRIX_EXIT
#define MATRIX_EXIT BUTTON_TOPLEFT
#endif
#ifndef MATRIX_SLEEP_MORE
#define MATRIX_SLEEP_MORE BUTTON_MIDRIGHT
#endif
#ifndef MATRIX_SLEEP_LESS
#define MATRIX_SLEEP_LESS BUTTON_MIDLEFT
#endif
#ifndef MATRIX_PAUSE
#define MATRIX_PAUSE BUTTON_CENTER
#endif
#endif
#define SLEEP HZ/50
/* Each position is of this type */
typedef struct cmatrix {
int val;
int bold;
} cmatrix;
/* The matrix - who'd have guessed it was just a few hundred bytes? */
static cmatrix matrix[ROWS][COLS];
static int length[COLS];
static int spaces[COLS];
static int updates[COLS];
static void matrix_init(void) {
int i,j;
/* Seed rand */
rb->srand(*rb->current_tick);
/* Make the matrix */
for (i = 0; i <= ROWS; i++) {
for (j = 0; j <= COLS - 1; j++ ) {
matrix[i][j].val = -1;
matrix[i][j].bold = 0;
}
}
for (j = 0; j <= COLS - 1; j++) {
/* Set up spaces[] array of how many spaces to skip */
spaces[j] = rb->rand() % ROWS + 1;
/* And length of the stream */
length[j] = rb->rand() % (ROWS - 3) + 3;
/* Sentinel value for creation of new objects */
matrix[1][j].val = 129;
/* And set updates[] array for update speed. */
updates[j] = rb->rand() % 3 + 1;
}
}
static void matrix_blit_char(const int row, const int col, int cha)
{
if (cha == 129 || cha == 2 || cha > MAXCHARS)
cha = 0;
if (matrix[row][col].bold == 1) {
rb->lcd_bitmap_part(matrix_bold, cha*COL_W, 0,
STRIDE( SCREEN_MAIN,
BMPWIDTH_matrix_bold, BMPHEIGHT_matrix_bold),
col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
}
else {
rb->lcd_bitmap_part(matrix_normal, cha*COL_W, 0,
STRIDE( SCREEN_MAIN,
BMPWIDTH_matrix_normal, BMPHEIGHT_matrix_normal),
col*COL_W + LEFTMARGIN, row*COL_H + TOPMARGIN, COL_W, COL_H);
}
}
static void matrix_loop(void)
{
int i, j = 0, y, z, firstcoldone = 0;
static int count = 0;
int randomness = 6;
count++;
if (count > 4)
count = 1;
for (j = 0; j <= COLS - 1; j++) {
if (count > updates[j]) {
/* New style scrolling */
if (matrix[0][j].val == -1 && matrix[1][j].val == 129
&& spaces[j] > 0) {
matrix[0][j].val = -1;
spaces[j]--;
} else if (matrix[0][j].val == -1 && matrix[1][j].val == 129){
length[j] = rb->rand() % (ROWS - 3) + 3;
matrix[0][j].val = rb->rand() % (MAXCHARS-1) + 1;
if (rb->rand() % 2 == 1)
matrix[0][j].bold = 2;
spaces[j] = rb->rand() % ROWS + 1;
}
i = 0;
y = 0;
firstcoldone = 0;
while (i <= ROWS) {
/* Skip over spaces */
/* this is whear the characters were disappearing */
/*
while (i <= ROWS && (matrix[i][j].val == 129 ||
matrix[i][j].val == -1))
i++;
*/
/* A little more random now for spaces */
if (rb->rand() % randomness == 1){
while (i <= ROWS && (matrix[i][j].val == 129 ||
matrix[i][j].val == -1)){
i++;
randomness--;
if(randomness <=1)
randomness = 6;}
}else{
randomness++;
if(randomness >6)
randomness = 6;
}
if (i > ROWS)
break;
/* Go to the head of this collumn */
z = i;
y = 0;
while (i <= ROWS && (matrix[i][j].val != 129 &&
matrix[i][j].val != -1)) {
i++;
y++;
}
if (i > ROWS) {
matrix[z][j].val = 129;
matrix[ROWS - 1][j].bold = 1;
matrix_blit_char(z - 1, j, matrix[z][j].val);
continue;
}
matrix[i][j].val = rb->rand() % (MAXCHARS-1) + 1;
if (matrix[i - 1][j].bold == 2) {
matrix[i - 1][j].bold = 1;
matrix[i][j].bold = 2;
}
/* If we're at the top of the collumn and it's reached its
* full length (about to start moving down), we do this
* to get it moving. This is also how we keep segments
* not already growing from growing accidentally =>
*/
if (y > length[j] || firstcoldone) {
matrix[z][j].val = 129;
matrix[0][j].val = -1;
}
firstcoldone = 1;
i++;
}
for (i = 1; i <= ROWS; i++) {
if (matrix[i][j].val == 0 || matrix[i][j].bold == 2) {
if (matrix[i][j].val == 0)
matrix_blit_char(i - 1, j, 20);
else
matrix_blit_char(i - 1, j, matrix[i][j].val);
} else {
if (matrix[i][j].val == 1)
matrix_blit_char(i - 1, j, 2);
else if (matrix[i][j].val == -1)
matrix_blit_char(i - 1, j, 129);
else
matrix_blit_char(i - 1, j, matrix[i][j].val);
}
}
}
}
}
enum plugin_status plugin_start(const void* parameter) {
int button;
int sleep = SLEEP;
bool frozen = false;
(void)parameter;
rb->lcd_set_background(LCD_BLACK);
rb->lcd_set_backdrop(NULL);
rb->lcd_clear_display();
matrix_init();
while (1) {
if (!frozen) {
matrix_loop();
rb->lcd_update();
rb->sleep(sleep);
}
button = rb->button_get(frozen);
switch(button) {
case MATRIX_PAUSE:
frozen = !frozen;
break;
case MATRIX_EXIT:
return PLUGIN_OK;
break;
case MATRIX_SLEEP_MORE:
/* Sleep longer */
sleep += SLEEP;
break;
case MATRIX_SLEEP_LESS:
/* Sleep less */
sleep -= SLEEP;
if (sleep < 0) sleep = 0;
break;
default:
if (rb->default_event_handler(button) == SYS_USB_CONNECTED) {
return PLUGIN_USB_CONNECTED;
}
break;
}
}
return PLUGIN_OK;
}