summaryrefslogtreecommitdiff
path: root/apps/plugins
ModeNameSize
-rw-r--r--BUILD_OVERLAY201logplain
-rw-r--r--CATEGORIES1942logplain
-rw-r--r--SOURCES3635logplain
-rw-r--r--SUBDIRS2099logplain
-rw-r--r--alarmclock.c5994logplain
-rw-r--r--alpine_cdc.c36361logplain
-rw-r--r--battery_bench.c16668logplain
d---------beatbox72logplain
-rw-r--r--bench_mem_jpeg.c4736logplain
-rw-r--r--bench_scaler.c4164logplain
d---------bitmaps230logplain
-rw-r--r--blackjack.c54375logplain
-rw-r--r--boomshine.lua11713logplain
-rw-r--r--bounce.c26894logplain
-rw-r--r--brickmania.c89322logplain
-rw-r--r--bubbles.c91462logplain
-rw-r--r--calculator.c59854logplain
-rw-r--r--calendar.c30296logplain
-rw-r--r--chessbox.c1254logplain
d---------chessbox348logplain
-rw-r--r--chessclock.c22028logplain
-rw-r--r--chip8.c45059logplain
-rw-r--r--chopper.c25002logplain
-rw-r--r--clix.c26810logplain
d---------clock947logplain
-rw-r--r--codebuster.c16209logplain
-rw-r--r--credits.c12935logplain
-rw-r--r--credits.pl490logplain
-rw-r--r--crypt_firmware.c8880logplain
-rw-r--r--cube.c25488logplain
-rw-r--r--demystify.c11794logplain
-rw-r--r--dice.c6490logplain
-rw-r--r--dict.c9192logplain
-rw-r--r--disktidy.c16878logplain
-rw-r--r--disktidy.config380logplain
d---------doom4771logplain
-rw-r--r--elfdep.pl1085logplain
-rw-r--r--euroconverter.c17375logplain
d---------fft406logplain
-rw-r--r--fire.c10454logplain
-rw-r--r--fireworks.c18642logplain
-rw-r--r--firmware_flash.c27522logplain
-rw-r--r--flipit.c26670logplain
d---------fractals483logplain
d---------frotz1051logplain
-rw-r--r--goban.c1255logplain
d---------goban764logplain
-rw-r--r--greyscale.c13297logplain
-rw-r--r--helloworld.c1502logplain
-rw-r--r--helloworld.lua5375logplain
d---------imageviewer252logplain
-rw-r--r--invadrox.c53768logplain
-rw-r--r--iriver_flash.c20218logplain
-rw-r--r--iriverify.c4364logplain
-rw-r--r--jackpot.c10132logplain
-rw-r--r--jewels.c54895logplain
-rw-r--r--keybox.c17423logplain
-rw-r--r--lamp.c7467logplain
d---------lib2558logplain
-rw-r--r--logo.c10145logplain
d---------lua2753logplain
-rw-r--r--matrix.c12326logplain
-rw-r--r--maze.c17173logplain
-rw-r--r--mazezam.c33206logplain
-rw-r--r--md5sum.c7116logplain
-rw-r--r--metronome.c55870logplain
d---------midi482logplain
-rw-r--r--minesweeper.c27982logplain
-rw-r--r--mosaique.c7806logplain
-rw-r--r--mp3_encoder.c102430logplain
d---------mpegplayer1857logplain
-rw-r--r--nim.c8203logplain
-rw-r--r--oscilloscope.c31151logplain
d---------pacbox599logplain
d---------pdbox367logplain
-rw-r--r--pegbox.c38547logplain
-rw-r--r--pictureflow.c1265logplain
d---------pictureflow120logplain
-rw-r--r--pitch_detector.c37899logplain
-rw-r--r--plasma.c13585logplain
-rw-r--r--plugin.lds7447logplain
-rw-r--r--plugins.make3845logplain
-rw-r--r--pong.c16467logplain
-rw-r--r--ppmviewer.c9224logplain
-rw-r--r--properties.c12009logplain
-rw-r--r--random_folder_advance_config.c17530logplain
-rw-r--r--remote_control.c6796logplain
d---------reversi438logplain
-rw-r--r--robotfindskitten.c36553logplain
-rw-r--r--rockblox.c44826logplain
-rw-r--r--rockblox1d.c10566logplain
-rw-r--r--rockbox-fonts.config1543logplain
-rw-r--r--rockbox_flash.c27740logplain
-rw-r--r--rockboy.c1246logplain
d---------rockboy1518logplain
-rw-r--r--rocklife.c17255logplain
-rw-r--r--rockpaint.c93737logplain
-rw-r--r--search.c4779logplain
d---------searchengine308logplain
-rw-r--r--settings_dumper.c6145logplain
d---------shortcuts217logplain
-rw-r--r--sliding_puzzle.c25071logplain
-rw-r--r--snake.c14431logplain
-rw-r--r--snake2.c37573logplain
-rw-r--r--snake2.levels3254logplain
-rw-r--r--snow.c7087logplain
-rw-r--r--sokoban.c60289logplain
-rw-r--r--sokoban.levels16483logplain
-rw-r--r--solitaire.c60484logplain
-rw-r--r--sort.c6341logplain
-rw-r--r--spacerocks.c54261logplain
-rw-r--r--splitedit.c37405logplain
-rw-r--r--star.c34955logplain
-rw-r--r--starfield.c16263logplain
-rw-r--r--stats.c7498logplain
-rw-r--r--stopwatch.c15791logplain
-rw-r--r--stopwatch.lua9533logplain
d---------sudoku302logplain
-rw-r--r--superdom.c69656logplain
-rw-r--r--test_boost.c2399logplain
-rw-r--r--test_codec.c22432logplain
-rw-r--r--test_core_jpeg.c2804logplain
-rw-r--r--test_disk.c12360logplain
-rw-r--r--test_fps.c11245logplain
-rw-r--r--test_gfx.c15322logplain
-rw-r--r--test_grey.c8458logplain
-rw-r--r--test_greylib_bitmap_scale.c3009logplain
-rw-r--r--test_mem.c7678logplain
-rw-r--r--test_mem_jpeg.c3253logplain
-rw-r--r--test_resize.c4788logplain
-rw-r--r--test_sampr.c9841logplain
-rw-r--r--test_scanrate.c7373logplain
-rw-r--r--test_touchscreen.c4234logplain
-rw-r--r--test_viewports.c7252logplain
-rw-r--r--test_viewports.lua2907logplain
-rw-r--r--text_editor.c15560logplain
-rw-r--r--theme_remove.c20855logplain
-rw-r--r--vbrfix.c7905logplain
-rw-r--r--video.c34183logplain
-rw-r--r--viewer.c93799logplain
-rw-r--r--viewers.config1673logplain
-rw-r--r--vu_meter.c26388logplain
-rw-r--r--wav2wv.c9210logplain
-rw-r--r--wavplay.c139594logplain
-rw-r--r--wavrecord.c146631logplain
-rw-r--r--wavview.c13590logplain
-rw-r--r--wormlet.c73687logplain
-rw-r--r--xobox.c30911logplain
-rw-r--r--zxbox.c1195logplain
d---------zxbox2810logplain
___ * \______________/ \ "one" bit * * So I send out the data in a timer interrupt spawned to 0.6 ms. * In phases where the line is floating high, I can check for collisions. * (happens if the other side driving it low, too.) * * Data is transmitted in multiples of 4 bit, to ease BCD representation. */ /* 2nd level ISR for M-Bus transmission */ void transmit_isr(void) { bool exit = false; TSR4 &= ~0x01; /* clear the interrupt */ switch(gSendIRQ.step++) { case 0: and_b(~0x04, &PBDRH); /* low (read-modify-write access may have changed it while it was input) */ or_b(0x04, &PBIORH); /* drive low (output) */ break; case 1: /* 0.6 ms */ if (!gSendIRQ.bit) /* sending "zero"? */ and_b(~0x04, &PBIORH); /* float (input) */ break; case 2: /* 1.2 ms */ if (!gSendIRQ.bit && ((PBDR & PB10) == 0)) gSendIRQ.collision = true; break; case 3: /* 1.8 ms */ if (gSendIRQ.bit) /* sending "one"? */ and_b(~0x04, &PBIORH); /* float (input) */ else if ((PBDR & PB10) == 0) gSendIRQ.collision = true; break; case 4: /* 2.4 ms */ if ((PBDR & PB10) == 0) gSendIRQ.collision = true; /* prepare next round */ gSendIRQ.step = 0; gSendIRQ.bitmask >>= 1; if (gSendIRQ.bitmask) { /* new bit */ gSendIRQ.bit = (gSendIRQ.byte & gSendIRQ.bitmask) != 0; } else { /* new byte */ if (++gSendIRQ.index < gSendIRQ.send_size) { gSendIRQ.bitmask = 0x08; gSendIRQ.byte = gSendIRQ.send_buf[gSendIRQ.index]; gSendIRQ.bit = (gSendIRQ.byte & gSendIRQ.bitmask) != 0; } else exit = true; /* done */ } break; } if (exit || gSendIRQ.collision) { /* stop transmission */ or_b(0x20, PBCR1_ADDR+1); /* RxD1 again for PB10 */ timer_set_mode(TM_OFF); /* stop the timer */ gSendIRQ.busy = false; /* do this last, to avoid race conditions */ } } /* For receiving, I use the "normal" serial RX feature of the CPU, * so we can receive within an interrupt, no line polling necessary. * Luckily, the M-Bus bit always starts with a falling edge and ends with a high, * this matches with the start bit and the stop bit of a serial transmission. * The baudrate is set such that the M-Bus bit time (ca. 3ms) matches * the serial reception time of one byte, so we receive one byte per * M-Bus bit. * Start bit, 8 data bits and stop bit (total=10) nicely fall into the 5 * phases like above: * * 0 0.6 1.2 1.8 2.4 3.0 ms * | | | | | | time * __ _______________________________ * \_______/ \ "zero" bit * __ _______________ * \_______________________/ \ "one" bit * * | | | | | | | | | | | serial sampling interval * Start 0 1 2 3 4 5 6 7 Stop bit (LSB first!) * * By looking at the bit pattern in the serial byte we can distinguish * the short low from the longer low, tell "zero" and "one" apart. * So we receive 0xFE for a "zero", 0xE0 for a "one". * It may be necessary to treat the bits next to transitions as don't care, * in case the timing is not so accurate. * Bits are always sent "back-to-back", so I detect the packet end by timeout. */ void uart_init(unsigned baudrate) { RXI1 = (unsigned long)uart_rx_isr; /* install ISR */ ERI1 = (unsigned long)uart_err_isr; /* install ISR */ SCR1 = 0x00; /* disable everything; select async mode with SCK pin as I/O */ SMR1 = 0x00; /* async, 8N1, NoMultiProc, sysclock/1 */ BRR1 = ((FREQ/(32*baudrate))-1); IPRE = (IPRE & ~0xf000) | 0xc000; /* interrupt on level 12 */ rb->sleep(1); /* hardware needs to settle for at least one bit interval */ and_b(~(SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER), &SSR1); /* clear any receiver flag */ or_b(SCI_RE | SCI_RIE , &SCR1); /* enable the receiver with interrupt */ } void uart_rx_isr(void) /* RXI1 */ { unsigned char data; t_rcv_queue_entry* p_entry = &gRcvIRQ.queue[gRcvIRQ.buf_write]; /* short cut */ data = RDR1; /* get data */ and_b(~SCI_RDRF, &SSR1); /* clear data received flag */ if (gTimer.mode == TM_TRANSMIT) p_entry->error = RX_OVERLAP; /* oops, we're also transmitting, stop */ else timer_set_mode(TM_RX_TIMEOUT); /* (re)spawn timeout */ if (p_entry->error != RX_BUSY) return; if ((data & ~0x00) == 0xFE) /* 01111111 in line order (reverse) */ { /* "zero" received */ gRcvIRQ.byte <<= 1; } else if ((data & ~0x00) == 0xE0) /* 00000111 in line order (reverse) */ { /* "one" received */ gRcvIRQ.byte = gRcvIRQ.byte << 1 | 0x01; } else { /* unrecognized pulse */ p_entry->error = RX_SYMBOL; } if (p_entry->error == RX_BUSY) { if (++gRcvIRQ.bit >= 4) { /* byte completed */ if (p_entry->size >= sizeof(p_entry->buf)) { p_entry->error = RX_OVERFLOW; /* buffer full */ } else { p_entry->buf[p_entry->size] = gRcvIRQ.byte; gRcvIRQ.byte = 0; gRcvIRQ.bit = 0; p_entry->size++; } } } } void uart_err_isr(void) /* ERI1 */ { t_rcv_queue_entry* p_entry = &gRcvIRQ.queue[gRcvIRQ.buf_write]; /* short cut */ if (p_entry->error == RX_BUSY) { /* terminate reception in case of error */ if (SSR1 & SCI_FER) p_entry->error = RX_FRAMING; else if (SSR1 & SCI_ORER) p_entry->error = RX_OVERRUN; else if (SSR1 & SCI_PER) p_entry->error = RX_PARITY; } /* clear any receiver flag */ and_b(~(SCI_RDRF | SCI_ORER | SCI_FER | SCI_PER), &SSR1); } /* 2nd level ISR for receiver timeout, this finalizes reception */ void receive_timeout_isr(void) { t_rcv_queue_entry* p_entry = &gRcvIRQ.queue[gRcvIRQ.buf_write]; /* short cut */ timer_set_mode(TM_OFF); /* single shot */ if (p_entry->error == RX_BUSY) /* everthing OK so far? */ p_entry->error = RX_RECEIVED; /* end with valid data */ /* move to next queue entry */ gRcvIRQ.buf_write++; if (gRcvIRQ.buf_write >= MBUS_RCV_QUEUESIZE) gRcvIRQ.buf_write = 0; p_entry = &gRcvIRQ.queue[gRcvIRQ.buf_write]; if (gRcvIRQ.buf_write == gRcvIRQ.buf_read) { /* queue overflow */ gRcvIRQ.overflow = true; /* what can I do? Continueing overwrites the oldest. */ } gRcvIRQ.byte = 0; gRcvIRQ.bit = 0; p_entry->size = 0; p_entry->error = RX_BUSY; /* enable receive on new entry */ } /* generate the checksum */ unsigned char calc_checksum(unsigned char* p_msg, int digits) { int chk = 0; int i; for (i=0; i<digits; i++) { chk ^= p_msg[i]; } chk = (chk+1) % 16; return chk; } /****************** high-level M-Bus functions ******************/ void mbus_init(void) { /* init the send object */ rb->memset(&gSendIRQ, 0, sizeof(gSendIRQ)); timer_init(MBUS_STEP_FREQ, (MBUS_BIT_FREQ*10)/15); /* setup frequency and timeout (1.5 bit) */ /* init receiver */ rb->memset(&gRcvIRQ, 0, sizeof(gRcvIRQ)); uart_init(MBUS_BAUDRATE); } /* send out a number of BCD digits (one per byte) with M-Bus protocol */ int mbus_send(unsigned char* p_msg, int digits) { /* wait for previous transmit/receive to end */ while(gTimer.mode != TM_OFF) /* wait for "free line" */ rb->sleep(1); /* fill in our part */ rb->memcpy(gSendIRQ.send_buf, p_msg, digits); /* add checksum */ gSendIRQ.send_buf[digits] = calc_checksum(p_msg, digits); digits++; /* debug dump, to be removed */ if (gTread.foreground) { char buf[MBUS_MAX_SIZE+1]; dump_packet(buf, sizeof(buf), gSendIRQ.send_buf, digits); /*print_scroll(buf); */ } gSendIRQ.send_size = digits; /* prepare everything so the ISR can start right away */ gSendIRQ.index = 0; gSendIRQ.byte = gSendIRQ.send_buf[0]; gSendIRQ.bitmask = 0x08; gSendIRQ.step = 0; gSendIRQ.bit = (gSendIRQ.byte & gSendIRQ.bitmask) != 0; gSendIRQ.collision = false; gSendIRQ.busy = true; /* last chance to wait for a new detected receive to end */ while(gTimer.mode != TM_OFF) /* wait for "free line" */ rb->sleep(1); and_b(~0x30, PBCR1_ADDR+1); /* GPIO for PB10 */ timer_set_mode(TM_TRANSMIT); /* run */ /* make the call blocking until sent out */ rb->sleep(digits*4*HZ/MBUS_BIT_FREQ); /* should take this long */ while(gSendIRQ.busy) /* poll in case it lasts longer */ rb->sleep(1); /* (should not happen) */ /* debug output, to be removed */ if (gTread.foreground) { if (gSendIRQ.collision) print_scroll("collision"); } return gSendIRQ.collision; } /* returns the size of message copy, 0 if timed out, negative on error */ int mbus_receive(unsigned char* p_msg, unsigned bufsize, int timeout) { int retval = 0; do { if (gRcvIRQ.buf_read != gRcvIRQ.buf_write) { /* something in the queue */ t_rcv_queue_entry* p_entry = &gRcvIRQ.queue[gRcvIRQ.buf_read]; /* short cut */ if (p_entry->error == RX_RECEIVED) { /* seems valid */ rb->memcpy(p_msg, p_entry->buf, MIN(p_entry->size, bufsize)); retval = p_entry->size; /* return message size */ } else { /* an error occured */ retval = - p_entry->error; /* return negative number */ } /* next queue readout position */ gRcvIRQ.buf_read++; if (gRcvIRQ.buf_read >= MBUS_RCV_QUEUESIZE) gRcvIRQ.buf_read = 0; return retval; /* exit */ } if (timeout != 0 || gTimer.mode != TM_OFF) /* also carry on if reception in progress */ { if (timeout != -1 && timeout != 0) /* if not infinite or expired */ timeout--; rb->sleep(1); /* wait a while */ } } while (timeout != 0 || gTimer.mode != TM_OFF); return 0; /* timeout */ } /****************** MMI helper fuctions ******************/ void print_scroll(char* string) { static char screen[LINES][COLUMNS+1]; /* visible strings */ static unsigned pos = 0; /* next print position */ static unsigned screentop = 0; /* for scrolling */ if (!gTread.foreground) return; /* just to protect careless callers */ if (pos >= LINES) { /* need to scroll first */ int i; rb->lcd_clear_display(); screentop++; for (i=0; i<LINES-1; i++) rb->lcd_puts(0, i, screen[(i+screentop) % LINES]); pos = LINES-1; } /* no strncpy avail. */ rb->snprintf(screen[(pos+screentop) % LINES], sizeof(screen[0]), "%s", string); rb->lcd_puts(0, pos, screen[(pos+screentop) % LINES]); rb->lcd_update(); pos++; } void dump_packet(char* dest, int dst_size, char* src, int n) { int i; int len = MIN(dst_size-1, n); for (i=0; i<len; i++) { /* convert to hex digits */ dest[i] = src[i] < 10 ? '0' + src[i] : 'A' + src[i] - 10; } dest[i] = '\0'; /* zero terminate string */ } /****************** CD changer emulation ******************/ bool bit_test(unsigned char* buf, unsigned bit) { return (buf[bit>>2] & BIT_N(bit&3)) != 0; } void bit_set(unsigned char* buf, unsigned bit, bool val) { if (val) buf[bit>>2] |= BIT_N(bit&3); else buf[bit>>2] &= ~BIT_N(bit&3); } void emu_init(void) { rb->memset(&gEmu, 0, sizeof(gEmu)); gEmu.poll_interval = HZ; /* init the play message to 990000000000000 */ gEmu.playmsg[0] = gEmu.playmsg[1] = 0x9; /* init the changing message to 9B900000001 */ gEmu.changemsg[0] = gEmu.changemsg[2] = 0x9; gEmu.changemsg[1] = 0xB; gEmu.changemsg[10] = 0x1; /* init the disk status message to 9C1019999990 */ rb->memset(&gEmu.diskmsg, 0x9, sizeof(gEmu.diskmsg)); gEmu.diskmsg[1] = 0xC; gEmu.diskmsg[2] = gEmu.diskmsg[4] = 0x1; gEmu.diskmsg[3] = gEmu.diskmsg[11] = 0x0; } /* feed a radio command into the emulator */ void emu_process_packet(unsigned char* mbus_msg, int msg_size) { bool playmsg_dirty = false; bool diskmsg_dirty = false; if (msg_size == 2 && mbus_msg[0] == 1 && mbus_msg[1] == 8) { /* 18: ping */ mbus_send("\x09\x08", 2); /* 98: ping OK */ } else if (msg_size == 5 && mbus_msg[0] == 1 && mbus_msg[1] == 1 && mbus_msg[2] == 1) { /* set play state */ if (bit_test(mbus_msg, 16)) { if (gEmu.set_state == EMU_FF || gEmu.set_state == EMU_FR) /* was seeking? */ { /* seek to final position */ set_position(gEmu.time); } else if (gEmu.set_state != EMU_PLAYING || gEmu.set_state != EMU_PAUSED) { /* was not playing yet, better send disk message */ diskmsg_dirty = true; } set_play(); gEmu.set_state = EMU_PLAYING; playmsg_dirty = true; } if (bit_test(mbus_msg, 17)) { gEmu.set_state = EMU_PAUSED; playmsg_dirty = true; set_pause(); } if (bit_test(mbus_msg, 14)) { gEmu.set_state = EMU_STOPPED; playmsg_dirty = true; set_stop(); } if (bit_test(mbus_msg, 18)) { gEmu.set_state = EMU_FF; playmsg_dirty = true; set_pause(); } if (bit_test(mbus_msg, 19)) { gEmu.set_state = EMU_FR; playmsg_dirty = true; set_pause(); } if (bit_test(mbus_msg, 12)) /* scan stop */ { bit_set(gEmu.playmsg, 51, false); playmsg_dirty = true; } if (gEmu.set_state == EMU_FF || gEmu.set_state == EMU_FR) gEmu.poll_interval = HZ/4; /* faster refresh */ else gEmu.poll_interval = HZ; } else if (msg_size == 8 && mbus_msg[0] == 1 && mbus_msg[1] == 1 && mbus_msg[2] == 4) { /* set program mode */ gEmu.playmsg[11] = mbus_msg[3]; /* copy repeat, random, intro */ gEmu.playmsg[12] = mbus_msg[4]; /* ToDo */ playmsg_dirty = true; } else if (msg_size ==8 && mbus_msg[0] == 1 && mbus_msg[1] == 1 && mbus_msg[2] == 3) { /* changing */ gEmu.time = 0; /* reset playtime */ playmsg_dirty = true; if (mbus_msg[3] == 0) { /* changing track */ if (mbus_msg[4] == 0xA && mbus_msg[5] == 0x3) { /* next random */ gEmu.playmsg[3] = rb->rand() % 10; /* ToDo */ gEmu.playmsg[4] = rb->rand() % 10; } else if (mbus_msg[4] == 0xB && mbus_msg[5] == 0x3) { /* previous random */ gEmu.playmsg[3] = rb->rand() % 10; /* ToDo */ gEmu.playmsg[4] = rb->rand() % 10; } else { /* normal track select */ set_track(mbus_msg[4]*10 + mbus_msg[5]); } } else { /* changing disk */ diskmsg_dirty = true; gEmu.changemsg[3] = mbus_msg[3]; /* copy disk */ gEmu.diskmsg[2] = mbus_msg[3]; gEmu.changemsg[7] = gEmu.playmsg[11]; /* copy flags from status */ gEmu.changemsg[8] = gEmu.playmsg[12]; /*gEmu.playmsg[3] = 0; */ /* reset to track 1 */ /*gEmu.playmsg[4] = 1; */ mbus_send(gEmu.changemsg, sizeof(gEmu.changemsg)); } } else { /* if in doubt, send Ack */ mbus_send("\x09\x0F\x00\x00\x00\x00\x00", 7); } if (playmsg_dirty) { rb->yield(); /* give the audio thread a chance to process */ get_playmsg(); /* force update */ mbus_send(gEmu.playmsg, sizeof(gEmu.playmsg)); } if (diskmsg_dirty) { get_diskmsg(); /* force update */ mbus_send(gEmu.diskmsg, sizeof(gEmu.diskmsg)); } } /* called each second in case the emulator has something to do */ void emu_tick(void) { get_playmsg(); /* force update */ if (bit_test(gEmu.playmsg, 56)) /* play bit */ { unsigned remain; /* helper as we walk down the digits */ switch(gEmu.set_state) { case EMU_FF: gEmu.time += 10; case EMU_FR: gEmu.time -= 5; if (gEmu.time < 0) gEmu.time = 0; else if (gEmu.time > get_tracklength()) gEmu.time = get_tracklength(); /* convert value to MM:SS */ remain = (unsigned)gEmu.time; gEmu.playmsg[7] = remain / (10*60); remain -= gEmu.playmsg[7] * (10*60); gEmu.playmsg[8] = remain / 60; remain -= gEmu.playmsg[8] * 60; gEmu.playmsg[9] = remain / 10; remain -= gEmu.playmsg[9] * 10; gEmu.playmsg[10] = remain; } mbus_send(gEmu.playmsg, sizeof(gEmu.playmsg)); } } /****************** communication with Rockbox playback ******************/ /* update the play message with Rockbox info */ void get_playmsg(void) { int track, time; if (gEmu.set_state != EMU_FF && gEmu.set_state != EMU_FR) { switch(rb->audio_status()) { case AUDIO_STATUS_PLAY: print_scroll("AudioStat Play"); if (gEmu.set_state == EMU_FF || gEmu.set_state == EMU_FR) gEmu.playmsg[2] = gEmu.set_state; /* set FF/FR */ else gEmu.playmsg[2] = EMU_PLAYING; /* set normal play */ bit_set(gEmu.playmsg, 56, true); /* set play */ bit_set(gEmu.playmsg, 57, false); /* clear pause */ bit_set(gEmu.playmsg, 59, false); /* clear stop */ break; case AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE: print_scroll("AudioStat Pause"); gEmu.playmsg[2] = EMU_PAUSED; bit_set(gEmu.playmsg, 56, false); /* clear play */ bit_set(gEmu.playmsg, 57, true); /* set pause */ bit_set(gEmu.playmsg, 59, false); /* clear stop */ break; default: print_scroll("AudioStat 0"); gEmu.playmsg[2] = EMU_STOPPED; bit_set(gEmu.playmsg, 56, false); /* clear play */ bit_set(gEmu.playmsg, 57, false); /* clear pause */ bit_set(gEmu.playmsg, 59, true); /* set stop */ break; } /* convert value to MM:SS */ time = get_playtime(); gEmu.time = time; /* copy it */ gEmu.playmsg[7] = time / (10*60); time -= gEmu.playmsg[7] * (10*60); gEmu.playmsg[8] = time / 60; time -= gEmu.playmsg[8] * 60; gEmu.playmsg[9] = time / 10; time -= gEmu.playmsg[9] * 10; gEmu.playmsg[10] = time; } else /* FF/FR */ { gEmu.playmsg[2] = gEmu.set_state; /* in FF/FR, report that instead */ } track = get_track(); gEmu.playmsg[3] = track / 10; gEmu.playmsg[4] = track % 10; } /* update the disk status message with Rockbox info */ void get_diskmsg(void) { int tracks = rb->playlist_amount(); if (tracks > 99) tracks = 99; gEmu.diskmsg[5] = tracks / 10; gEmu.diskmsg[6] = tracks % 10; } /* return the current track time in seconds */ int get_playtime(void) { struct mp3entry* p_mp3entry; p_mp3entry = rb->audio_current_track(); if (p_mp3entry == NULL) return 0; return p_mp3entry->elapsed / 1000; } /* return the total length of the current track */ int get_tracklength(void) { struct mp3entry* p_mp3entry; p_mp3entry = rb->audio_current_track(); if (p_mp3entry == NULL) return 0; return p_mp3entry->length / 1000; } /* change to a new track */ void set_track(int selected) { if (selected > get_track()) { print_scroll("audio_next"); rb->audio_next(); } else if (selected < get_track()) { print_scroll("audio_prev"); rb->audio_prev(); } } /* return the track number */ int get_track(void) { struct mp3entry* p_mp3entry; p_mp3entry = rb->audio_current_track(); if (p_mp3entry == NULL) return 0; return p_mp3entry->index + 1; /* track numbers start with 1 */ } /* start or resume playback */ void set_play(void) { if (rb->audio_status() == AUDIO_STATUS_PLAY) return; if (rb->audio_status() == (AUDIO_STATUS_PLAY | AUDIO_STATUS_PAUSE)) { print_scroll("audio_resume"); rb->audio_resume(); } else { print_scroll("audio_play(0)"); rb->audio_play(0); } } /* pause playback */ void set_pause(void) { if (rb->audio_status() == AUDIO_STATUS_PLAY) { print_scroll("audio_pause"); rb->audio_pause(); } } /* stop playback */ void set_stop(void) { if (rb->audio_status() & AUDIO_STATUS_PLAY) { print_scroll("audio_stop"); rb->audio_stop(); } } /* seek */ void set_position(int seconds) { if (rb->audio_status() & AUDIO_STATUS_PLAY) { print_scroll("audio_ff_rewind"); rb->audio_ff_rewind(seconds * 1000); } } /****************** main thread + helper ******************/ /* set to everything flat and 0 dB volume */ void sound_neutral(void) { /* neutral sound settings */ rb->sound_set(SOUND_BASS, 0); rb->sound_set(SOUND_TREBLE, 0); rb->sound_set(SOUND_BALANCE, 0); rb->sound_set(SOUND_VOLUME, 0); #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) rb->sound_set(SOUND_LOUDNESS, 0); rb->sound_set(SOUND_SUPERBASS, 0); rb->sound_set(SOUND_AVC, 0); #endif } /* return to user settings */ void sound_normal(void) { /* restore sound settings */ rb->sound_set(SOUND_BASS, rb->global_settings->bass); rb->sound_set(SOUND_TREBLE, rb->global_settings->treble); rb->sound_set(SOUND_BALANCE, rb->global_settings->balance); rb->sound_set(SOUND_VOLUME, rb->global_settings->volume); #if (CONFIG_CODEC == MAS3587F) || (CONFIG_CODEC == MAS3539F) rb->sound_set(SOUND_LOUDNESS, rb->global_settings->loudness); rb->sound_set(SOUND_SUPERBASS, rb->global_settings->superbass); rb->sound_set(SOUND_AVC, rb->global_settings->avc); #endif } /* the thread running it all */ void thread(void) { int msg_size; unsigned char mbus_msg[MBUS_MAX_SIZE]; char buf[32]; bool connected = false; long last_tick = *rb->current_tick; /* for 1 sec tick */ do { msg_size = mbus_receive(mbus_msg, sizeof(mbus_msg), 1); if (msg_size > 0) { /* received something */ if(gTread.foreground) { dump_packet(buf, sizeof(buf), mbus_msg, msg_size); /*print_scroll(buf); */ } if (msg_size > 2 && mbus_msg[0] == 1 && mbus_msg[msg_size-1] == calc_checksum(mbus_msg, msg_size-1)) { /* sanity and checksum OK */ if (!connected) { /* with the first received packet: */ sound_neutral(); /* set to flat and 0dB volume */ connected = true; } emu_process_packet(mbus_msg, msg_size-1); /* pass without chksum */ } else if(gTread.foreground) { /* not OK */ print_scroll("bad packet"); } } else if (msg_size < 0 && gTread.foreground) { /* error */ rb->snprintf(buf, sizeof(buf), "rcv error %d", msg_size); print_scroll(buf); } if (*rb->current_tick - last_tick >= gEmu.poll_interval) { /* call the emulation regulary */ emu_tick(); last_tick += gEmu.poll_interval; } } while (!gTread.exiting); } /* callback to end the TSR plugin, called before a new one gets loaded */ bool exit_tsr(bool reenter) { if (reenter) return false; /* dont let it start again */ gTread.exiting = true; /* tell the thread to end */ rb->thread_wait(gTread.thread); /* wait until it did */ uart_init(BAUDRATE); /* return to standard baudrate */ IPRE = (IPRE & ~0xF000); /* UART interrupt off */ timer_set_mode(TM_OFF); /* timer interrupt off */ sound_normal(); /* restore sound settings */ return true; } /****************** main ******************/ int main(const void* parameter) { (void)parameter; #ifdef DEBUG int button; #endif ssize_t stacksize; void* stack; mbus_init(); /* init the M-Bus layer */ emu_init(); /* init emulator */ rb->splash(HZ/5, "Alpine CDC"); /* be quick on autostart */ #ifdef DEBUG print_scroll("Alpine M-Bus Test"); print_scroll("any key to TSR"); #endif /* init the worker thread */ stack = rb->plugin_get_buffer((size_t *)&stacksize); /* use the rest as stack */ stack = (void*)(((unsigned int)stack + 100) & ~3); /* a bit away, 32 bit align */ stacksize = (stacksize - 100) & ~3; if (stacksize < DEFAULT_STACK_SIZE) { rb->splash(HZ*2, "Out of memory"); return -1; } rb->memset(&gTread, 0, sizeof(gTread)); gTread.foreground = true; gTread.thread = rb->create_thread(thread, stack, stacksize, 0, "CDC" IF_PRIO(, PRIORITY_BACKGROUND) IF_COP(, CPU)); #ifdef DEBUG do { button = rb->button_get(true); } while (button & BUTTON_REL); #endif gTread.foreground = false; /* we're in the background now */ rb->plugin_tsr(exit_tsr); /* stay resident */ #ifdef DEBUG return rb->default_event_handler(button); #else return 0; #endif } /***************** Plugin Entry Point *****************/ enum plugin_status plugin_start(const void* parameter) { /* now go ahead and have fun! */ return (main(parameter)==0) ? PLUGIN_OK : PLUGIN_ERROR; } #endif /* CONFIG_CPU==SH7034 && !(CONFIG_STORAGE & STORAGE_MMC) */