test
chan_fs/diskio.c@0:c1253c12d4bc, 2010-02-21 (annotated)
- Committer:
- emh203
- Date:
- Sun Feb 21 02:45:09 2010 +0000
- Revision:
- 0:c1253c12d4bc
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
emh203 | 0:c1253c12d4bc | 1 | /*-----------------------------------------------------------------------*/ |
emh203 | 0:c1253c12d4bc | 2 | /* Low level disk I/O module skeleton for FatFs (C)ChaN, 2007 */ |
emh203 | 0:c1253c12d4bc | 3 | /*-----------------------------------------------------------------------*/ |
emh203 | 0:c1253c12d4bc | 4 | /* This is a stub disk I/O module that acts as front end of the existing */ |
emh203 | 0:c1253c12d4bc | 5 | /* disk I/O modules and attach it to FatFs module with common interface. */ |
emh203 | 0:c1253c12d4bc | 6 | /*-----------------------------------------------------------------------*/ |
emh203 | 0:c1253c12d4bc | 7 | |
emh203 | 0:c1253c12d4bc | 8 | #include "diskio.h" |
emh203 | 0:c1253c12d4bc | 9 | #include "mbed.h" |
emh203 | 0:c1253c12d4bc | 10 | |
emh203 | 0:c1253c12d4bc | 11 | |
emh203 | 0:c1253c12d4bc | 12 | //****************************************************************************************************************** |
emh203 | 0:c1253c12d4bc | 13 | // MBED SPI/CS Select functions.... Modify for your layout. |
emh203 | 0:c1253c12d4bc | 14 | //************************************************************************************** |
emh203 | 0:c1253c12d4bc | 15 | |
emh203 | 0:c1253c12d4bc | 16 | SPI _spi(p5, p6, p7); // mosi, miso, sclk |
emh203 | 0:c1253c12d4bc | 17 | DigitalOut _cs(p8); |
emh203 | 0:c1253c12d4bc | 18 | |
emh203 | 0:c1253c12d4bc | 19 | //****************************************************************************************************************** |
emh203 | 0:c1253c12d4bc | 20 | // Low Level Sector Access Function Prototypes('C' Castrated versions of Simon Ford's C++ MBED SDFileSystem class |
emh203 | 0:c1253c12d4bc | 21 | //****************************************************************************************************************** |
emh203 | 0:c1253c12d4bc | 22 | int _cmd(int cmd, int arg); |
emh203 | 0:c1253c12d4bc | 23 | int _read(BYTE *buffer, int length); |
emh203 | 0:c1253c12d4bc | 24 | int _write(BYTE *buffer, int length); |
emh203 | 0:c1253c12d4bc | 25 | int ext_bits(BYTE *data, int msb, int lsb); |
emh203 | 0:c1253c12d4bc | 26 | int _sd_sectors(); |
emh203 | 0:c1253c12d4bc | 27 | int _sectors; |
emh203 | 0:c1253c12d4bc | 28 | |
emh203 | 0:c1253c12d4bc | 29 | #define SD_COMMAND_TIMEOUT 5000 |
emh203 | 0:c1253c12d4bc | 30 | |
emh203 | 0:c1253c12d4bc | 31 | |
emh203 | 0:c1253c12d4bc | 32 | //****************************************************************************************************************** |
emh203 | 0:c1253c12d4bc | 33 | // Sector Access functions for CHAN FatFs |
emh203 | 0:c1253c12d4bc | 34 | //****************************************************************************************************************** |
emh203 | 0:c1253c12d4bc | 35 | |
emh203 | 0:c1253c12d4bc | 36 | DRESULT disk_ioctl ( |
emh203 | 0:c1253c12d4bc | 37 | BYTE drv, /* Physical drive nmuber (0..) */ |
emh203 | 0:c1253c12d4bc | 38 | BYTE ctrl, /* Control code */ |
emh203 | 0:c1253c12d4bc | 39 | void *buff /* Buffer to send/receive control data */ |
emh203 | 0:c1253c12d4bc | 40 | ) |
emh203 | 0:c1253c12d4bc | 41 | { |
emh203 | 0:c1253c12d4bc | 42 | DRESULT res; |
emh203 | 0:c1253c12d4bc | 43 | |
emh203 | 0:c1253c12d4bc | 44 | switch(ctrl) |
emh203 | 0:c1253c12d4bc | 45 | { |
emh203 | 0:c1253c12d4bc | 46 | case CTRL_SYNC: |
emh203 | 0:c1253c12d4bc | 47 | res = RES_OK; |
emh203 | 0:c1253c12d4bc | 48 | break; |
emh203 | 0:c1253c12d4bc | 49 | |
emh203 | 0:c1253c12d4bc | 50 | case GET_SECTOR_SIZE: |
emh203 | 0:c1253c12d4bc | 51 | res = RES_OK; |
emh203 | 0:c1253c12d4bc | 52 | *(WORD *)buff = 512; |
emh203 | 0:c1253c12d4bc | 53 | break; |
emh203 | 0:c1253c12d4bc | 54 | |
emh203 | 0:c1253c12d4bc | 55 | case GET_SECTOR_COUNT: |
emh203 | 0:c1253c12d4bc | 56 | res = RES_OK; |
emh203 | 0:c1253c12d4bc | 57 | *(DWORD *)buff = (WORD)_sd_sectors(); |
emh203 | 0:c1253c12d4bc | 58 | break; |
emh203 | 0:c1253c12d4bc | 59 | |
emh203 | 0:c1253c12d4bc | 60 | case GET_BLOCK_SIZE: |
emh203 | 0:c1253c12d4bc | 61 | res = RES_OK; |
emh203 | 0:c1253c12d4bc | 62 | *(DWORD *)buff = 1; |
emh203 | 0:c1253c12d4bc | 63 | break; |
emh203 | 0:c1253c12d4bc | 64 | |
emh203 | 0:c1253c12d4bc | 65 | default: |
emh203 | 0:c1253c12d4bc | 66 | res = RES_OK; |
emh203 | 0:c1253c12d4bc | 67 | break; |
emh203 | 0:c1253c12d4bc | 68 | } |
emh203 | 0:c1253c12d4bc | 69 | return res; |
emh203 | 0:c1253c12d4bc | 70 | } |
emh203 | 0:c1253c12d4bc | 71 | |
emh203 | 0:c1253c12d4bc | 72 | DSTATUS disk_initialize(BYTE Drive) { |
emh203 | 0:c1253c12d4bc | 73 | |
emh203 | 0:c1253c12d4bc | 74 | _spi.frequency(100000); // Set to 100kHz for initialisation |
emh203 | 0:c1253c12d4bc | 75 | |
emh203 | 0:c1253c12d4bc | 76 | // Initialise the card by clocking it a bit (cs = 1) |
emh203 | 0:c1253c12d4bc | 77 | for(int i=0; i<16; i++) { |
emh203 | 0:c1253c12d4bc | 78 | _spi.write(0xFF); |
emh203 | 0:c1253c12d4bc | 79 | } |
emh203 | 0:c1253c12d4bc | 80 | |
emh203 | 0:c1253c12d4bc | 81 | // send CMD0, should return with all zeros except IDLE STATE set (bit 0) |
emh203 | 0:c1253c12d4bc | 82 | if(_cmd(0, 0) != 0x01) { |
emh203 | 0:c1253c12d4bc | 83 | fprintf(stderr, "Not in idle state\n"); |
emh203 | 0:c1253c12d4bc | 84 | return STA_NOINIT; |
emh203 | 0:c1253c12d4bc | 85 | } |
emh203 | 0:c1253c12d4bc | 86 | |
emh203 | 0:c1253c12d4bc | 87 | // ACMD41 to give host capacity support (repeat until not busy) |
emh203 | 0:c1253c12d4bc | 88 | // ACMD41 is application specific command, so we send APP_CMD (CMD55) beforehand |
emh203 | 0:c1253c12d4bc | 89 | for(int i=0;; i++) { |
emh203 | 0:c1253c12d4bc | 90 | _cmd(55, 0); |
emh203 | 0:c1253c12d4bc | 91 | int response = _cmd(41, 0); |
emh203 | 0:c1253c12d4bc | 92 | if(response == 0) { |
emh203 | 0:c1253c12d4bc | 93 | break; |
emh203 | 0:c1253c12d4bc | 94 | } else if(i > SD_COMMAND_TIMEOUT) { |
emh203 | 0:c1253c12d4bc | 95 | fprintf(stderr, "Timeout waiting for card\n"); |
emh203 | 0:c1253c12d4bc | 96 | return STA_NOINIT; |
emh203 | 0:c1253c12d4bc | 97 | } |
emh203 | 0:c1253c12d4bc | 98 | } |
emh203 | 0:c1253c12d4bc | 99 | |
emh203 | 0:c1253c12d4bc | 100 | _sectors = _sd_sectors(); |
emh203 | 0:c1253c12d4bc | 101 | |
emh203 | 0:c1253c12d4bc | 102 | // Set block length to 512 (CMD16) |
emh203 | 0:c1253c12d4bc | 103 | if(_cmd(16, 512) != 0) { |
emh203 | 0:c1253c12d4bc | 104 | fprintf(stderr, "Set block timeout\n"); |
emh203 | 0:c1253c12d4bc | 105 | return STA_NOINIT; |
emh203 | 0:c1253c12d4bc | 106 | } |
emh203 | 0:c1253c12d4bc | 107 | |
emh203 | 0:c1253c12d4bc | 108 | _spi.frequency(10000000); // Set to 10MHz for data transfer |
emh203 | 0:c1253c12d4bc | 109 | return 0; |
emh203 | 0:c1253c12d4bc | 110 | } |
emh203 | 0:c1253c12d4bc | 111 | |
emh203 | 0:c1253c12d4bc | 112 | DRESULT disk_write(BYTE Drive,const BYTE * Buffer, DWORD SectorNumber, BYTE SectorCount) |
emh203 | 0:c1253c12d4bc | 113 | { |
emh203 | 0:c1253c12d4bc | 114 | BYTE i; |
emh203 | 0:c1253c12d4bc | 115 | |
emh203 | 0:c1253c12d4bc | 116 | BYTE * MyBufOut = (BYTE *)Buffer; |
emh203 | 0:c1253c12d4bc | 117 | |
emh203 | 0:c1253c12d4bc | 118 | for(i=0;i<SectorCount;i++) |
emh203 | 0:c1253c12d4bc | 119 | { |
emh203 | 0:c1253c12d4bc | 120 | // set write address for single block (CMD24) |
emh203 | 0:c1253c12d4bc | 121 | if(_cmd(24, (SectorNumber + i) * 512 ) != 0) { |
emh203 | 0:c1253c12d4bc | 122 | return RES_ERROR; |
emh203 | 0:c1253c12d4bc | 123 | } |
emh203 | 0:c1253c12d4bc | 124 | |
emh203 | 0:c1253c12d4bc | 125 | // send the data block |
emh203 | 0:c1253c12d4bc | 126 | _write(MyBufOut, 512); |
emh203 | 0:c1253c12d4bc | 127 | |
emh203 | 0:c1253c12d4bc | 128 | MyBufOut+=512; |
emh203 | 0:c1253c12d4bc | 129 | } |
emh203 | 0:c1253c12d4bc | 130 | return RES_OK; |
emh203 | 0:c1253c12d4bc | 131 | } |
emh203 | 0:c1253c12d4bc | 132 | |
emh203 | 0:c1253c12d4bc | 133 | DRESULT disk_read(BYTE Drive, BYTE * Buffer,DWORD SectorNumber, BYTE SectorCount) |
emh203 | 0:c1253c12d4bc | 134 | { |
emh203 | 0:c1253c12d4bc | 135 | BYTE i; |
emh203 | 0:c1253c12d4bc | 136 | for(i=0;i<SectorCount;i++) |
emh203 | 0:c1253c12d4bc | 137 | { |
emh203 | 0:c1253c12d4bc | 138 | // set read address for single block (CMD17) |
emh203 | 0:c1253c12d4bc | 139 | if(_cmd(17, (SectorNumber+i) * 512) != 0) |
emh203 | 0:c1253c12d4bc | 140 | { |
emh203 | 0:c1253c12d4bc | 141 | return RES_ERROR; |
emh203 | 0:c1253c12d4bc | 142 | } |
emh203 | 0:c1253c12d4bc | 143 | // receive the data |
emh203 | 0:c1253c12d4bc | 144 | _read(Buffer, 512); |
emh203 | 0:c1253c12d4bc | 145 | |
emh203 | 0:c1253c12d4bc | 146 | Buffer+=512; |
emh203 | 0:c1253c12d4bc | 147 | } |
emh203 | 0:c1253c12d4bc | 148 | return RES_OK; |
emh203 | 0:c1253c12d4bc | 149 | } |
emh203 | 0:c1253c12d4bc | 150 | |
emh203 | 0:c1253c12d4bc | 151 | |
emh203 | 0:c1253c12d4bc | 152 | DWORD get_fattime(void) |
emh203 | 0:c1253c12d4bc | 153 | { |
emh203 | 0:c1253c12d4bc | 154 | time_t CurrentTimeStamp; |
emh203 | 0:c1253c12d4bc | 155 | tm *CurrentLocalTime; |
emh203 | 0:c1253c12d4bc | 156 | DWORD FATFSTimeCode; |
emh203 | 0:c1253c12d4bc | 157 | |
emh203 | 0:c1253c12d4bc | 158 | CurrentTimeStamp = time(NULL); |
emh203 | 0:c1253c12d4bc | 159 | CurrentLocalTime = localtime(&CurrentTimeStamp); |
emh203 | 0:c1253c12d4bc | 160 | |
emh203 | 0:c1253c12d4bc | 161 | //Map the tm struct time into the FatFs time code |
emh203 | 0:c1253c12d4bc | 162 | FATFSTimeCode = ((CurrentLocalTime->tm_year-80)<<25) | |
emh203 | 0:c1253c12d4bc | 163 | ((CurrentLocalTime->tm_mon+1)<<21) | |
emh203 | 0:c1253c12d4bc | 164 | ((CurrentLocalTime->tm_mday)<<16) | |
emh203 | 0:c1253c12d4bc | 165 | ((CurrentLocalTime->tm_hour)<<11) | |
emh203 | 0:c1253c12d4bc | 166 | ((CurrentLocalTime->tm_min)<<5) | |
emh203 | 0:c1253c12d4bc | 167 | ((CurrentLocalTime->tm_sec)); |
emh203 | 0:c1253c12d4bc | 168 | |
emh203 | 0:c1253c12d4bc | 169 | return FATFSTimeCode; |
emh203 | 0:c1253c12d4bc | 170 | } |
emh203 | 0:c1253c12d4bc | 171 | |
emh203 | 0:c1253c12d4bc | 172 | DSTATUS disk_status(BYTE Drive) |
emh203 | 0:c1253c12d4bc | 173 | { |
emh203 | 0:c1253c12d4bc | 174 | return 0; |
emh203 | 0:c1253c12d4bc | 175 | } |
emh203 | 0:c1253c12d4bc | 176 | |
emh203 | 0:c1253c12d4bc | 177 | //************************************************************************************** |
emh203 | 0:c1253c12d4bc | 178 | // Low Level Sector Access Functions (Castrated versions of Simon Fords C++ MBED class |
emh203 | 0:c1253c12d4bc | 179 | //************************************************************************************** |
emh203 | 0:c1253c12d4bc | 180 | |
emh203 | 0:c1253c12d4bc | 181 | int _cmd(int cmd, int arg) { |
emh203 | 0:c1253c12d4bc | 182 | _cs = 0; |
emh203 | 0:c1253c12d4bc | 183 | |
emh203 | 0:c1253c12d4bc | 184 | // send a command |
emh203 | 0:c1253c12d4bc | 185 | _spi.write(0x40 | cmd); |
emh203 | 0:c1253c12d4bc | 186 | _spi.write(arg >> 24); |
emh203 | 0:c1253c12d4bc | 187 | _spi.write(arg >> 16); |
emh203 | 0:c1253c12d4bc | 188 | _spi.write(arg >> 8); |
emh203 | 0:c1253c12d4bc | 189 | _spi.write(arg >> 0); |
emh203 | 0:c1253c12d4bc | 190 | _spi.write(0x95); |
emh203 | 0:c1253c12d4bc | 191 | |
emh203 | 0:c1253c12d4bc | 192 | // wait for the repsonse (response[7] == 0) |
emh203 | 0:c1253c12d4bc | 193 | for(int i=0; i<SD_COMMAND_TIMEOUT; i++) { |
emh203 | 0:c1253c12d4bc | 194 | int response = _spi.write(0xFF); |
emh203 | 0:c1253c12d4bc | 195 | if(!(response & 0x80)) { |
emh203 | 0:c1253c12d4bc | 196 | _cs = 1; |
emh203 | 0:c1253c12d4bc | 197 | return response; |
emh203 | 0:c1253c12d4bc | 198 | } |
emh203 | 0:c1253c12d4bc | 199 | } |
emh203 | 0:c1253c12d4bc | 200 | _cs = 1; |
emh203 | 0:c1253c12d4bc | 201 | return -1; // timeout |
emh203 | 0:c1253c12d4bc | 202 | } |
emh203 | 0:c1253c12d4bc | 203 | |
emh203 | 0:c1253c12d4bc | 204 | int _read(BYTE *buffer, int length) { |
emh203 | 0:c1253c12d4bc | 205 | _cs = 0; |
emh203 | 0:c1253c12d4bc | 206 | |
emh203 | 0:c1253c12d4bc | 207 | // read until start byte (0xFF) |
emh203 | 0:c1253c12d4bc | 208 | while(_spi.write(0xFF) != 0xFE); |
emh203 | 0:c1253c12d4bc | 209 | |
emh203 | 0:c1253c12d4bc | 210 | // read data |
emh203 | 0:c1253c12d4bc | 211 | for(int i=0; i<length; i++) { |
emh203 | 0:c1253c12d4bc | 212 | buffer[i] = _spi.write(0xFF); |
emh203 | 0:c1253c12d4bc | 213 | } |
emh203 | 0:c1253c12d4bc | 214 | _spi.write(0xFF); // checksum |
emh203 | 0:c1253c12d4bc | 215 | _spi.write(0xFF); |
emh203 | 0:c1253c12d4bc | 216 | |
emh203 | 0:c1253c12d4bc | 217 | _cs = 1; |
emh203 | 0:c1253c12d4bc | 218 | return 0; |
emh203 | 0:c1253c12d4bc | 219 | } |
emh203 | 0:c1253c12d4bc | 220 | |
emh203 | 0:c1253c12d4bc | 221 | int _write(BYTE *buffer, int length) { |
emh203 | 0:c1253c12d4bc | 222 | _cs = 0; |
emh203 | 0:c1253c12d4bc | 223 | |
emh203 | 0:c1253c12d4bc | 224 | // indicate start of block |
emh203 | 0:c1253c12d4bc | 225 | _spi.write(0xFE); |
emh203 | 0:c1253c12d4bc | 226 | |
emh203 | 0:c1253c12d4bc | 227 | // write the data |
emh203 | 0:c1253c12d4bc | 228 | for(int i=0; i<length; i++) { |
emh203 | 0:c1253c12d4bc | 229 | _spi.write(buffer[i]); |
emh203 | 0:c1253c12d4bc | 230 | } |
emh203 | 0:c1253c12d4bc | 231 | |
emh203 | 0:c1253c12d4bc | 232 | // write the checksum |
emh203 | 0:c1253c12d4bc | 233 | _spi.write(0xFF); |
emh203 | 0:c1253c12d4bc | 234 | _spi.write(0xFF); |
emh203 | 0:c1253c12d4bc | 235 | |
emh203 | 0:c1253c12d4bc | 236 | // check the repsonse token |
emh203 | 0:c1253c12d4bc | 237 | if((_spi.write(0xFF) & 0x1F) != 0x05) { |
emh203 | 0:c1253c12d4bc | 238 | _cs = 1; |
emh203 | 0:c1253c12d4bc | 239 | return 1; |
emh203 | 0:c1253c12d4bc | 240 | } |
emh203 | 0:c1253c12d4bc | 241 | |
emh203 | 0:c1253c12d4bc | 242 | // wait for write to finish |
emh203 | 0:c1253c12d4bc | 243 | while(_spi.write(0xFF) == 0); |
emh203 | 0:c1253c12d4bc | 244 | |
emh203 | 0:c1253c12d4bc | 245 | _cs = 1; |
emh203 | 0:c1253c12d4bc | 246 | return 0; |
emh203 | 0:c1253c12d4bc | 247 | } |
emh203 | 0:c1253c12d4bc | 248 | |
emh203 | 0:c1253c12d4bc | 249 | int ext_bits(BYTE *data, int msb, int lsb) { |
emh203 | 0:c1253c12d4bc | 250 | int bits = 0; |
emh203 | 0:c1253c12d4bc | 251 | int size = 1 + msb - lsb; |
emh203 | 0:c1253c12d4bc | 252 | for(int i=0; i<size; i++) { |
emh203 | 0:c1253c12d4bc | 253 | int position = lsb + i; |
emh203 | 0:c1253c12d4bc | 254 | int byte = 15 - (position >> 3); |
emh203 | 0:c1253c12d4bc | 255 | int bit = position & 0x7; |
emh203 | 0:c1253c12d4bc | 256 | int value = (data[byte] >> bit) & 1; |
emh203 | 0:c1253c12d4bc | 257 | bits |= value << i; |
emh203 | 0:c1253c12d4bc | 258 | } |
emh203 | 0:c1253c12d4bc | 259 | return bits; |
emh203 | 0:c1253c12d4bc | 260 | } |
emh203 | 0:c1253c12d4bc | 261 | |
emh203 | 0:c1253c12d4bc | 262 | int _sd_sectors() { |
emh203 | 0:c1253c12d4bc | 263 | |
emh203 | 0:c1253c12d4bc | 264 | // CMD9, Response R2 (R1 byte + 16-byte block read) |
emh203 | 0:c1253c12d4bc | 265 | if(_cmd(9, 0) != 0) { |
emh203 | 0:c1253c12d4bc | 266 | fprintf(stderr, "Didn't get a response from the disk\n"); |
emh203 | 0:c1253c12d4bc | 267 | return 0; |
emh203 | 0:c1253c12d4bc | 268 | } |
emh203 | 0:c1253c12d4bc | 269 | |
emh203 | 0:c1253c12d4bc | 270 | BYTE csd[16]; |
emh203 | 0:c1253c12d4bc | 271 | if(_read(csd, 16) != 0) { |
emh203 | 0:c1253c12d4bc | 272 | fprintf(stderr, "Couldn't read csd response from disk\n"); |
emh203 | 0:c1253c12d4bc | 273 | return 0; |
emh203 | 0:c1253c12d4bc | 274 | } |
emh203 | 0:c1253c12d4bc | 275 | |
emh203 | 0:c1253c12d4bc | 276 | // csd_structure : csd[127:126] |
emh203 | 0:c1253c12d4bc | 277 | // c_size : csd[73:62] |
emh203 | 0:c1253c12d4bc | 278 | // c_size_mult : csd[49:47] |
emh203 | 0:c1253c12d4bc | 279 | // read_bl_len : csd[83:80] |
emh203 | 0:c1253c12d4bc | 280 | |
emh203 | 0:c1253c12d4bc | 281 | int csd_structure = ext_bits(csd, 127, 126); |
emh203 | 0:c1253c12d4bc | 282 | int c_size = ext_bits(csd, 73, 62); |
emh203 | 0:c1253c12d4bc | 283 | int c_size_mult = ext_bits(csd, 49, 47); |
emh203 | 0:c1253c12d4bc | 284 | int read_bl_len = ext_bits(csd, 83, 80); |
emh203 | 0:c1253c12d4bc | 285 | |
emh203 | 0:c1253c12d4bc | 286 | if(csd_structure != 0) { |
emh203 | 0:c1253c12d4bc | 287 | fprintf(stderr, "This disk tastes funny! I only know about type 0 CSD structures"); |
emh203 | 0:c1253c12d4bc | 288 | return 0; |
emh203 | 0:c1253c12d4bc | 289 | } |
emh203 | 0:c1253c12d4bc | 290 | |
emh203 | 0:c1253c12d4bc | 291 | int blocks = (c_size + 1) * (1 << (c_size_mult + 2)); |
emh203 | 0:c1253c12d4bc | 292 | int block_size = 1 << read_bl_len; |
emh203 | 0:c1253c12d4bc | 293 | |
emh203 | 0:c1253c12d4bc | 294 | if(block_size != 512) { |
emh203 | 0:c1253c12d4bc | 295 | fprintf(stderr, "This disk tastes funny! I only like 512 byte blocks (%d)\r\n",block_size); |
emh203 | 0:c1253c12d4bc | 296 | return 0; |
emh203 | 0:c1253c12d4bc | 297 | } |
emh203 | 0:c1253c12d4bc | 298 | |
emh203 | 0:c1253c12d4bc | 299 | return blocks; |
emh203 | 0:c1253c12d4bc | 300 | } |