local fix version of myBlueUSB (http://mbed.org/users/networker/code/myBlueUSB/). - merge deleted files which are required to compile. - enable echo back of received data via RFCOMM.

Dependencies:   AvailableMemory FatFileSystem mbed myUSBHost

Committer:
nobukuma
Date:
Sun Dec 08 21:52:09 2013 +0000
Revision:
2:9f25a7fa1a54
Parent:
0:003889bc474f
???BT??????????????????; ?????????????????

Who changed what in which revision?

UserRevisionLine numberNew contents of line
nobukuma 0:003889bc474f 1
nobukuma 0:003889bc474f 2 /*
nobukuma 0:003889bc474f 3 Copyright (c) 2010 Peter Barrett
nobukuma 0:003889bc474f 4
nobukuma 0:003889bc474f 5 Permission is hereby granted, free of charge, to any person obtaining a copy
nobukuma 0:003889bc474f 6 of this software and associated documentation files (the "Software"), to deal
nobukuma 0:003889bc474f 7 in the Software without restriction, including without limitation the rights
nobukuma 0:003889bc474f 8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
nobukuma 0:003889bc474f 9 copies of the Software, and to permit persons to whom the Software is
nobukuma 0:003889bc474f 10 furnished to do so, subject to the following conditions:
nobukuma 0:003889bc474f 11
nobukuma 0:003889bc474f 12 The above copyright notice and this permission notice shall be included in
nobukuma 0:003889bc474f 13 all copies or substantial portions of the Software.
nobukuma 0:003889bc474f 14
nobukuma 0:003889bc474f 15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
nobukuma 0:003889bc474f 16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
nobukuma 0:003889bc474f 17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
nobukuma 0:003889bc474f 18 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
nobukuma 0:003889bc474f 19 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
nobukuma 0:003889bc474f 20 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
nobukuma 0:003889bc474f 21 THE SOFTWARE.
nobukuma 0:003889bc474f 22 */
nobukuma 0:003889bc474f 23 #include "mbed.h"
nobukuma 0:003889bc474f 24 #include <vector>
nobukuma 0:003889bc474f 25 #include "Utils.h"
nobukuma 0:003889bc474f 26 #include "USBHost.h"
nobukuma 0:003889bc474f 27 #include "hci.h"
nobukuma 0:003889bc474f 28 #include "HCITransportUSB.h"
nobukuma 0:003889bc474f 29 #include "RFCOMM.h"
nobukuma 0:003889bc474f 30 #include "ftclasslibusbdevbt.h"
nobukuma 0:003889bc474f 31 #include "sdp_data.h"
nobukuma 0:003889bc474f 32 #include "sdp.h"
nobukuma 0:003889bc474f 33 #include "btserial.h"
nobukuma 0:003889bc474f 34 #include "neighbourhood.h"
nobukuma 0:003889bc474f 35
nobukuma 0:003889bc474f 36 /************************************************
nobukuma 0:003889bc474f 37 TODO:
nobukuma 0:003889bc474f 38 mtu and credits are completely unhandled - in progress
nobukuma 0:003889bc474f 39 multiple rfcomm sessions should be possible - done
nobukuma 0:003889bc474f 40 SDP would be nice - beta
nobukuma 0:003889bc474f 41 multiple rfcomm channels are untested
nobukuma 0:003889bc474f 42 decoupling of rfcomm and application - much better
nobukuma 0:003889bc474f 43 packets are not reassembled - some are (HCI and ft application level)
nobukuma 0:003889bc474f 44 disconnect and timeouts
nobukuma 0:003889bc474f 45 ************************************************/
nobukuma 0:003889bc474f 46 #define DEBUG 1
nobukuma 0:003889bc474f 47 int state = 0;
nobukuma 0:003889bc474f 48
nobukuma 0:003889bc474f 49 //int bulk = 0;
nobukuma 0:003889bc474f 50 void printf(const BD_ADDR* addr) {
nobukuma 0:003889bc474f 51 const u8* a = addr->addr;
nobukuma 0:003889bc474f 52 printf("%02X:%02X:%02X:%02X:%02X:%02X",a[5],a[4],a[3],a[2],a[1],a[0]);
nobukuma 0:003889bc474f 53 }
nobukuma 0:003889bc474f 54
nobukuma 0:003889bc474f 55 const char FtDevClass[3] = {0x00, 0x1F, 0x82 };
nobukuma 0:003889bc474f 56 const char SerDevClass[3] = {4, 1, 0x00};
nobukuma 0:003889bc474f 57 // Instance
nobukuma 0:003889bc474f 58 //RFCOMMManager rfcomm_manager;
nobukuma 0:003889bc474f 59
nobukuma 0:003889bc474f 60 class application : public HCI {
nobukuma 0:003889bc474f 61 BTDevice* devs[8];
nobukuma 0:003889bc474f 62 int count, i, pending;
nobukuma 0:003889bc474f 63 public:
nobukuma 0:003889bc474f 64 // We have connected to a device
nobukuma 0:003889bc474f 65 void ConnectionComplete(connection_info* info) {
nobukuma 0:003889bc474f 66 printf("ConnectionComplete ");
nobukuma 0:003889bc474f 67 BD_ADDR* a = &info->bdaddr;
nobukuma 0:003889bc474f 68 printf(a);
nobukuma 0:003889bc474f 69 printf("\n");
nobukuma 0:003889bc474f 70 RemoteNameRequest(a);
nobukuma 0:003889bc474f 71 for (i++; i < count; i++) {//find the next device to open
nobukuma 0:003889bc474f 72 printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
nobukuma 2:9f25a7fa1a54 73 //if (devs[i]->_handle == 0 && memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0) {//or some other way to connect to RFCOMM devices
nobukuma 2:9f25a7fa1a54 74 if (devs[i]->_handle == 0) { //
nobukuma 0:003889bc474f 75 BD_ADDR* bd = &devs[i]->_info.bdaddr;
nobukuma 0:003889bc474f 76 printf("Connecting to ");
nobukuma 0:003889bc474f 77 printf(bd);
nobukuma 0:003889bc474f 78 printf("\n");
nobukuma 0:003889bc474f 79 pending++;
nobukuma 0:003889bc474f 80 CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.)
nobukuma 0:003889bc474f 81 printf("connection cmd was sent\n");
nobukuma 0:003889bc474f 82 return;
nobukuma 0:003889bc474f 83 }
nobukuma 0:003889bc474f 84 }
nobukuma 0:003889bc474f 85 //state = 1; //start the real application
nobukuma 0:003889bc474f 86 }
nobukuma 0:003889bc474f 87
nobukuma 0:003889bc474f 88 void ConnectDevices() {
nobukuma 0:003889bc474f 89 count = GetDevices(devs,8);//get pointers to all bluetooth devices
nobukuma 0:003889bc474f 90 pending = 0;
nobukuma 0:003889bc474f 91 for (i = 0; i < count; i++) {
nobukuma 0:003889bc474f 92 printfBytes("DEVICE CLASS",devs[i]->_info.dev_class,3);
nobukuma 0:003889bc474f 93 if (devs[i]->_handle == 0 /*&& memcmp(devs[i]->_info.dev_class, FtDevClass, 3)==0*/) {//or some other way to connect to RFCOMM devices
nobukuma 0:003889bc474f 94 BD_ADDR* bd = &devs[i]->_info.bdaddr;
nobukuma 0:003889bc474f 95 printf("Connecting to ");
nobukuma 0:003889bc474f 96 printf(bd);
nobukuma 0:003889bc474f 97 printf("\n");
nobukuma 0:003889bc474f 98 pending++;
nobukuma 0:003889bc474f 99 CreateConnection(bd); //some low level connect, just let it happen for now (sets pin, mtu etc.)
nobukuma 0:003889bc474f 100 printf("connection cmd was sent\n");
nobukuma 0:003889bc474f 101 return;
nobukuma 0:003889bc474f 102 }
nobukuma 0:003889bc474f 103 }
nobukuma 0:003889bc474f 104 if (pending == 0) state = 1;//for the case when there are no ft devices
nobukuma 0:003889bc474f 105 }
nobukuma 0:003889bc474f 106 virtual void Callback(HCI_CALLBACK_EVENT c, const u8* data, int len);
nobukuma 0:003889bc474f 107 int csr_write_bd_addr(BD_ADDR *bdaddr, bool transient=true);
nobukuma 0:003889bc474f 108 int csr_reset_device(bool transient=true);
nobukuma 0:003889bc474f 109 } App; //application instance
nobukuma 0:003889bc474f 110
nobukuma 0:003889bc474f 111 extern "C" void mbed_reset();
nobukuma 0:003889bc474f 112
nobukuma 0:003889bc474f 113
nobukuma 0:003889bc474f 114 void application::Callback(HCI_CALLBACK_EVENT evt, const u8* data, int len) {//these events are forwarded (in)directly from HCIRecv
nobukuma 0:003889bc474f 115 unsigned char pin[] = "1234";
nobukuma 0:003889bc474f 116 unsigned char newaddr[] = {0x2c, 0x07, 0x54, 0x7b, 0x13, 0x00};//possible ft TX address (ROBO TX-277)
nobukuma 0:003889bc474f 117 // unsigned char newaddr[] = {0x57, 0x0a, 0x3d, 0x83, 0x15, 0x00};//original address of the cheap round BT dongle
nobukuma 0:003889bc474f 118 printf("\x1b[%dm", 33);
nobukuma 0:003889bc474f 119 switch (evt) {
nobukuma 0:003889bc474f 120 case CALLBACK_READY:
nobukuma 0:003889bc474f 121 printf("CALLBACK_READY\n");
nobukuma 0:003889bc474f 122 printf("my address = ");
nobukuma 0:003889bc474f 123 printf((BD_ADDR*)data);
nobukuma 0:003889bc474f 124 if (memcmp(newaddr, data, 6) != 0) { //csr_write_bd_addr((BD_ADDR*)newaddr, false);
nobukuma 0:003889bc474f 125 }
nobukuma 0:003889bc474f 126 Inquiry();//start the second phase of the discovery
nobukuma 0:003889bc474f 127 break;
nobukuma 0:003889bc474f 128
nobukuma 0:003889bc474f 129 case CALLBACK_INQUIRY_RESULT: //optionally build the list of FT devices here
nobukuma 0:003889bc474f 130 printf("CALLBACK_INQUIRY_RESULT ");
nobukuma 0:003889bc474f 131 printf((BD_ADDR*)data);
nobukuma 0:003889bc474f 132 printf("\n");//data points to inquiry_info struct
nobukuma 0:003889bc474f 133 // RemoteNameRequest((BD_ADDR*)data);
nobukuma 0:003889bc474f 134 break;
nobukuma 0:003889bc474f 135
nobukuma 0:003889bc474f 136 case CALLBACK_INQUIRY_DONE:
nobukuma 0:003889bc474f 137 printf("CALLBACK_INQUIRY_DONE\n");
nobukuma 0:003889bc474f 138 neighbors = new neighbourhood(&App);
nobukuma 0:003889bc474f 139 neighbors->read();
nobukuma 0:003889bc474f 140 ConnectDevices();
nobukuma 0:003889bc474f 141 break;
nobukuma 0:003889bc474f 142
nobukuma 0:003889bc474f 143 case CALLBACK_REMOTE_NAME: {
nobukuma 0:003889bc474f 144 BD_ADDR* addr = (BD_ADDR*)data;
nobukuma 0:003889bc474f 145 const char* name = (const char*)(data + 6);
nobukuma 0:003889bc474f 146 printf(addr);
nobukuma 0:003889bc474f 147 printf(" = % s\n",name);
nobukuma 0:003889bc474f 148 pending--;
nobukuma 0:003889bc474f 149 if (pending == 0) state = 1;
nobukuma 0:003889bc474f 150 }
nobukuma 0:003889bc474f 151 break;
nobukuma 0:003889bc474f 152
nobukuma 0:003889bc474f 153 case CALLBACK_CONNECTION_COMPLETE: {
nobukuma 0:003889bc474f 154 connection_info *ci = (connection_info*)data;
nobukuma 0:003889bc474f 155 if (ci->status>0) {
nobukuma 0:003889bc474f 156 printf("Connection failed, status=0x%02X\n", ci->status);
nobukuma 0:003889bc474f 157 break;
nobukuma 0:003889bc474f 158 }
nobukuma 0:003889bc474f 159 ConnectionComplete(ci);
nobukuma 0:003889bc474f 160 printf("Going to open sdp socket\n");
nobukuma 0:003889bc474f 161 L2CAPAddr addr;
nobukuma 0:003889bc474f 162 memcpy(&addr.bdaddr, &ci->bdaddr, 6);
nobukuma 0:003889bc474f 163 //int s = SDP.Open(&addr.hdr);
nobukuma 0:003889bc474f 164 }
nobukuma 0:003889bc474f 165 break;
nobukuma 0:003889bc474f 166 case CALLBACK_PIN_REQ:
nobukuma 0:003889bc474f 167 printf("Enter PIN for ");
nobukuma 0:003889bc474f 168 printf((BD_ADDR*)data);
nobukuma 0:003889bc474f 169 printf(" : submitting %s\n", pin);
nobukuma 0:003889bc474f 170 //USBLoop(); wait(1.0); USBLoop();
nobukuma 0:003889bc474f 171 //for(int k=0; k<2000000;k++) USBLoop();
nobukuma 0:003889bc474f 172 PinCodeReply(data, pin);
nobukuma 0:003889bc474f 173 break;
nobukuma 0:003889bc474f 174 case CALLBACK_VENDOR:
nobukuma 0:003889bc474f 175 printfBytes("Vendor Reply:", data, len);
nobukuma 0:003889bc474f 176 //mbed_reset();
nobukuma 0:003889bc474f 177 if (data[0] == 0xc2)
nobukuma 0:003889bc474f 178 csr_reset_device(false);
nobukuma 0:003889bc474f 179 break;
nobukuma 0:003889bc474f 180 default:
nobukuma 0:003889bc474f 181 printf("Unhandled HCI Callback %d\n", evt);
nobukuma 0:003889bc474f 182 };
nobukuma 0:003889bc474f 183 printf("\x1b[%dm", 0);
nobukuma 0:003889bc474f 184 }
nobukuma 0:003889bc474f 185
nobukuma 0:003889bc474f 186 #define CSR_WRITE 0xFC00
nobukuma 0:003889bc474f 187
nobukuma 0:003889bc474f 188 int application::csr_write_bd_addr(BD_ADDR *bdaddr, bool transient) {
nobukuma 0:003889bc474f 189 unsigned char cmd[] = { 0xc2,
nobukuma 0:003889bc474f 190 0x02, 0x00, 0x0c, 0x00, 0x11, 0x47, 0x03, 0x70,
nobukuma 0:003889bc474f 191 0x00, 0x00, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00,
nobukuma 0:003889bc474f 192 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
nobukuma 0:003889bc474f 193 };
nobukuma 0:003889bc474f 194
nobukuma 0:003889bc474f 195 if (transient)
nobukuma 0:003889bc474f 196 cmd[15] = 0x08;
nobukuma 0:003889bc474f 197
nobukuma 0:003889bc474f 198 cmd[17] = bdaddr->addr[2];
nobukuma 0:003889bc474f 199 cmd[18] = 0x00;
nobukuma 0:003889bc474f 200 cmd[19] = bdaddr->addr[0];
nobukuma 0:003889bc474f 201 cmd[20] = bdaddr->addr[1];
nobukuma 0:003889bc474f 202 cmd[21] = bdaddr->addr[3];
nobukuma 0:003889bc474f 203 cmd[22] = 0x00;
nobukuma 0:003889bc474f 204 cmd[23] = bdaddr->addr[4];
nobukuma 0:003889bc474f 205 cmd[24] = bdaddr->addr[5];
nobukuma 0:003889bc474f 206
nobukuma 0:003889bc474f 207 return SendCmd(CSR_WRITE, cmd, sizeof(cmd));
nobukuma 0:003889bc474f 208 }
nobukuma 0:003889bc474f 209
nobukuma 0:003889bc474f 210 int application::csr_reset_device(bool transient) {
nobukuma 0:003889bc474f 211 unsigned char cmd[] = { 0xc2, 0x02, 0x00, 0x09, 0x00,
nobukuma 0:003889bc474f 212 0x00, 0x00, 0x01, 0x40, 0x00, 0x00,
nobukuma 0:003889bc474f 213 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
nobukuma 0:003889bc474f 214 };
nobukuma 0:003889bc474f 215
nobukuma 0:003889bc474f 216 if (transient)
nobukuma 0:003889bc474f 217 cmd[7] = 0x02;
nobukuma 0:003889bc474f 218
nobukuma 0:003889bc474f 219 return SendCmd(CSR_WRITE, cmd, sizeof(cmd));
nobukuma 0:003889bc474f 220 }
nobukuma 0:003889bc474f 221
nobukuma 0:003889bc474f 222
nobukuma 0:003889bc474f 223 // these should be placed in the DMA SRAM
nobukuma 0:003889bc474f 224 typedef struct {
nobukuma 0:003889bc474f 225 u8 _hciBuffer[MAX_HCL_SIZE];
nobukuma 0:003889bc474f 226 u8 _aclBuffer[MAX_ACL_SIZE];
nobukuma 0:003889bc474f 227 } SRAMPlacement;
nobukuma 0:003889bc474f 228
nobukuma 0:003889bc474f 229 HCITransportUSB _HCITransportUSB; //use USB as the transport to the radio
nobukuma 0:003889bc474f 230
nobukuma 0:003889bc474f 231 int OnBluetoothInsert(int device) {//install the HCI and start discovery, user callbacks are made to HciCalback
nobukuma 0:003889bc474f 232 printf("Bluetooth inserted of %d\n",device);
nobukuma 0:003889bc474f 233 u32 sramLen;
nobukuma 0:003889bc474f 234 u8* sram = USBGetBuffer(&sramLen);
nobukuma 0:003889bc474f 235 sram = (u8*)(((u32)sram + 1023) & ~1023);
nobukuma 0:003889bc474f 236 SRAMPlacement* s = (SRAMPlacement*)sram;
nobukuma 0:003889bc474f 237 _HCITransportUSB.Open(device,s->_hciBuffer,s->_aclBuffer);//setup buffers for USB host, incoming data goes first to HCIRecv and ACLRecv
nobukuma 0:003889bc474f 238 RegisterSocketHandler(SOCKET_L2CAP,&App); //register the application::hci as handler for L2CAP events
nobukuma 0:003889bc474f 239 RegisterSocketHandler(SOCKET_RFCOM, &rfcomm_manager);//set the RFCOMMManager as the RFCOM socket handler
nobukuma 0:003889bc474f 240 if (RegisterSocketHandler(SOCKET_SDP, &SDP))
nobukuma 0:003889bc474f 241 printf("Could not register SDP socket type\n");
nobukuma 0:003889bc474f 242 App.Open(&_HCITransportUSB);//the callback is virtual
nobukuma 0:003889bc474f 243 App.Inquiry();//start discovery of BT devices phase 0
nobukuma 0:003889bc474f 244 return 0;
nobukuma 0:003889bc474f 245 }
nobukuma 0:003889bc474f 246
nobukuma 0:003889bc474f 247 DigitalOut led(LED1), loop(LED2);
nobukuma 0:003889bc474f 248
nobukuma 0:003889bc474f 249 int comm = 0;
nobukuma 0:003889bc474f 250 btserial *incoming, *outgoing;
nobukuma 0:003889bc474f 251
nobukuma 0:003889bc474f 252 void echo(int socket, SocketState state, const u8* data, int len, void* userData) {
nobukuma 0:003889bc474f 253 const u8 connack[] = { 0xbe, 0xef, 8, 'C','O','N','N','_','A','C','K', 0x11};
nobukuma 0:003889bc474f 254 printf("Echo: socket %d, state %d, len=%d\n", socket, state, len);
nobukuma 0:003889bc474f 255 if (state==SocketState_Open) {
nobukuma 0:003889bc474f 256 if (len == 0) {
nobukuma 0:003889bc474f 257 printf("Sending CONN_ACK\n");
nobukuma 0:003889bc474f 258 Socket_Send(socket, connack, sizeof(connack));
nobukuma 0:003889bc474f 259 } else {
nobukuma 2:9f25a7fa1a54 260 printf("echo back: len=%d, data[0]=%x\n", len, data[0]);
nobukuma 2:9f25a7fa1a54 261 Socket_Send(socket, data, len); // uncomment
nobukuma 0:003889bc474f 262 printfBytes("echo:", data, len);
nobukuma 0:003889bc474f 263 }
nobukuma 0:003889bc474f 264 }
nobukuma 0:003889bc474f 265 }
nobukuma 0:003889bc474f 266
nobukuma 0:003889bc474f 267 void TestShell() {
nobukuma 0:003889bc474f 268 int n=0;
nobukuma 0:003889bc474f 269 USBInit();
nobukuma 0:003889bc474f 270 for (;;) {
nobukuma 0:003889bc474f 271 switch (state) {
nobukuma 0:003889bc474f 272 case 0: //inquiry and low-level connection
nobukuma 0:003889bc474f 273 break;
nobukuma 0:003889bc474f 274 case 1: {//initialisation
nobukuma 0:003889bc474f 275 printf("Ready to open ports\n");
nobukuma 0:003889bc474f 276 InitFtBtDeviceList();
nobukuma 0:003889bc474f 277 int n = GetNrOfFtBtDevices();
nobukuma 0:003889bc474f 278 printf("%d ft BT devices have been found\n", n);
nobukuma 0:003889bc474f 279 if (n > 0) {
nobukuma 0:003889bc474f 280 ftbtdev *d = GetFtUsbDeviceHandle(0);
nobukuma 0:003889bc474f 281 if (d==0) printf("could not get device handle\n");
nobukuma 0:003889bc474f 282 int sock = OpenFtBtDevice(d);
nobukuma 0:003889bc474f 283 }
nobukuma 0:003889bc474f 284 state = 2;
nobukuma 2:9f25a7fa1a54 285 comm = Socket_Listen(SOCKET_RFCOM, 1, echo, 0); // uncomment
nobukuma 0:003889bc474f 286 //incoming = new btserial(1);
nobukuma 0:003889bc474f 287 }
nobukuma 0:003889bc474f 288 break;
nobukuma 0:003889bc474f 289 case 2://main loop
nobukuma 2:9f25a7fa1a54 290 /*if (incoming->readable()>0){
nobukuma 0:003889bc474f 291 int c= incoming->getc();
nobukuma 0:003889bc474f 292 putc(c, stderr);
nobukuma 0:003889bc474f 293 incoming->putc(c);
nobukuma 0:003889bc474f 294 }
nobukuma 2:9f25a7fa1a54 295 else if (incoming->readable()<0){
nobukuma 0:003889bc474f 296 state = 3;
nobukuma 0:003889bc474f 297 printf("end of session");
nobukuma 0:003889bc474f 298 delete incoming;
nobukuma 0:003889bc474f 299 }*/
nobukuma 0:003889bc474f 300 break;
nobukuma 0:003889bc474f 301 default:
nobukuma 0:003889bc474f 302 break;
nobukuma 0:003889bc474f 303 }
nobukuma 0:003889bc474f 304 loop=1;
nobukuma 0:003889bc474f 305 USBLoop();
nobukuma 0:003889bc474f 306 loop=0;
nobukuma 0:003889bc474f 307 n++;
nobukuma 0:003889bc474f 308 if (n>=500000) {
nobukuma 0:003889bc474f 309 n=0;
nobukuma 0:003889bc474f 310 led = !led;
nobukuma 0:003889bc474f 311 }
nobukuma 0:003889bc474f 312 }
nobukuma 0:003889bc474f 313 //printf("Dropped out of main loop!\n");
nobukuma 0:003889bc474f 314 }
nobukuma 0:003889bc474f 315
nobukuma 0:003889bc474f 316 //********************************************************************************************************************************