Add the RTOS processing. for the Network radio streaming receiver.
Fork of VS1053b by
VS1053.cpp@0:7728d9c6c487, 2010-12-14 (annotated)
- Committer:
- christi_s
- Date:
- Tue Dec 14 18:22:54 2010 +0000
- Revision:
- 0:7728d9c6c487
- Child:
- 1:ced2c297cc1b
initial
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
christi_s | 0:7728d9c6c487 | 1 | #include "VS1053.h" |
christi_s | 0:7728d9c6c487 | 2 | #include "mbed.h" |
christi_s | 0:7728d9c6c487 | 3 | |
christi_s | 0:7728d9c6c487 | 4 | // patch binarys |
christi_s | 0:7728d9c6c487 | 5 | #include "Patches/VS1053b_patch_1_5.c" |
christi_s | 0:7728d9c6c487 | 6 | #include "Patches/VS1053b_patch_1_5_flac.c" |
christi_s | 0:7728d9c6c487 | 7 | #include "Patches/VS1053b_patch_1_4_flac.c" |
christi_s | 0:7728d9c6c487 | 8 | // spectrum analyzer binary |
christi_s | 0:7728d9c6c487 | 9 | #include "Patches/VS1053b_specana.c" |
christi_s | 0:7728d9c6c487 | 10 | |
christi_s | 0:7728d9c6c487 | 11 | |
christi_s | 0:7728d9c6c487 | 12 | /* ================================================================== |
christi_s | 0:7728d9c6c487 | 13 | * Constructor |
christi_s | 0:7728d9c6c487 | 14 | * =================================================================*/ |
christi_s | 0:7728d9c6c487 | 15 | VS1053::VS1053( |
christi_s | 0:7728d9c6c487 | 16 | PinName mosi, PinName miso, PinName sck, PinName cs, PinName rst, |
christi_s | 0:7728d9c6c487 | 17 | PinName dreq, PinName dcs) |
christi_s | 0:7728d9c6c487 | 18 | : |
christi_s | 0:7728d9c6c487 | 19 | _spi(mosi, miso, sck), |
christi_s | 0:7728d9c6c487 | 20 | _CS(cs), |
christi_s | 0:7728d9c6c487 | 21 | _RST(rst), |
christi_s | 0:7728d9c6c487 | 22 | _DREQ(dreq), |
christi_s | 0:7728d9c6c487 | 23 | _DCS(dcs) { |
christi_s | 0:7728d9c6c487 | 24 | firstTime=-1; |
christi_s | 0:7728d9c6c487 | 25 | } |
christi_s | 0:7728d9c6c487 | 26 | |
christi_s | 0:7728d9c6c487 | 27 | /*=================================================================== |
christi_s | 0:7728d9c6c487 | 28 | * Functions |
christi_s | 0:7728d9c6c487 | 29 | *==================================================================*/ |
christi_s | 0:7728d9c6c487 | 30 | |
christi_s | 0:7728d9c6c487 | 31 | void VS1053::cs_low(void) { |
christi_s | 0:7728d9c6c487 | 32 | _CS = 0; |
christi_s | 0:7728d9c6c487 | 33 | } |
christi_s | 0:7728d9c6c487 | 34 | void VS1053::cs_high(void) { |
christi_s | 0:7728d9c6c487 | 35 | _CS = 1; |
christi_s | 0:7728d9c6c487 | 36 | } |
christi_s | 0:7728d9c6c487 | 37 | void VS1053::dcs_low(void) { |
christi_s | 0:7728d9c6c487 | 38 | _DCS = 0; |
christi_s | 0:7728d9c6c487 | 39 | |
christi_s | 0:7728d9c6c487 | 40 | } |
christi_s | 0:7728d9c6c487 | 41 | void VS1053::dcs_high(void) { |
christi_s | 0:7728d9c6c487 | 42 | _DCS = 1; |
christi_s | 0:7728d9c6c487 | 43 | } |
christi_s | 0:7728d9c6c487 | 44 | void VS1053::sci_en(void) { //SCI enable |
christi_s | 0:7728d9c6c487 | 45 | cs_high(); |
christi_s | 0:7728d9c6c487 | 46 | dcs_high(); |
christi_s | 0:7728d9c6c487 | 47 | cs_low(); |
christi_s | 0:7728d9c6c487 | 48 | } |
christi_s | 0:7728d9c6c487 | 49 | void VS1053::sci_dis(void) { //SCI disable |
christi_s | 0:7728d9c6c487 | 50 | cs_high(); |
christi_s | 0:7728d9c6c487 | 51 | } |
christi_s | 0:7728d9c6c487 | 52 | void VS1053::sdi_en(void) { //SDI enable |
christi_s | 0:7728d9c6c487 | 53 | dcs_high(); |
christi_s | 0:7728d9c6c487 | 54 | cs_high(); |
christi_s | 0:7728d9c6c487 | 55 | dcs_low(); |
christi_s | 0:7728d9c6c487 | 56 | } |
christi_s | 0:7728d9c6c487 | 57 | void VS1053::sdi_dis(void) { //SDI disable |
christi_s | 0:7728d9c6c487 | 58 | dcs_high(); |
christi_s | 0:7728d9c6c487 | 59 | } |
christi_s | 0:7728d9c6c487 | 60 | void VS1053::reset(void) { //hardware reset |
christi_s | 0:7728d9c6c487 | 61 | // wait(0.01); |
christi_s | 0:7728d9c6c487 | 62 | wait_ms(10); |
christi_s | 0:7728d9c6c487 | 63 | _RST = 0; |
christi_s | 0:7728d9c6c487 | 64 | // wait(0.01); |
christi_s | 0:7728d9c6c487 | 65 | wait_ms(5); |
christi_s | 0:7728d9c6c487 | 66 | _RST = 1; |
christi_s | 0:7728d9c6c487 | 67 | // wait(0.10); |
christi_s | 0:7728d9c6c487 | 68 | wait_ms(10); |
christi_s | 0:7728d9c6c487 | 69 | } |
christi_s | 0:7728d9c6c487 | 70 | void VS1053::power_down(void) { //hardware and software reset |
christi_s | 0:7728d9c6c487 | 71 | cs_low(); |
christi_s | 0:7728d9c6c487 | 72 | reset(); |
christi_s | 0:7728d9c6c487 | 73 | // sci_write(0x00, SM_PDOWN); |
christi_s | 0:7728d9c6c487 | 74 | sci_write(0x00, 0x10); // tempo |
christi_s | 0:7728d9c6c487 | 75 | wait(0.01); |
christi_s | 0:7728d9c6c487 | 76 | reset(); |
christi_s | 0:7728d9c6c487 | 77 | } |
christi_s | 0:7728d9c6c487 | 78 | void VS1053::sci_initialise(void) { |
christi_s | 0:7728d9c6c487 | 79 | _RST = 1; //no reset |
christi_s | 0:7728d9c6c487 | 80 | _spi.format(8,0); //spi 8bit interface, steady state low |
christi_s | 0:7728d9c6c487 | 81 | // _spi.frequency(1000000); //rising edge data record, freq. 1Mhz |
christi_s | 0:7728d9c6c487 | 82 | _spi.frequency(2000000); //rising edge data record, freq. 2Mhz |
christi_s | 0:7728d9c6c487 | 83 | |
christi_s | 0:7728d9c6c487 | 84 | |
christi_s | 0:7728d9c6c487 | 85 | cs_low(); |
christi_s | 0:7728d9c6c487 | 86 | for (int i=0; i<4; i++) { |
christi_s | 0:7728d9c6c487 | 87 | _spi.write(0xFF); //clock the chip a bit |
christi_s | 0:7728d9c6c487 | 88 | } |
christi_s | 0:7728d9c6c487 | 89 | cs_high(); |
christi_s | 0:7728d9c6c487 | 90 | dcs_high(); |
christi_s | 0:7728d9c6c487 | 91 | wait_us(5); |
christi_s | 0:7728d9c6c487 | 92 | } |
christi_s | 0:7728d9c6c487 | 93 | void VS1053::sdi_initialise(void) { |
christi_s | 0:7728d9c6c487 | 94 | _spi.format(8,0); |
christi_s | 0:7728d9c6c487 | 95 | // _spi.frequency(7000000); //set to 7MHz |
christi_s | 0:7728d9c6c487 | 96 | // _spi.frequency(12000000); //set to 12MHz to make fast transfer |
christi_s | 0:7728d9c6c487 | 97 | _spi.frequency(18000000); //set to 18MHz to make fast transfer |
christi_s | 0:7728d9c6c487 | 98 | //NG does not work// _spi.frequency(24000000); //set to 24MHz to make fast transfer |
christi_s | 0:7728d9c6c487 | 99 | |
christi_s | 0:7728d9c6c487 | 100 | cs_high(); |
christi_s | 0:7728d9c6c487 | 101 | dcs_high(); |
christi_s | 0:7728d9c6c487 | 102 | } |
christi_s | 0:7728d9c6c487 | 103 | void VS1053::sci_write(unsigned char address, unsigned short int data) { |
christi_s | 0:7728d9c6c487 | 104 | sci_en(); //enables SCI/disables SDI |
christi_s | 0:7728d9c6c487 | 105 | |
christi_s | 0:7728d9c6c487 | 106 | while (!_DREQ); //wait unitl data request is high |
christi_s | 0:7728d9c6c487 | 107 | _spi.write(0x02); //SCI write |
christi_s | 0:7728d9c6c487 | 108 | _spi.write(address); //register address |
christi_s | 0:7728d9c6c487 | 109 | _spi.write((data >> 8) & 0xFF); //write out first half of data word |
christi_s | 0:7728d9c6c487 | 110 | _spi.write(data & 0xFF); //write out second half of data word |
christi_s | 0:7728d9c6c487 | 111 | |
christi_s | 0:7728d9c6c487 | 112 | sci_dis(); //enables SDI/disables SCI |
christi_s | 0:7728d9c6c487 | 113 | wait_us(5); |
christi_s | 0:7728d9c6c487 | 114 | } |
christi_s | 0:7728d9c6c487 | 115 | void VS1053::sdi_write(unsigned char datum) { |
christi_s | 0:7728d9c6c487 | 116 | sdi_en(); |
christi_s | 0:7728d9c6c487 | 117 | |
christi_s | 0:7728d9c6c487 | 118 | while (!_DREQ); |
christi_s | 0:7728d9c6c487 | 119 | _spi.write(datum); |
christi_s | 0:7728d9c6c487 | 120 | |
christi_s | 0:7728d9c6c487 | 121 | //? sci_dis(); |
christi_s | 0:7728d9c6c487 | 122 | sdi_dis(); |
christi_s | 0:7728d9c6c487 | 123 | } |
christi_s | 0:7728d9c6c487 | 124 | unsigned short int VS1053::sci_read(unsigned short int address) { |
christi_s | 0:7728d9c6c487 | 125 | cs_low(); //enables SCI/disables SDI |
christi_s | 0:7728d9c6c487 | 126 | |
christi_s | 0:7728d9c6c487 | 127 | while (!_DREQ); //wait unitl data request is high |
christi_s | 0:7728d9c6c487 | 128 | _spi.write(0x03); //SCI write |
christi_s | 0:7728d9c6c487 | 129 | _spi.write(address); //register address |
christi_s | 0:7728d9c6c487 | 130 | unsigned short int received = _spi.write(0x00); //write out dummy byte |
christi_s | 0:7728d9c6c487 | 131 | received <<= 8; |
christi_s | 0:7728d9c6c487 | 132 | received += _spi.write(0x00); //write out dummy byte |
christi_s | 0:7728d9c6c487 | 133 | |
christi_s | 0:7728d9c6c487 | 134 | cs_high(); //enables SDI/disables SCI |
christi_s | 0:7728d9c6c487 | 135 | |
christi_s | 0:7728d9c6c487 | 136 | return received; //return received word |
christi_s | 0:7728d9c6c487 | 137 | } |
christi_s | 0:7728d9c6c487 | 138 | void VS1053::sine_test_activate(unsigned char wave) { |
christi_s | 0:7728d9c6c487 | 139 | cs_high(); //enables SDI/disables SCI |
christi_s | 0:7728d9c6c487 | 140 | |
christi_s | 0:7728d9c6c487 | 141 | while (!_DREQ); //wait unitl data request is high |
christi_s | 0:7728d9c6c487 | 142 | _spi.write(0x53); //SDI write |
christi_s | 0:7728d9c6c487 | 143 | _spi.write(0xEF); //SDI write |
christi_s | 0:7728d9c6c487 | 144 | _spi.write(0x6E); //SDI write |
christi_s | 0:7728d9c6c487 | 145 | _spi.write(wave); //SDI write |
christi_s | 0:7728d9c6c487 | 146 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 147 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 148 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 149 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 150 | |
christi_s | 0:7728d9c6c487 | 151 | cs_low(); //enables SCI/disables SDI |
christi_s | 0:7728d9c6c487 | 152 | } |
christi_s | 0:7728d9c6c487 | 153 | void VS1053::sine_test_deactivate(void) { |
christi_s | 0:7728d9c6c487 | 154 | cs_high(); |
christi_s | 0:7728d9c6c487 | 155 | |
christi_s | 0:7728d9c6c487 | 156 | while (!_DREQ); |
christi_s | 0:7728d9c6c487 | 157 | _spi.write(0x45); //SDI write |
christi_s | 0:7728d9c6c487 | 158 | _spi.write(0x78); //SDI write |
christi_s | 0:7728d9c6c487 | 159 | _spi.write(0x69); //SDI write |
christi_s | 0:7728d9c6c487 | 160 | _spi.write(0x74); //SDI write |
christi_s | 0:7728d9c6c487 | 161 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 162 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 163 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 164 | _spi.write(0x00); //filler byte |
christi_s | 0:7728d9c6c487 | 165 | } |
christi_s | 0:7728d9c6c487 | 166 | |
christi_s | 0:7728d9c6c487 | 167 | void VS1053::writeStream(unsigned char *array, int size) { |
christi_s | 0:7728d9c6c487 | 168 | for (int i=0; i<size; i++) { |
christi_s | 0:7728d9c6c487 | 169 | sdi_write(array[i]); |
christi_s | 0:7728d9c6c487 | 170 | } |
christi_s | 0:7728d9c6c487 | 171 | } |
christi_s | 0:7728d9c6c487 | 172 | |
christi_s | 0:7728d9c6c487 | 173 | #if 0 |
christi_s | 0:7728d9c6c487 | 174 | // this function does not work |
christi_s | 0:7728d9c6c487 | 175 | // because of function call overhead |
christi_s | 0:7728d9c6c487 | 176 | void VS1053::putcStream(unsigned char datum) { |
christi_s | 0:7728d9c6c487 | 177 | sdi_write(datum); |
christi_s | 0:7728d9c6c487 | 178 | } |
christi_s | 0:7728d9c6c487 | 179 | #endif |
christi_s | 0:7728d9c6c487 | 180 | |
christi_s | 0:7728d9c6c487 | 181 | unsigned short int VS1053::wram_read(unsigned short int address) { |
christi_s | 0:7728d9c6c487 | 182 | unsigned short int tmp1,tmp2; |
christi_s | 0:7728d9c6c487 | 183 | sci_write(SCI_WRAMADDR,address); |
christi_s | 0:7728d9c6c487 | 184 | tmp1=sci_read(SCI_WRAM); |
christi_s | 0:7728d9c6c487 | 185 | sci_write(SCI_WRAMADDR,address); |
christi_s | 0:7728d9c6c487 | 186 | tmp2=sci_read(SCI_WRAM); |
christi_s | 0:7728d9c6c487 | 187 | if (tmp1==tmp2) return tmp1; |
christi_s | 0:7728d9c6c487 | 188 | sci_write(SCI_WRAMADDR,address); |
christi_s | 0:7728d9c6c487 | 189 | tmp1=sci_read(SCI_WRAM); |
christi_s | 0:7728d9c6c487 | 190 | if (tmp1==tmp2) return tmp1; |
christi_s | 0:7728d9c6c487 | 191 | sci_write(SCI_WRAMADDR,address); |
christi_s | 0:7728d9c6c487 | 192 | tmp1=sci_read(SCI_WRAM); |
christi_s | 0:7728d9c6c487 | 193 | if (tmp1==tmp2) return tmp1; |
christi_s | 0:7728d9c6c487 | 194 | return tmp1; |
christi_s | 0:7728d9c6c487 | 195 | } |
christi_s | 0:7728d9c6c487 | 196 | |
christi_s | 0:7728d9c6c487 | 197 | void VS1053::wram_write(unsigned short int address, unsigned short int data) { |
christi_s | 0:7728d9c6c487 | 198 | sci_write(SCI_WRAMADDR,address); |
christi_s | 0:7728d9c6c487 | 199 | sci_write(SCI_WRAM,data); |
christi_s | 0:7728d9c6c487 | 200 | return; |
christi_s | 0:7728d9c6c487 | 201 | } |
christi_s | 0:7728d9c6c487 | 202 | |
christi_s | 0:7728d9c6c487 | 203 | |
christi_s | 0:7728d9c6c487 | 204 | void VS1053::terminateStream(void) { |
christi_s | 0:7728d9c6c487 | 205 | #if 1 |
christi_s | 0:7728d9c6c487 | 206 | unsigned int endFillByte=wram_read(para_endFillByte); |
christi_s | 0:7728d9c6c487 | 207 | // printf("endFillByte:%04X\r\n",endFillByte); // debug |
christi_s | 0:7728d9c6c487 | 208 | for (int n=0; n<2052; n++) sdi_write(0xFF&endFillByte); |
christi_s | 0:7728d9c6c487 | 209 | sci_write(SCI_MODE,(SM_SDINEW+SM_CANCEL)); |
christi_s | 0:7728d9c6c487 | 210 | for (int n=0; n<2048; n++) sdi_write(0xFF&endFillByte); |
christi_s | 0:7728d9c6c487 | 211 | // don't reset if you don't want to lose the patch |
christi_s | 0:7728d9c6c487 | 212 | // sci_write(SCI_MODE,(SM_SDINEW+SM_RESET)); // set mode reg. |
christi_s | 0:7728d9c6c487 | 213 | // wait_ms(10); |
christi_s | 0:7728d9c6c487 | 214 | #endif |
christi_s | 0:7728d9c6c487 | 215 | } |
christi_s | 0:7728d9c6c487 | 216 | |
christi_s | 0:7728d9c6c487 | 217 | void VS1053::write_plugin(const unsigned short *plugin, unsigned int len) { |
christi_s | 0:7728d9c6c487 | 218 | unsigned int i; |
christi_s | 0:7728d9c6c487 | 219 | unsigned short addr, n, val; |
christi_s | 0:7728d9c6c487 | 220 | |
christi_s | 0:7728d9c6c487 | 221 | for (i=0; i<len;) { |
christi_s | 0:7728d9c6c487 | 222 | addr = plugin[i++]; |
christi_s | 0:7728d9c6c487 | 223 | n = plugin[i++]; |
christi_s | 0:7728d9c6c487 | 224 | if (n & 0x8000U) { //RLE run, replicate n samples |
christi_s | 0:7728d9c6c487 | 225 | n &= 0x7FFF; |
christi_s | 0:7728d9c6c487 | 226 | val = plugin[i++]; |
christi_s | 0:7728d9c6c487 | 227 | while (n--) { |
christi_s | 0:7728d9c6c487 | 228 | sci_write(addr,val); |
christi_s | 0:7728d9c6c487 | 229 | } |
christi_s | 0:7728d9c6c487 | 230 | } else { //copy run, copy n sample |
christi_s | 0:7728d9c6c487 | 231 | while (n--) { |
christi_s | 0:7728d9c6c487 | 232 | val = plugin[i++]; |
christi_s | 0:7728d9c6c487 | 233 | sci_write(addr,val); |
christi_s | 0:7728d9c6c487 | 234 | } |
christi_s | 0:7728d9c6c487 | 235 | } |
christi_s | 0:7728d9c6c487 | 236 | } |
christi_s | 0:7728d9c6c487 | 237 | |
christi_s | 0:7728d9c6c487 | 238 | return; |
christi_s | 0:7728d9c6c487 | 239 | } |
christi_s | 0:7728d9c6c487 | 240 | |
christi_s | 0:7728d9c6c487 | 241 | |
christi_s | 0:7728d9c6c487 | 242 | void VS1053::initialize(void) { |
christi_s | 0:7728d9c6c487 | 243 | _RST = 1; |
christi_s | 0:7728d9c6c487 | 244 | cs_high(); //chip disabled |
christi_s | 0:7728d9c6c487 | 245 | sci_initialise(); //initialise MBED |
christi_s | 0:7728d9c6c487 | 246 | sci_write(SCI_MODE,(SM_SDINEW+SM_RESET)); // set mode reg. |
christi_s | 0:7728d9c6c487 | 247 | wait_ms(10); |
christi_s | 0:7728d9c6c487 | 248 | #if 1 |
christi_s | 0:7728d9c6c487 | 249 | // debug |
christi_s | 0:7728d9c6c487 | 250 | unsigned int chipID_0=wram_read(para_chipID_0); |
christi_s | 0:7728d9c6c487 | 251 | if (firstTime) printf("chipID_0:%04X\r\n",chipID_0); // debug |
christi_s | 0:7728d9c6c487 | 252 | unsigned int chipID_1=wram_read(para_chipID_1); |
christi_s | 0:7728d9c6c487 | 253 | if (firstTime) printf("chipID_1:%04X\r\n",chipID_1); // debug |
christi_s | 0:7728d9c6c487 | 254 | unsigned int struct_version=wram_read(para_version); |
christi_s | 0:7728d9c6c487 | 255 | if (firstTime) printf("structure version:%04X\r\n",struct_version); // debug |
christi_s | 0:7728d9c6c487 | 256 | #endif |
christi_s | 0:7728d9c6c487 | 257 | //get chip version, set clock multiplier and load patch |
christi_s | 0:7728d9c6c487 | 258 | int i = (sci_read(SCI_STATUS)&0xF0)>>4; |
christi_s | 0:7728d9c6c487 | 259 | if (i == 4) { |
christi_s | 0:7728d9c6c487 | 260 | if (firstTime) printf("Installed Chip is: VS1053\r\n"); |
christi_s | 0:7728d9c6c487 | 261 | sci_write(SCI_CLOCKF, (SC_MULT_XTALIx50+SC_ADD_20x)); |
christi_s | 0:7728d9c6c487 | 262 | #ifdef VS_PATCH |
christi_s | 0:7728d9c6c487 | 263 | // loading patch |
christi_s | 0:7728d9c6c487 | 264 | write_plugin(vs1053b_patch, sizeof(vs1053b_patch)/2); |
christi_s | 0:7728d9c6c487 | 265 | if (firstTime) { |
christi_s | 0:7728d9c6c487 | 266 | printf("VS1053b patch loaded.\r\n"); |
christi_s | 0:7728d9c6c487 | 267 | printf("patch size:%d bytes\r\n",sizeof(vs1053b_patch)); |
christi_s | 0:7728d9c6c487 | 268 | } |
christi_s | 0:7728d9c6c487 | 269 | #endif |
christi_s | 0:7728d9c6c487 | 270 | #ifdef VS_SPECANA |
christi_s | 0:7728d9c6c487 | 271 | // loading plugin(spectrum analyzer) |
christi_s | 0:7728d9c6c487 | 272 | write_plugin(vs1053b_specana, sizeof(vs1053b_specana)/2); |
christi_s | 0:7728d9c6c487 | 273 | if (firstTime) printf("VS1053b specana loaded.\r\n"); |
christi_s | 0:7728d9c6c487 | 274 | #endif |
christi_s | 0:7728d9c6c487 | 275 | } else printf("??? Not Supported Chip???\r\n"); |
christi_s | 0:7728d9c6c487 | 276 | sdi_initialise(); |
christi_s | 0:7728d9c6c487 | 277 | firstTime=0; // disable message when init after 1st time |
christi_s | 0:7728d9c6c487 | 278 | } |
christi_s | 0:7728d9c6c487 | 279 | |
christi_s | 0:7728d9c6c487 | 280 | void VS1053::setVolume(unsigned short int vol) { |
christi_s | 0:7728d9c6c487 | 281 | while (!_DREQ); |
christi_s | 0:7728d9c6c487 | 282 | sci_write(0x0B, vol); |
christi_s | 0:7728d9c6c487 | 283 | } |