A modern Music Player Daemon based on Rockbox open source high quality audio player
libadwaita audio rust zig deno mpris rockbox mpd

ClipPlus BOOTLOADER DONT FIT!

REMOVED FROM ALL NATIVE BOOTLOADERS:
finish removing the text scrolling
pare down printf to a minimal subset (%c %s %l %d %u and %x(%p))
remove diacritic and rtl language support

GOAL 134000

START 135305

CURRENT 133700

SUCCESS! (ASSUMING IT WORKS -- UNESTED)

Change-Id: Ic3f6ac1dc260578f581ee53458b3e5bb47d313ec

+529 -3
+2
bootloader/SOURCES
··· 1 1 common.c 2 + format.c 3 + snprintf.c 2 4 3 5 #if defined(IPOD_NANO2G) 4 6 ipodnano2g.c
+324
bootloader/format.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2002 by Gary Czvitkovicz 11 + * Copyright (C) 2017 by William Wilgus 12 + * 13 + * This program is free software; you can redistribute it and/or 14 + * modify it under the terms of the GNU General Public License 15 + * as published by the Free Software Foundation; either version 2 16 + * of the License, or (at your option) any later version. 17 + * 18 + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 + * KIND, either express or implied. 20 + * 21 + ****************************************************************************/ 22 + 23 + 24 + #include <stdarg.h> 25 + #include <stdbool.h> 26 + #include <limits.h> 27 + #include <string.h> 28 + #include "file.h" 29 + #include "format.h" 30 + 31 + static const char hexdigit[] = "0123456789ABCDEF"; 32 + 33 + /* smaller compressed binary without inline but 18% slower */ 34 + #define FMT_DECL static inline 35 + 36 + FMT_DECL int fmt_width_precision(int *ch, const char **fmt, char **str, va_list *ap) 37 + { 38 + int value = 0; 39 + (void) str; 40 + (void) ap; 41 + 42 + while (*ch >= '0' && *ch <= '9') 43 + { 44 + value = 10 * value + (*ch - '0'); 45 + *ch = *(*fmt)++; 46 + } 47 + return value; 48 + } 49 + 50 + FMT_DECL int fmt_integer_signed(int *ch, const char **fmt, char **str, va_list *ap) 51 + { 52 + int val, rem, sign; 53 + (void) ch; 54 + (void) fmt; 55 + 56 + val = sign = va_arg(*ap, int); 57 + if (val < 0) 58 + val = -val; 59 + do { 60 + rem = val % 10; 61 + val /= 10; 62 + *--(*str) = rem + '0'; 63 + 64 + } while (val > 0); 65 + 66 + if (sign < 0) 67 + *--(*str) = '-'; 68 + return 0; 69 + } 70 + 71 + FMT_DECL int fmt_integer_unsigned(int *ch, const char **fmt, char **str, va_list *ap) 72 + { 73 + unsigned int uval, urem; 74 + (void) ch; 75 + (void) fmt; 76 + 77 + uval = va_arg(*ap, unsigned int); 78 + do { 79 + urem = uval % 10; 80 + uval /= 10; 81 + *--(*str) = urem + '0'; 82 + } while (uval > 0); 83 + return 0; 84 + } 85 + 86 + FMT_DECL int fmt_long(int *ch, const char **fmt, char **str, va_list *ap) 87 + { 88 + int pad = 0; 89 + long lval, lrem, lsign = 0; 90 + unsigned long ulval, ulrem; 91 + char ch_l = *ch; 92 + 93 + *ch = *(*fmt)++; 94 + if (*ch == 'd') { 95 + lval = lsign = va_arg(*ap, long); 96 + 97 + if (lval < 0) 98 + lval = -lval; 99 + do { 100 + lrem = lval % 10; 101 + lval /= 10; 102 + *--(*str) = lrem + '0'; 103 + } while (lval > 0); 104 + 105 + if (lsign < 0) 106 + *--(*str) = '-'; 107 + } 108 + else if (*ch == 'u') { 109 + ulval = va_arg(*ap, unsigned long); 110 + do { 111 + ulrem = ulval % 10; 112 + ulval /= 10; 113 + *--(*str) = ulrem + '0'; 114 + } while (ulval > 0); 115 + } 116 + else if (*ch == 'x' || *ch == 'X') { 117 + pad++; 118 + ulval = va_arg(*ap, long); 119 + do { 120 + *--(*str) = hexdigit[ulval & 0xf]; 121 + ulval >>= 4; 122 + } while (ulval > 0); 123 + } 124 + else { 125 + *--(*str) = ch_l; 126 + *--(*str) = *ch; 127 + } 128 + return pad; 129 + } 130 + 131 + FMT_DECL int fmt_character(int *ch, const char **fmt, char **str, va_list *ap) 132 + { 133 + (void) ch; 134 + (void) fmt; 135 + 136 + *--(*str) = va_arg(*ap, int); 137 + return 0; 138 + } 139 + 140 + FMT_DECL int fmt_string(int *ch, const char **fmt, char **str, va_list *ap) 141 + { 142 + (void) ch; 143 + (void) fmt; 144 + 145 + *str = va_arg (*ap, char*); 146 + return 0; 147 + } 148 + 149 + FMT_DECL int fmt_hex_unsigned(int *ch, const char **fmt, char **str, va_list *ap) 150 + { 151 + unsigned int uval; 152 + (void) ch; 153 + (void) fmt; 154 + 155 + uval = va_arg(*ap, int); 156 + do { 157 + *--(*str) = hexdigit[uval & 0xf]; 158 + uval >>= 4; 159 + } while (uval > 0); 160 + return 1; 161 + } 162 + 163 + FMT_DECL int fmt_pointer(int *ch, const char **fmt, char **str, va_list *ap) 164 + { 165 + int pad = fmt_hex_unsigned(ch, fmt, str, ap); 166 + /* for pointers prepend 0x and act like 'X' */ 167 + *--(*str) = 'x'; 168 + *--(*str) = '0'; 169 + return pad; 170 + } 171 + 172 + FMT_DECL int fmt_sizet(int *ch, const char **fmt, char **str, va_list *ap) 173 + { 174 + size_t uszval, uszrem; 175 + ssize_t szval, szrem, szsign; 176 + char ch_z = *ch; 177 + *ch = *(*fmt)++; 178 + 179 + if (*ch == 'd') { 180 + szval = szsign = va_arg(*ap, ssize_t); 181 + if (szval < 0) 182 + szval = -szval; 183 + do { 184 + szrem = szval % 10; 185 + szval /= 10; 186 + *--(*str) = szrem + '0'; 187 + } while (szval > 0); 188 + 189 + if (szsign < 0) 190 + *--(*str) = '-'; 191 + } 192 + else if (*ch == 'u') { 193 + uszval = va_arg(*ap, size_t); 194 + do { 195 + uszrem = uszval % 10; 196 + uszval /= 10; 197 + *--(*str) = uszrem + '0'; 198 + } while (uszval > 0); 199 + } 200 + else { 201 + *--(*str) = ch_z; 202 + *--(*str) = *ch; 203 + } 204 + return 0; 205 + } 206 + 207 + static inline int fmt_next_char(int *ch, const char **fmt, char **str, va_list *ap) 208 + { 209 + (void) fmt; 210 + (void) ap; 211 + 212 + *--(*str) = *ch; 213 + return 0; 214 + } 215 + 216 + 217 + 218 + void format( 219 + /* call 'push()' for each output letter */ 220 + int (*push)(void *userp, unsigned char data), 221 + void *userp, 222 + const char *fmt, 223 + va_list ap) 224 + { 225 + bool ok = true; 226 + char *str; 227 + char tmpbuf[12], pad; 228 + int ch, width, precision, padded; 229 + 230 + 231 + ch = *fmt++; 232 + tmpbuf[sizeof tmpbuf - 1] = '\0'; 233 + 234 + do 235 + { 236 + if (ch == '%') 237 + { 238 + str = tmpbuf + sizeof tmpbuf - 1; 239 + ch = *fmt++; 240 + padded = (ch == '0' ? 1 : 0); 241 + width = fmt_width_precision(&ch, &fmt, &str, &ap); 242 + 243 + precision = INT_MAX; 244 + if(ch == '.') 245 + { 246 + ch = *fmt++; 247 + precision = fmt_width_precision(&ch, &fmt, &str, &ap); 248 + } 249 + 250 + if (ch == 'd') 251 + fmt_integer_signed(&ch, &fmt, &str, &ap); 252 + else if (ch == 'u') 253 + fmt_integer_unsigned(&ch, &fmt, &str, &ap); 254 + else if (ch == 'l') 255 + padded += fmt_long(&ch, &fmt, &str, &ap); 256 + else if (ch == 'c') 257 + fmt_character(&ch, &fmt, &str, &ap); 258 + else if (ch == 's') 259 + fmt_string(&ch, &fmt, &str, &ap); 260 + else if (ch == 'x' || ch == 'X') 261 + padded += fmt_hex_unsigned(&ch, &fmt, &str, &ap); 262 + else if (ch == 'p' || ch == 'P') 263 + padded += fmt_pointer(&ch, &fmt, &str, &ap); 264 + #if 0 265 + else if (ch == 'z') 266 + fmt_sizet(&ch, &fmt, &str, &ap); 267 + #endif 268 + else 269 + fmt_next_char(&ch, &fmt, &str, &ap); 270 + 271 + width -= strlen (str); 272 + if (width > 0) 273 + { 274 + pad = (padded ? '0' : ' '); 275 + while (width-- > 0 && ok) 276 + ok=push(userp, pad); 277 + } 278 + while(*str != '\0' && ok && precision--) 279 + ok=push(userp, *str++); 280 + } 281 + else 282 + ok=push(userp, ch); 283 + 284 + } while ((ch = *fmt++) != '\0' && ok); 285 + } 286 + 287 + struct for_fprintf { 288 + int fd; /* where to store it */ 289 + int bytes; /* amount stored */ 290 + }; 291 + 292 + static int fprfunc(void *pr, unsigned char letter) 293 + { 294 + struct for_fprintf *fpr = (struct for_fprintf *)pr; 295 + int rc = write(fpr->fd, &letter, 1); 296 + 297 + if(rc > 0) { 298 + fpr->bytes++; /* count them */ 299 + return true; /* we are ok */ 300 + } 301 + 302 + return false; /* failure */ 303 + } 304 + 305 + 306 + int fdprintf(int fd, const char *fmt, ...) 307 + { 308 + va_list ap; 309 + struct for_fprintf fpr; 310 + 311 + fpr.fd=fd; 312 + fpr.bytes=0; 313 + 314 + va_start(ap, fmt); 315 + format(fprfunc, &fpr, fmt, ap); 316 + va_end(ap); 317 + 318 + return fpr.bytes; /* return 0 on error */ 319 + } 320 + 321 + void vuprintf(int (*push)(void *userp, unsigned char data), void *userp, const char *fmt, va_list ap) 322 + { 323 + format(push, userp, fmt, ap); 324 + }
+37
bootloader/format.h
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2002 by Felix Arends 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 + #ifndef __FORMAT_H__ 23 + #define __FORMAT_H__ 24 + 25 + void format( 26 + /* call 'push()' for each output letter */ 27 + int (*push)(void *userp, unsigned char data), 28 + void *userp, 29 + const char *fmt, 30 + va_list ap); 31 + 32 + /* callback function is called for every output character (byte) with userp and 33 + * should return 0 when ch is a char other than '\0' that should stop printing */ 34 + void vuprintf(int (*push)(void *userp, unsigned char data), 35 + void *userp, const char *fmt, va_list ap); 36 + 37 + #endif /* __FORMAT_H__ */
+80
bootloader/snprintf.c
··· 1 + /*************************************************************************** 2 + * __________ __ ___. 3 + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ 4 + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / 5 + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < 6 + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ 7 + * \/ \/ \/ \/ \/ 8 + * $Id$ 9 + * 10 + * Copyright (C) 2002 by Gary Czvitkovicz 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 + /* 23 + * Minimal printf and snprintf formatting functions 24 + * 25 + * These support %c %s %l %d %u and %x(%p) 26 + * Field width and zero-padding flag only 27 + */ 28 + 29 + #include <stdio.h> 30 + #include <stdarg.h> 31 + #include <stdbool.h> 32 + #include <limits.h> 33 + #include "format.h" 34 + 35 + struct for_snprintf { 36 + unsigned char *ptr; /* where to store it */ 37 + size_t bytes; /* amount already stored */ 38 + size_t max; /* max amount to store */ 39 + }; 40 + 41 + static int sprfunc(void *ptr, unsigned char letter) 42 + { 43 + struct for_snprintf *pr = (struct for_snprintf *)ptr; 44 + if(pr->bytes < pr->max) { 45 + *pr->ptr = letter; 46 + pr->ptr++; 47 + pr->bytes++; 48 + return true; 49 + } 50 + return false; /* filled buffer */ 51 + } 52 + 53 + 54 + int snprintf(char *buf, size_t size, const char *fmt, ...) 55 + { 56 + int len; 57 + va_list ap; 58 + 59 + va_start(ap, fmt); 60 + len = vsnprintf(buf, size, fmt, ap); 61 + va_end(ap); 62 + 63 + return len; 64 + } 65 + 66 + int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap) 67 + { 68 + struct for_snprintf pr; 69 + 70 + pr.ptr = (unsigned char *)buf; 71 + pr.bytes = 0; 72 + pr.max = size; 73 + 74 + format(sprfunc, &pr, fmt, ap); 75 + 76 + /* make sure it ends with a trailing zero */ 77 + pr.ptr[(pr.bytes < pr.max) ? 0 : -1] = '\0'; 78 + 79 + return pr.bytes; 80 + }
+10 -2
firmware/common/diacritic.c
··· 194 194 }; 195 195 196 196 #define MRU_MAX_LEN 32 197 - 197 + #ifndef BOOTLOADER 198 198 bool is_diacritic(const unsigned short char_code, bool *is_rtl) 199 199 { 200 200 static uint8_t mru_len = 0; ··· 248 248 249 249 return (char_code < diac->base + (info & DIAC_CNT)); 250 250 } 251 - 251 + #else /*BOOTLOADER*/ 252 + inline bool is_diacritic(const unsigned short char_code, bool *is_rtl) 253 + { 254 + (void)char_code; 255 + if (is_rtl) 256 + *is_rtl = false; 257 + return false; 258 + } 259 + #endif /* ndef BOOTLOADER*/
+67
firmware/drivers/lcd-bitmap-common.c
··· 118 118 LCDFN(update_rect)(current_vp->x + x, current_vp->y + y, width, height); 119 119 } 120 120 121 + #ifndef BOOTLOADER 121 122 /* put a string at a given pixel position, skipping first ofs pixel columns */ 122 123 static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) 123 124 { ··· 257 258 } 258 259 font_lock(current_vp->font, false); 259 260 } 261 + #else /* BOOTLOADER */ 262 + /* put a string at a given pixel position, skipping first ofs pixel columns */ 263 + static void LCDFN(putsxyofs)(int x, int y, int ofs, const unsigned char *str) 264 + { 265 + unsigned short *ucs; 266 + struct font* pf = font_get(current_vp->font); 267 + int vp_flags = current_vp->flags; 268 + const unsigned char *bits; 269 + int width; 270 + 271 + if ((vp_flags & VP_FLAG_ALIGNMENT_MASK) != 0) 272 + { 273 + int w; 274 + 275 + LCDFN(getstringsize)(str, &w, NULL); 276 + /* center takes precedence */ 277 + if (vp_flags & VP_FLAG_ALIGN_CENTER) 278 + { 279 + x = ((current_vp->width - w)/ 2) + x; 280 + if (x < 0) 281 + x = 0; 282 + } 283 + else 284 + { 285 + x = current_vp->width - w - x; 286 + x += ofs; 287 + ofs = 0; 288 + } 289 + } 290 + 291 + /* allow utf but no diacritics or rtl lang */ 292 + for (ucs = bidi_l2v(str, 1); *ucs; ucs++) 293 + { 294 + const unsigned short next_ch = ucs[1]; 295 + 296 + if (x >= current_vp->width) 297 + break; 298 + 299 + /* Get proportional width and glyph bits */ 300 + width = font_get_width(pf, *ucs); 301 + 302 + if (ofs > width) 303 + { 304 + ofs -= width; 305 + continue; 306 + } 307 + 308 + bits = font_get_bits(pf, *ucs); 309 + 310 + #if defined(MAIN_LCD) && defined(HAVE_LCD_COLOR) 311 + if (pf->depth) 312 + lcd_alpha_bitmap_part(bits, ofs, 0, width, x, y, 313 + width - ofs, pf->height); 314 + else 315 + #endif 316 + LCDFN(mono_bitmap_part)(bits, ofs, 0, width, x, 317 + y, width - ofs, pf->height); 318 + if (next_ch) 319 + { 320 + x += width - ofs; 321 + ofs = 0; 322 + } 323 + } 324 + } 325 + #endif 326 + 260 327 261 328 /*** pixel oriented text output ***/ 262 329
+9 -1
firmware/scroll_engine.c
··· 52 52 }; 53 53 54 54 static void scroll_thread(void); 55 - static char scroll_stack[DEFAULT_STACK_SIZE*3]; 56 55 static const char scroll_name[] = "scroll"; 57 56 58 57 #include "drivers/lcd-scroll.c" ··· 195 194 } 196 195 #endif /* HAVE_REMOTE_LCD */ 197 196 197 + 198 + #ifndef BOOTLOADER 198 199 void scroll_init(void) 199 200 { 201 + static char scroll_stack[DEFAULT_STACK_SIZE*3]; 200 202 #ifdef HAVE_REMOTE_LCD 201 203 queue_init(&scroll_queue, true); 202 204 #endif ··· 205 207 IF_PRIO(, PRIORITY_USER_INTERFACE) 206 208 IF_COP(, CPU)); 207 209 } 210 + #else 211 + void scroll_init(void) 212 + { 213 + /* DUMMY */ 214 + } 215 + #endif /* ndef BOOTLOADER*/