A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd
at master 387 lines 11 kB view raw
1/*************************************************************************** 2 * __________ __ ___. 3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 * \/ \/ \/ \/ \/ 8 * $Id$ 9 * 10 * Copyright (C) 2009 by Bertrik Sikken 11 * 12 * This program is free software; you can redistribute it and/or 13 * modify it under the terms of the GNU General Public License 14 * as published by the Free Software Foundation; either version 2 15 * of the License, or (at your option) any later version. 16 * 17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 18 * KIND, either express or implied. 19 * 20 ****************************************************************************/ 21 22#include <stdlib.h> 23#include <stdio.h> 24#include <stdarg.h> 25#include <string.h> 26 27#include "config.h" 28 29#include "inttypes.h" 30#include "cpu.h" 31#include "system.h" 32#include "lcd.h" 33#include "../kernel-internal.h" 34#include "backlight.h" 35#include "backlight-target.h" 36#include "button.h" 37#include "panic.h" 38#include "power.h" 39#include "common.h" 40#include "usb.h" 41#include "bitmaps/rockboxlogo.h" 42 43#include "adc.h" 44#include "adc-target.h" 45 46#include "timer.h" 47 48#include "i2c-s5l8700.h" 49#include "dma-target.h" 50#include "pcm.h" 51#include "audiohw.h" 52#include "rtc.h" 53#include "tuner.h" 54#include "si4700.h" 55#include "fmradio_i2c.h" 56#include "wmcodec.h" 57#include "nand-target.h" 58 59#define LONG_DELAY 200000 60#define SHORT_DELAY 50000 61#define PAUSE_DELAY 50000 62 63static inline void delay(unsigned int duration) 64{ 65 volatile unsigned int i; 66 for(i=0;i<duration;i++); 67} 68 69// forward declaration 70static int rds_decode(int line, struct si4700_dbg_info *nfo); 71 72void main(void) 73{ 74 char mystring[64]; 75 int line, col; 76 struct tm dt; 77 int i; 78 struct si4700_dbg_info si4700_info; 79 int brightness = DEFAULT_BRIGHTNESS_SETTING; 80 unsigned int button; 81 unsigned int fm_frequency = 100700000; 82 int audiovol = 0x60; 83 unsigned nand_ids[4]; 84 85 // enable all peripherals 86 PWRCON = 0; 87 88 // disable all interrupts 89 INTMSK = 0; 90 91 // start with all GPIOs as input 92 PCON0 = 0; 93 PCON1 = 0; 94 PCON2 = 0; 95 PCON3 = 0; 96 PCON4 = 0; 97 PCON5 = 0; 98 PCON6 = 0; 99 PCON7 = 0; 100 101 system_init(); 102 kernel_init(); 103 104 asm volatile("msr cpsr_c, #0x13\n\t"); // enable interrupts 105 106 lcd_init(); 107 108 lcd_clear_display(); 109 lcd_bitmap(rockboxlogo, 0, 160, BMPWIDTH_rockboxlogo, BMPHEIGHT_rockboxlogo); 110 lcd_update(); 111 112 power_init(); 113 114 i2c_init(); 115 fmradio_i2c_init(); 116 adc_init(); 117 backlight_hw_init(); 118 button_init_device(); 119 120 // FM power 121 si4700_init(); 122 tuner_power(true); 123 si4700_set(RADIO_SLEEP, 0); 124 si4700_set(RADIO_MUTE, 0); 125 si4700_set(RADIO_REGION, 0); 126 si4700_set(RADIO_FREQUENCY, fm_frequency); 127 128 lcd_puts_scroll(0,0,"+++ this is a very very long line to test scrolling. ---"); 129 130 // WM1800 codec configuration 131 wmcodec_write(0x0F, 0); // codec reset 132 wmcodec_write(0x19, 0xF0); // pwr mgmt1: VMID = 1, VREF, AINL, AINR 133 wmcodec_write(0x1A, 0x60); // pwr mgmt2: LOUT1, ROUT1 134 wmcodec_write(0x2F, 0x0C); // pwr mgmt3: LOMIX, ROMIX 135 wmcodec_write(0x02, audiovol); // LOUT1VOL 136 wmcodec_write(0x03, audiovol | (1 << 8)); // ROUT1VOL 137 wmcodec_write(0x22, (1 << 7) | (7 << 4)); // left out mix (1) 138 wmcodec_write(0x25, (1 << 7) | (7 << 4)); // right out mix (2) 139 140 // enable audio 141 PCON5 = (PCON5 & ~0x0000000F) | 0x00000001; 142 PDAT5 |= 1; 143 144 nand_ll_init(); 145 for (i = 0; i < 4; i++) { 146 nand_ids[i] = nand_ll_read_id(i); 147 } 148 149 while (true) 150 { 151 line = 1; 152 153#if 1 /* enable to see GPIOs */ 154 snprintf(mystring, 64, "%02X %02X %02X %02X %02X %02X %02X %02X", 155 PDAT0, PDAT1, PDAT2, PDAT3, PDAT4, PDAT5, PDAT6, PDAT7); 156 lcd_puts(0, line++, mystring); 157#endif 158 159#if 1 /* enable this to see info about the RTC */ 160 rtc_read_datetime(&dt); 161 snprintf(mystring, 64, "RTC: %04d-%02d-%02d %02d:%02d:%02d", 162 dt.tm_year + 1900, dt.tm_mon+1, dt.tm_mday, 163 dt.tm_hour, dt.tm_min, dt.tm_sec); 164 lcd_puts(0, line++, mystring); 165#endif 166 167#if 1 /* enable this to see radio debug info */ 168 button = button_read_device(); 169 if (button & BUTTON_RIGHT) { 170 fm_frequency += 100000; 171 si4700_set(RADIO_FREQUENCY, fm_frequency); 172 } 173 if (button & BUTTON_LEFT) { 174 fm_frequency -= 100000; 175 si4700_set(RADIO_FREQUENCY, fm_frequency); 176 } 177 snprintf(mystring, 64, "FM frequency: %9d", fm_frequency); 178 lcd_puts(0, line++, mystring); 179 180 si4700_dbg_info(&si4700_info); 181 col = snprintf(mystring, 64, "FM: "); 182 for (i = 0; i < 16; i++) { 183 col += snprintf(mystring + col, 64, "%04X ", si4700_info.regs[i]); 184 if (((i + 1) % 4) == 0) { 185 lcd_puts(0, line++, mystring); 186 col = 4; 187 } 188 } 189 line = rds_decode(line, &si4700_info); 190#endif 191 192#if 1 /* volume control with up/down keys */ 193 button = button_read_device(); 194 if (button & BUTTON_UP) { 195 if (audiovol < 127) { 196 audiovol++; 197 wmcodec_write(0x02, audiovol); 198 wmcodec_write(0x03, (1 << 8) | audiovol); 199 } 200 } 201 if (button & BUTTON_DOWN) { 202 if (audiovol > 0) { 203 audiovol--; 204 wmcodec_write(0x02, audiovol); 205 wmcodec_write(0x03, (1 << 8) | audiovol); 206 } 207 } 208 snprintf(mystring, 64, "volume %3d", audiovol); 209 lcd_puts(0, line++, mystring); 210#endif 211 212#if 1 /* enable this to see ADC info */ 213 snprintf(mystring, 64, "ADC: %04X %04X %04X %04X", 214 adc_read(0), adc_read(1), adc_read(2), adc_read(3)); 215 lcd_puts(0, line++, mystring); 216 snprintf(mystring, 64, "ADC:USB %4d mV BAT %4d mV", 217 (adc_read(0) * 6000) >> 10, (adc_read(2) * 4650) >> 10); 218 lcd_puts(0, line++, mystring); 219#endif 220 221#if 1 /* enable this so see USB info */ 222 snprintf(mystring, 64, "CLK %08X CLK2 %08X", CLKCON, CLKCON2); 223 lcd_puts(0, line++, mystring); 224 225 snprintf(mystring, 64, "%04X %04X %04X %04X", PHYCTRL, PHYPWR, URSTCON, UCLKCON); 226 lcd_puts(0, line++, mystring); 227 228 snprintf(mystring, 64, "SCR %04X SSR %04X EIR %04X", USB_SCR, USB_SSR, USB_EIR); 229 lcd_puts(0, line++, mystring); 230 231 snprintf(mystring, 64, "FAR %04X FNR %04X EP0 %04X", USB_FAR, USB_FNR, USB_EP0SR); 232 lcd_puts(0, line++, mystring); 233#endif 234 235#if 1 /* button lights controlled by keypad */ 236 button = button_read_device(); 237 if (button & (BUTTON_UP | BUTTON_DOWN | BUTTON_LEFT | BUTTON_RIGHT)) { 238 PDAT3 |= (1 << 3); 239 } 240 else { 241 PDAT3 &= ~(1 << 3); 242 } 243 if (button & (BUTTON_BACK | BUTTON_MENU)) { 244 PDAT3 |= (1 << 2); 245 } 246 else { 247 PDAT3 &= ~(1 << 2); 248 } 249 if (button & (BUTTON_SELECT)) { 250 PDAT4 |= (1 << 2); 251 } 252 else { 253 PDAT4 &= ~(1 << 2); 254 } 255#endif 256 257#if 1 /* backlight brightness controlled by up/down keys */ 258 button = button_read_device(); 259 if (button & BUTTON_MENU) { 260 if (brightness < MAX_BRIGHTNESS_SETTING) { 261 brightness++; 262 backlight_hw_brightness(brightness); 263 } 264 } 265 else if (button & BUTTON_BACK) { 266 if (brightness > MIN_BRIGHTNESS_SETTING) { 267 brightness--; 268 backlight_hw_brightness(brightness); 269 } 270 } 271 snprintf(mystring, 64, "brightness %3d", brightness); 272 lcd_puts(0, line++, mystring); 273#endif 274 275#if 1 /* power off using power button */ 276 button = button_read_device(); 277 if (button & BUTTON_POWER) { 278 power_off(); 279 } 280#endif 281 282#if 1 /* button info */ 283 snprintf(mystring, 64, "BUTTONS %08X, %s", button_read_device(), 284 headphones_inserted() ? "HP" : "hp"); 285 lcd_puts(0, line++, mystring); 286#endif 287 288#if 1 /* NAND debug */ 289 snprintf(mystring, 64, "NAND ID: %08X %08X", nand_ids[0], nand_ids[1]); 290 lcd_puts(0, line++, mystring); 291 snprintf(mystring, 64, "NAND ID: %08X %08X", nand_ids[2], nand_ids[3]); 292 lcd_puts(0, line++, mystring); 293#endif 294 295#if 1 296 snprintf(mystring, 64, "TIMER A:%08X B:%08X", TACNT, TBCNT); 297 lcd_puts(0, line++, mystring); 298 snprintf(mystring, 64, "TIMER C:%08X D:%08X", TCCNT, TDCNT); 299 lcd_puts(0, line++, mystring); 300#endif 301 302 lcd_update(); 303 } 304} 305 306 307static int rds_decode(int line, struct si4700_dbg_info *nfo) 308{ 309 unsigned short rdsdata[4]; 310 unsigned int pi, group, tp, pty, segment, abflag; 311 static unsigned int af1 = 0, af2 = 0; 312 static unsigned int day = 0, hour = 0, minute = 0; 313 static unsigned int abflag_prev = -1; 314 static char mystring[64]; 315 316 /* big RDS arrays */ 317 static char ps[9]; 318 static char rt[65]; 319 320 rdsdata[0] = nfo->regs[12]; 321 rdsdata[1] = nfo->regs[13]; 322 rdsdata[2] = nfo->regs[14]; 323 rdsdata[3] = nfo->regs[15]; 324 325 pi = rdsdata[0]; 326 group = (rdsdata[1] >> 11) & 0x1F; 327 tp = (rdsdata[1] >> 10) & 1; 328 pty = (rdsdata[1] >> 5) & 0x1F; 329 330 switch (group) { 331 332 case 0: /* group 0A: basic info */ 333 af1 = (rdsdata[2] >> 8) & 0xFF; 334 af2 = (rdsdata[2] >> 0) & 0xFF; 335 /* fall through */ 336 case 1: /* group 0B: basic info */ 337 segment = rdsdata[1] & 3; 338 ps[segment * 2 + 0] = (rdsdata[3] >> 8) & 0xFF; 339 ps[segment * 2 + 1] = (rdsdata[3] >> 0) & 0xFF; 340 break; 341 342 case 2: /* group 1A: programme item */ 343 case 3: /* group 1B: programme item */ 344 day = (rdsdata[3] >> 11) & 0x1F; 345 hour = (rdsdata[3] >> 6) & 0x1F; 346 minute = (rdsdata[3] >> 0) & 0x3F; 347 break; 348 349 case 4: /* group 2A: radio text */ 350 segment = rdsdata[1] & 0xF; 351 abflag = (rdsdata[1] >> 4) & 1; 352 if (abflag != abflag_prev) { 353 memset(rt, '.', 64); 354 abflag_prev = abflag; 355 } 356 rt[segment * 4 + 0] = (rdsdata[2] >> 8) & 0xFF; 357 rt[segment * 4 + 1] = (rdsdata[2] >> 0) & 0xFF; 358 rt[segment * 4 + 2] = (rdsdata[3] >> 8) & 0xFF; 359 rt[segment * 4 + 3] = (rdsdata[3] >> 0) & 0xFF; 360 break; 361 362 case 5: /* group 2B: radio text */ 363 segment = rdsdata[1] & 0xF; 364 abflag = (rdsdata[1] >> 4) & 1; 365 if (abflag != abflag_prev) { 366 memset(rt, '.', 64); 367 abflag_prev = abflag; 368 } 369 rt[segment * 2 + 0] = (rdsdata[3] >> 8) & 0xFF; 370 rt[segment * 2 + 1] = (rdsdata[3] >> 0) & 0xFF; 371 break; 372 373 default: 374 break; 375 } 376 377 snprintf(mystring, 64, "PI:%04X,TP:%d,PTY:%2d,AF:%02X/%02X", pi, tp, pty, af1, af2); 378 lcd_puts(0, line++, mystring); 379 snprintf(mystring, 64, "PS:%s,ITEM:%02d-%02d:%02d", ps, day, hour, minute); 380 lcd_puts(0, line++, mystring); 381 snprintf(mystring, 64, "RT:%s", rt); 382 lcd_puts(0, line++, mystring); 383 384 return line; 385} 386 387