Donatien Garnier / ZG2100NetIfSource
Committer:
donatien
Date:
Fri Aug 06 10:23:41 2010 +0000
Revision:
1:3a7c15057192
Parent:
0:b802fc31f1db

        

Who changed what in which revision?

UserRevisionLine numberNew contents of line
donatien 0:b802fc31f1db 1
donatien 0:b802fc31f1db 2 /*
donatien 0:b802fc31f1db 3 Copyright (c) 2010 Donatien Garnier (donatiengar [at] gmail [dot] com)
donatien 0:b802fc31f1db 4
donatien 0:b802fc31f1db 5 Permission is hereby granted, free of charge, to any person obtaining a copy
donatien 0:b802fc31f1db 6 of this software and associated documentation files (the "Software"), to deal
donatien 0:b802fc31f1db 7 in the Software without restriction, including without limitation the rights
donatien 0:b802fc31f1db 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
donatien 0:b802fc31f1db 9 copies of the Software, and to permit persons to whom the Software is
donatien 0:b802fc31f1db 10 furnished to do so, subject to the following conditions:
donatien 0:b802fc31f1db 11
donatien 0:b802fc31f1db 12 The above copyright notice and this permission notice shall be included in
donatien 0:b802fc31f1db 13 all copies or substantial portions of the Software.
donatien 0:b802fc31f1db 14
donatien 0:b802fc31f1db 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
donatien 0:b802fc31f1db 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
donatien 0:b802fc31f1db 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
donatien 0:b802fc31f1db 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
donatien 0:b802fc31f1db 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
donatien 0:b802fc31f1db 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
donatien 0:b802fc31f1db 21 THE SOFTWARE.
donatien 0:b802fc31f1db 22 */
donatien 0:b802fc31f1db 23
donatien 0:b802fc31f1db 24 #include "netCfg.h"
donatien 0:b802fc31f1db 25 #if NET_ZG2100
donatien 0:b802fc31f1db 26
donatien 0:b802fc31f1db 27 #include "zg_defs.h"
donatien 1:3a7c15057192 28 #include "zg_err.h"
donatien 0:b802fc31f1db 29 #include "zg_drv.h"
donatien 0:b802fc31f1db 30 #include "zg_com.h"
donatien 0:b802fc31f1db 31
donatien 0:b802fc31f1db 32 //#define __DEBUG
donatien 0:b802fc31f1db 33 #include "dbg/dbg.h"
donatien 0:b802fc31f1db 34
donatien 0:b802fc31f1db 35 #include "mbed.h"
donatien 0:b802fc31f1db 36 byte head_buf[ZG_HEAD_BUF_SIZE] ZG_MEM;
donatien 0:b802fc31f1db 37 byte fifo_buf[ZG_FIFO_BUF_SIZE] ZG_MEM; //Big buffer used for fifo transfers
donatien 1:3a7c15057192 38 static volatile bool int_raised;
donatien 1:3a7c15057192 39 static bool mgmt_busy; //Processing a req
donatien 1:3a7c15057192 40 static int tx_pending; //Packet sent but not acked yet
donatien 1:3a7c15057192 41 static bool connected; //Connected to a wifi network
donatien 0:b802fc31f1db 42 ZG_DATA zg_data; //Container for all data received from the chip
donatien 0:b802fc31f1db 43 ZG_DATA_MASK zg_data_mask; //Flags valid data
donatien 1:3a7c15057192 44 static uint32_t current_mgmt_param;
donatien 0:b802fc31f1db 45
donatien 0:b802fc31f1db 46 //Spi intf, Chip Select pin, Interrupt pin
donatien 0:b802fc31f1db 47 zg_err zg_drv_init()
donatien 0:b802fc31f1db 48 {
donatien 0:b802fc31f1db 49 word sys_version;
donatien 0:b802fc31f1db 50 int_raised = false;
donatien 0:b802fc31f1db 51 memset((void*)&zg_data, 0, sizeof(ZG_DATA));
donatien 0:b802fc31f1db 52 memset((void*)&zg_data_mask, 0, sizeof(ZG_DATA_MASK));
donatien 0:b802fc31f1db 53 current_mgmt_param = 0;
donatien 0:b802fc31f1db 54 mgmt_busy = false;
donatien 1:3a7c15057192 55 tx_pending = 0;
donatien 0:b802fc31f1db 56 connected = false;
donatien 0:b802fc31f1db 57
donatien 0:b802fc31f1db 58 //Reset
donatien 0:b802fc31f1db 59 zg_indexed_register_write(ZG_IREG_HW_RST, 0x80FF);
donatien 0:b802fc31f1db 60 zg_indexed_register_write(ZG_IREG_HW_RST, 0x0FFF);
donatien 0:b802fc31f1db 61
donatien 1:3a7c15057192 62 DBG("Started reset\n");
donatien 0:b802fc31f1db 63
donatien 0:b802fc31f1db 64 while( !(zg_indexed_register_read(ZG_IREG_HW_STATUS) & ZG_HW_STATUS_RESET) )
donatien 0:b802fc31f1db 65 {
donatien 0:b802fc31f1db 66 ;
donatien 0:b802fc31f1db 67 }
donatien 0:b802fc31f1db 68
donatien 1:3a7c15057192 69 DBG("Stopped\n");
donatien 0:b802fc31f1db 70
donatien 0:b802fc31f1db 71 while( zg_register_read(ZG_REG_F0_ROOM) == 0 )
donatien 0:b802fc31f1db 72 {
donatien 0:b802fc31f1db 73 ;
donatien 0:b802fc31f1db 74 }
donatien 0:b802fc31f1db 75
donatien 1:3a7c15057192 76 DBG("Started!\n");
donatien 0:b802fc31f1db 77
donatien 0:b802fc31f1db 78 //Reset OK
donatien 0:b802fc31f1db 79
donatien 0:b802fc31f1db 80 //Setup interrupts
donatien 0:b802fc31f1db 81 zg_register_write(ZG_REG_INTF, 0);
donatien 0:b802fc31f1db 82 zg_register_write(ZG_REG_INTE, ZG_INT_MASK_F0 | ZG_INT_MASK_F1);
donatien 0:b802fc31f1db 83
donatien 0:b802fc31f1db 84 zg_register_write(ZG_REG_INTF2, 0xff);
donatien 0:b802fc31f1db 85 zg_register_write(ZG_REG_INTE2, 0);
donatien 0:b802fc31f1db 86
donatien 0:b802fc31f1db 87 //Read firmware version : FIXME
donatien 0:b802fc31f1db 88
donatien 0:b802fc31f1db 89 zg_register_write(ZG_REG_SYSINFO_INDEX, 0);
donatien 0:b802fc31f1db 90
donatien 0:b802fc31f1db 91 sys_version = zg_register_read(ZG_REG_SYSINFO) << 8;
donatien 0:b802fc31f1db 92 sys_version |= zg_register_read(ZG_REG_SYSINFO) & 0xFF;
donatien 0:b802fc31f1db 93
donatien 1:3a7c15057192 94 DBG("System Version : %04x\n", sys_version);
donatien 0:b802fc31f1db 95
donatien 1:3a7c15057192 96 DBG("Setup region\n");
donatien 0:b802fc31f1db 97 //Setup region
donatien 0:b802fc31f1db 98 fifo_buf[0] = ZG_REGION;
donatien 0:b802fc31f1db 99 zg_mgmt_set_param(ZG_FIFO_MGMT_PARM_REGION, fifo_buf, 1);
donatien 0:b802fc31f1db 100
donatien 0:b802fc31f1db 101 while( zg_mgmt_is_busy() )
donatien 0:b802fc31f1db 102 {
donatien 0:b802fc31f1db 103 zg_process();
donatien 0:b802fc31f1db 104 }
donatien 0:b802fc31f1db 105
donatien 0:b802fc31f1db 106 return ZG_OK;
donatien 0:b802fc31f1db 107 }
donatien 0:b802fc31f1db 108
donatien 0:b802fc31f1db 109 void zg_on_data_attach( void (*on_data)() )
donatien 0:b802fc31f1db 110 {
donatien 0:b802fc31f1db 111
donatien 0:b802fc31f1db 112 }
donatien 0:b802fc31f1db 113
donatien 0:b802fc31f1db 114 void zg_process() //Must be called regularly by user
donatien 0:b802fc31f1db 115 {
donatien 1:3a7c15057192 116 if( /*int_raised*/ zg_is_int() )
donatien 0:b802fc31f1db 117 {
donatien 1:3a7c15057192 118 //DBG("Processing int\n");
donatien 0:b802fc31f1db 119 zg_int_process();
donatien 0:b802fc31f1db 120 int_raised = false;
donatien 0:b802fc31f1db 121 }
donatien 0:b802fc31f1db 122
donatien 0:b802fc31f1db 123 }
donatien 0:b802fc31f1db 124
donatien 0:b802fc31f1db 125 void zg_int_process()
donatien 0:b802fc31f1db 126 {
donatien 0:b802fc31f1db 127 uint32_t int_reg;
donatien 0:b802fc31f1db 128 int fifo;
donatien 0:b802fc31f1db 129 int len;
donatien 0:b802fc31f1db 130
donatien 0:b802fc31f1db 131 byte type;
donatien 0:b802fc31f1db 132 byte subtype;
donatien 0:b802fc31f1db 133
donatien 1:3a7c15057192 134 /*while(true) //Multiple interrupts might have been raised, loop until the interrupt register is blank
donatien 1:3a7c15057192 135 {*/
donatien 1:3a7c15057192 136 int_reg = zg_register_read(ZG_REG_INTF) & zg_register_read(ZG_REG_INTE); //Read Masked Interrupt reg
donatien 1:3a7c15057192 137 if( int_reg & ZG_INT_MASK_F0 )
donatien 1:3a7c15057192 138 {
donatien 1:3a7c15057192 139 fifo = 0;
donatien 1:3a7c15057192 140 }
donatien 1:3a7c15057192 141 else if( int_reg & ZG_INT_MASK_F1 )
donatien 1:3a7c15057192 142 {
donatien 1:3a7c15057192 143 fifo = 1;
donatien 1:3a7c15057192 144 }
donatien 1:3a7c15057192 145 else
donatien 1:3a7c15057192 146 {
donatien 1:3a7c15057192 147 return;
donatien 1:3a7c15057192 148 }
donatien 1:3a7c15057192 149
donatien 1:3a7c15057192 150 zg_register_write(ZG_REG_INTF, ZG_INT_MASK_F(fifo)); //Select that FIFO ?
donatien 1:3a7c15057192 151
donatien 1:3a7c15057192 152 len = zg_register_read(ZG_REG_F_LEN(fifo)) & 0xFFF; //Only 12 lower level bits represent length
donatien 1:3a7c15057192 153
donatien 1:3a7c15057192 154 zg_fifo_read(ZG_FIFO_ANY, &type, &subtype, fifo_buf, len);
donatien 1:3a7c15057192 155
donatien 1:3a7c15057192 156 //Dispatch this packet
donatien 1:3a7c15057192 157
donatien 1:3a7c15057192 158 switch( type )
donatien 1:3a7c15057192 159 {
donatien 1:3a7c15057192 160 case ZG_FIFO_RD_TXD_ACK:
donatien 1:3a7c15057192 161 //DBG("TX ACK\n");
donatien 1:3a7c15057192 162 //Packet has been transmitted, we can send another one
donatien 1:3a7c15057192 163 tx_pending--;
donatien 1:3a7c15057192 164 break;
donatien 1:3a7c15057192 165 case ZG_FIFO_RD_RXD_AVL:
donatien 1:3a7c15057192 166 //DBG("RX AVL\n");
donatien 1:3a7c15057192 167 //Received a packet, process it
donatien 1:3a7c15057192 168 zg_on_input(fifo_buf, len); //On reception of a ZG frame : convert into Eth frame & call zg_input
donatien 1:3a7c15057192 169 break;
donatien 1:3a7c15057192 170 case ZG_FIFO_RD_MGMT_AVL:
donatien 1:3a7c15057192 171 zg_on_mgmt_avl(subtype, fifo_buf, len);
donatien 1:3a7c15057192 172 mgmt_busy = false; //We can now do another mgmt req
donatien 1:3a7c15057192 173 break;
donatien 1:3a7c15057192 174 case ZG_FIFO_RD_MGMT_EVT:
donatien 1:3a7c15057192 175 zg_on_mgmt_evt(subtype, fifo_buf, len);
donatien 1:3a7c15057192 176 break;
donatien 1:3a7c15057192 177 default:
donatien 1:3a7c15057192 178 DBG("Int processed with type %d\n", type);
donatien 1:3a7c15057192 179 //Unknown type
donatien 1:3a7c15057192 180 //continue;
donatien 1:3a7c15057192 181 break;
donatien 1:3a7c15057192 182 }
donatien 1:3a7c15057192 183 /*}*/
donatien 0:b802fc31f1db 184 }
donatien 0:b802fc31f1db 185
donatien 0:b802fc31f1db 186 bool zg_mgmt_is_busy()
donatien 0:b802fc31f1db 187 {
donatien 0:b802fc31f1db 188 return mgmt_busy;
donatien 0:b802fc31f1db 189 }
donatien 0:b802fc31f1db 190
donatien 0:b802fc31f1db 191 void zg_mgmt_req(byte subtype, byte* buf, int len, bool close /*= true*/)
donatien 0:b802fc31f1db 192 {
donatien 0:b802fc31f1db 193 zg_fifo_write( ZG_FIFO_MGMT, ZG_FIFO_WR_MGMT_REQ, subtype, buf, len, true, close);
donatien 0:b802fc31f1db 194 mgmt_busy = true;
donatien 0:b802fc31f1db 195 }
donatien 0:b802fc31f1db 196
donatien 0:b802fc31f1db 197 void zg_mgmt_data(byte* buf, int len, bool close /*= true*/)
donatien 0:b802fc31f1db 198 {
donatien 0:b802fc31f1db 199 zg_fifo_write( ZG_FIFO_MGMT, ZG_FIFO_WR_MGMT_REQ, 0/*subtype: do not care*/, buf, len, false, close);
donatien 0:b802fc31f1db 200 }
donatien 0:b802fc31f1db 201
donatien 0:b802fc31f1db 202 void zg_mgmt_get_param(byte param)
donatien 0:b802fc31f1db 203 {
donatien 0:b802fc31f1db 204 head_buf[0] = 0;
donatien 0:b802fc31f1db 205 head_buf[1] = param;
donatien 0:b802fc31f1db 206 zg_mgmt_req( ZG_FIFO_MGMT_PARM_GET, head_buf, 2 );
donatien 0:b802fc31f1db 207 current_mgmt_param = param;
donatien 0:b802fc31f1db 208 }
donatien 0:b802fc31f1db 209
donatien 0:b802fc31f1db 210 void zg_mgmt_set_param(byte param, byte* buf, int len)
donatien 0:b802fc31f1db 211 {
donatien 0:b802fc31f1db 212 head_buf[0] = 0;
donatien 0:b802fc31f1db 213 head_buf[1] = param;
donatien 0:b802fc31f1db 214 zg_mgmt_req( ZG_FIFO_MGMT_PARM_SET, head_buf, 2, false );
donatien 0:b802fc31f1db 215 zg_mgmt_data( buf, len );
donatien 0:b802fc31f1db 216 current_mgmt_param = param;
donatien 0:b802fc31f1db 217 }
donatien 0:b802fc31f1db 218
donatien 0:b802fc31f1db 219 void zg_on_mgmt_avl(byte subtype, byte* buf, int len) //Data is available
donatien 0:b802fc31f1db 220 {
donatien 1:3a7c15057192 221 DBG("Management result, subtype %d\n", subtype);
donatien 0:b802fc31f1db 222 switch(subtype)
donatien 0:b802fc31f1db 223 {
donatien 0:b802fc31f1db 224 case ZG_FIFO_MGMT_SCAN: //Scan results
donatien 0:b802fc31f1db 225 zg_on_scan_results(buf, len);
donatien 0:b802fc31f1db 226 break;
donatien 0:b802fc31f1db 227
donatien 0:b802fc31f1db 228 case ZG_FIFO_MGMT_PSK_CALC: //Compute PSK Key
donatien 0:b802fc31f1db 229 zg_on_psk_key(buf, len);
donatien 0:b802fc31f1db 230 break;
donatien 0:b802fc31f1db 231 case ZG_FIFO_MGMT_PMK_KEY:
donatien 0:b802fc31f1db 232 break;
donatien 0:b802fc31f1db 233 case ZG_FIFO_MGMT_WEP_KEY:
donatien 0:b802fc31f1db 234 break;
donatien 0:b802fc31f1db 235
donatien 0:b802fc31f1db 236 case ZG_FIFO_MGMT_PARM_SET:
donatien 1:3a7c15057192 237 DBG("Param set\n");
donatien 0:b802fc31f1db 238 break;
donatien 0:b802fc31f1db 239 case ZG_FIFO_MGMT_PARM_GET:
donatien 0:b802fc31f1db 240 zg_on_mgmt_get_param(buf,len);
donatien 0:b802fc31f1db 241 break;
donatien 0:b802fc31f1db 242 case ZG_FIFO_MGMT_ADHOC:
donatien 0:b802fc31f1db 243 break;
donatien 0:b802fc31f1db 244 case ZG_FIFO_MGMT_CONNECT:
donatien 1:3a7c15057192 245 DBG("Connect result %d, MAC status is %d\n", buf[0], buf[1]);
donatien 1:3a7c15057192 246 zg_on_connect(zg_errcode((ZG_INT_ERR)buf[0]));
donatien 0:b802fc31f1db 247 connected = true;
donatien 0:b802fc31f1db 248 break;
donatien 0:b802fc31f1db 249 case ZG_FIFO_MGMT_CONN_MGMT:
donatien 0:b802fc31f1db 250 break;
donatien 0:b802fc31f1db 251 default:
donatien 0:b802fc31f1db 252 break;
donatien 0:b802fc31f1db 253 }
donatien 0:b802fc31f1db 254 }
donatien 0:b802fc31f1db 255
donatien 0:b802fc31f1db 256 void zg_on_mgmt_evt(byte subtype, byte* buf, int len) //Management event
donatien 0:b802fc31f1db 257 {
donatien 1:3a7c15057192 258 DBG("Management event, subtype %d\n", subtype);
donatien 0:b802fc31f1db 259 switch(subtype)
donatien 0:b802fc31f1db 260 {
donatien 0:b802fc31f1db 261 case ZG_FIFO_MGMT_DISASSOC:
donatien 0:b802fc31f1db 262 case ZG_FIFO_MGMT_DEAUTH:
donatien 1:3a7c15057192 263 DBG("Disconnected\n");
donatien 0:b802fc31f1db 264 connected = false;
donatien 0:b802fc31f1db 265 break;
donatien 0:b802fc31f1db 266 case ZG_FIFO_MGMT_CONN:
donatien 1:3a7c15057192 267 DBG("Connection status %d\n", DTOHS( *((word*)&buf[0]) ) );
donatien 0:b802fc31f1db 268 break;
donatien 0:b802fc31f1db 269
donatien 0:b802fc31f1db 270 default:
donatien 0:b802fc31f1db 271 break;
donatien 0:b802fc31f1db 272 }
donatien 0:b802fc31f1db 273 }
donatien 0:b802fc31f1db 274
donatien 0:b802fc31f1db 275 void zg_on_mgmt_get_param(byte* buf, int len)
donatien 0:b802fc31f1db 276 {
donatien 0:b802fc31f1db 277 if(buf[0] != 1 /*Success*/)
donatien 0:b802fc31f1db 278 {
donatien 0:b802fc31f1db 279 return;
donatien 0:b802fc31f1db 280 }
donatien 0:b802fc31f1db 281 buf+=4; //4-byte header
donatien 0:b802fc31f1db 282 len-=4;
donatien 0:b802fc31f1db 283 switch(current_mgmt_param)
donatien 0:b802fc31f1db 284 {
donatien 0:b802fc31f1db 285 case ZG_FIFO_MGMT_PARM_MACAD: //6 bytes len
donatien 0:b802fc31f1db 286 memcpy((void*)&zg_data.mac_addr, (void*)buf, ZG_MACADDR_LEN);
donatien 0:b802fc31f1db 287 zg_data_mask.mac_addr = true;
donatien 1:3a7c15057192 288 DBG("HW Addr is : %02x:%02x:%02x:%02x:%02x:%02x.\n",
donatien 0:b802fc31f1db 289 zg_data.mac_addr[0], zg_data.mac_addr[1], zg_data.mac_addr[2],
donatien 0:b802fc31f1db 290 zg_data.mac_addr[3], zg_data.mac_addr[4], zg_data.mac_addr[5]);
donatien 0:b802fc31f1db 291 break;
donatien 0:b802fc31f1db 292 case ZG_FIFO_MGMT_PARM_SYSV: //2 bytes len
donatien 0:b802fc31f1db 293 memcpy((void*)&zg_data.sys_version, (void*)buf, 2);
donatien 1:3a7c15057192 294 DBG("Sys version: ROM: %02x; Patch: %02x\n",
donatien 0:b802fc31f1db 295 zg_data.sys_version.rom, zg_data.sys_version.revision);
donatien 0:b802fc31f1db 296 zg_data_mask.sys_version = true;
donatien 0:b802fc31f1db 297 break;
donatien 0:b802fc31f1db 298 case ZG_FIFO_MGMT_PARM_REGION:
donatien 1:3a7c15057192 299 DBG("Region %d\n", buf[0]);
donatien 0:b802fc31f1db 300 break;
donatien 0:b802fc31f1db 301 default:
donatien 0:b802fc31f1db 302 break;
donatien 0:b802fc31f1db 303 }
donatien 0:b802fc31f1db 304 current_mgmt_param = 0;
donatien 0:b802fc31f1db 305 }
donatien 0:b802fc31f1db 306
donatien 0:b802fc31f1db 307 //uint32_t zg_fifo_room();
donatien 0:b802fc31f1db 308
donatien 0:b802fc31f1db 309 void zg_on_int() //On data available interrupt
donatien 0:b802fc31f1db 310 {
donatien 0:b802fc31f1db 311 int_raised = true;
donatien 0:b802fc31f1db 312 }
donatien 0:b802fc31f1db 313
donatien 0:b802fc31f1db 314 //Useful to be split in several function because Lwip stores buffers in chunks
donatien 0:b802fc31f1db 315 void zg_send_start()
donatien 0:b802fc31f1db 316 {
donatien 1:3a7c15057192 317 tx_pending++;
donatien 0:b802fc31f1db 318 zg_fifo_write( ZG_FIFO_DATA, ZG_FIFO_WR_TXD_REQ, ZG_FIFO_TXD_STD, NULL, 0, true, false ); //Open fifo but does not close it
donatien 0:b802fc31f1db 319 }
donatien 0:b802fc31f1db 320
donatien 0:b802fc31f1db 321 void zg_send(byte* buf, int len)
donatien 0:b802fc31f1db 322 {
donatien 0:b802fc31f1db 323 zg_fifo_write( ZG_FIFO_DATA, ZG_FIFO_WR_TXD_REQ, ZG_FIFO_TXD_STD, buf, len, false, false );
donatien 0:b802fc31f1db 324 }
donatien 0:b802fc31f1db 325
donatien 0:b802fc31f1db 326 void zg_send_end()
donatien 0:b802fc31f1db 327 {
donatien 0:b802fc31f1db 328 zg_fifo_write( ZG_FIFO_DATA, ZG_FIFO_WR_TXD_REQ, ZG_FIFO_TXD_STD, NULL, 0, false, true ); //Close fifo
donatien 0:b802fc31f1db 329 }
donatien 0:b802fc31f1db 330
donatien 0:b802fc31f1db 331 bool zg_send_is_busy()
donatien 0:b802fc31f1db 332 {
donatien 1:3a7c15057192 333 if( (tx_pending >= ZG_MAX_TX_PENDING) )
donatien 1:3a7c15057192 334 {
donatien 1:3a7c15057192 335 DBG("Tx is busy...\n");
donatien 1:3a7c15057192 336 return true;
donatien 1:3a7c15057192 337 }
donatien 1:3a7c15057192 338 return false;
donatien 0:b802fc31f1db 339 }
donatien 0:b802fc31f1db 340
donatien 0:b802fc31f1db 341 #endif