void writePacket() { /* * This is one way to write packets to the UsbPipe; using reserve() * and commit(). If you already have a buffer that you want to copy to the * UsbPipe, you can use write(). */ if (Usb::isConnected() && usbPipe.writeAvailable()) { /* * Access some buffer space for writing the next packet. This * is the zero-copy API for writing packets. Both reading and writing * have a traditional (one copy) API and a zero-copy API. */ UsbPacket &packet = usbPipe.sendQueue.reserve(); /* * Fill most of the packet with dummy data */ // 28-bit type code, for our own application's use packet.setType(0x5A); packet.resize(packet.capacity()); for (unsigned i = 0; i < packet.capacity(); ++i) { packet.bytes()[i] = 'a' + i; } /* * Fill the first 3 bytes with accelerometer data from Cube 0 */ Byte3 accel = vid.physicalAccel(); packet.bytes()[0] = accel.x; packet.bytes()[1] = accel.y; packet.bytes()[2] = accel.z; /* * Log the packet for debugging, and commit it to the FIFO. * The system will asynchronously send it to our peer. */ LOG("Sending: %d bytes, type=%02x, data=%19h\n", packet.size(), packet.type(), packet.bytes()); usbPipe.sendQueue.commit(); updatePacketCounts(1, 0); } }
void readPacket() { /* * This is one way to read packets from the BluetoothPipe; using read(), * and copying them into our own buffer. A faster but slightly more complex * method would use peek() to access the next packet, and pop() to remove it. * * We only attempt to read n packets to avoid the edge case in which packets * are arriving often enough to keep us in this loop indefinitely. Not likely * a concern for real applications, but keeps things flowing smoothly for * this example. */ UsbPacket packet; unsigned n = usbPipe.receiveQueue.capacity(); while (n && usbPipe.read(packet)) { n--; /* * We received a packet over USB! * Dump out its contents in hexadecimal, to the log and the display. */ LOG("Received: %d bytes, type=%02x, data=%19h\n", packet.size(), packet.type(), packet.bytes()); String<17> str; str << "len=" << Hex(packet.size(), 2) << " type=" << Hex(packet.type(), 2); vid.bg0rom.text(vec(1,10), str); packetHexDumpLine(packet, str, 0); vid.bg0rom.text(vec(0,12), str); packetHexDumpLine(packet, str, 8); vid.bg0rom.text(vec(0,13), str); packetHexDumpLine(packet, str, 16); vid.bg0rom.text(vec(0,14), str); // Update our counters updatePacketCounts(0, 1); } }
void WritePacket(int type, int packetLength, unsigned char* bytes) { /* * This is one way to write packets to the UsbPipe; using reserve() * and commit(). If you already have a buffer that you want to copy to the * UsbPipe, you can use write(). */ if (Usb::isConnected() && usbPipe.writeAvailable()) { /* * Access some buffer space for writing the next packet. This * is the zero-copy API for writing packets. Both reading and writing * have a traditional (one copy) API and a zero-copy API. */ UsbPacket &packet = usbPipe.sendQueue.reserve(); /* * Fill most of the packet with dummy data */ // 28-bit type code, for our own application's use // packet.setType(0x5); packet.setType(type); packet.resize(packet.capacity()); unsigned i; for (i = 0; i<packetLength; i++) packet.bytes()[i] = bytes[i]; for (; i < packet.capacity(); ++i) { packet.bytes()[i] = 0; } /* * Log the packet for debugging, and commit it to the FIFO. * The system will asynchronously send it to our peer. */ usbPipe.sendQueue.commit(); } }
void main() { /* * Display text in BG0_ROM mode on Cube 0 */ CubeID cube = 0; vid.initMode(BG0_ROM); vid.attach(cube); vid.bg0rom.text(vec(0,0), " USB Demo ", vid.bg0rom.WHITE_ON_TEAL); // Zero out our counters usbCounters.reset(); /* * When we transmit packets in this example, we'll fill them with our * cube's accelerometer state. When we receive packets, they'll * be hex-dumped to the screen. We also keep counters that show how many * packets have been processed. * * If possible, applications are encouraged to use event handlers so that * they only try to read packets when packets are available, and they only * write packets when buffer space is available. In this example, we always * want to read packets when they arrive, so we keep an onRead() handler * registered at all times. We also want to write as long as there's buffer * space, but only when a peer is connected. So we'll register and unregister * our onWrite() handler in onConnect() and onDisconnect(), respectively. * * Note that attach() will empty our transmit and receive queues. If we want * to enqueue write packets in onConnct(), we need to be sure the pipe is * attached before we set up onConnect/onDisconnect. */ Events::usbReadAvailable.set(onReadAvailable); usbPipe.attach(); updatePacketCounts(0, 0); /* * Watch for incoming connections, and display some text on the screen to * indicate connection state. */ Events::usbConnect.set(onConnect); Events::usbDisconnect.set(onDisconnect); if (Usb::isConnected()) { onConnect(); } else { onDisconnect(); } /* * Everything else happens in event handlers, nothing to do in our main loop. */ while (1) { for (unsigned n = 0; n < 60; n++) { readPacket(); writePacket(); System::paint(); } /* * For debugging, periodically log the USB packet counters. */ usbCounters.capture(); LOG("USB-Counters: rxPackets=%d txPackets=%d rxBytes=%d txBytes=%d rxUserDropped=%d\n", usbCounters.receivedPackets(), usbCounters.sentPackets(), usbCounters.receivedBytes(), usbCounters.sentBytes(), usbCounters.userPacketsDropped()); } }
void ReadPacket() { UsbPacket packet; while (usbPipe.read(packet)) { unsigned char *message = packet.bytes(); switch (message[0]) { case 1: //update bound variables/values (param, minValue, maxValue, bar_idx, local/remote) { //the format for the message is cube, length of parameter, parameter, minValue (length of 3), maxValue (length of 3), bar_idx, local/remote unsigned idCube = message[1]; char *newVal; Val[idCube][0] = message[3]+'0'; Val[idCube][1] = '.'; Val[idCube][2] = message[5]+'0'; update[idCube] = true; break; } case 2: //update the binding data- who is it bound to { //the message format is cubeId,length of param , element type, name, concentration/speed value unsigned idCube = message[1]; boundTo[idCube] = message[3]; Val[idCube][0] = message[4]+'0'; Val[idCube][1] = '.'; Val[idCube][2] = message[5]+'0'; update[idCube] = true; break; } case 3: //update the concentration/speed value has changed { //the mesage format is cube, local or remote unsigned idCube = message[1]; Val[idCube][0] = message[3]+'0'; Val[idCube][1] = '.'; Val[idCube][2] = message[5]+'0'; update[idCube] = true; break; } case 4: // to unbind the cube { unsigned idCube = message[1]; boundTo[idCube] = 0; update[idCube] = true; break; } case 5: //to change the state of the cube { unsigned idCube = message[1]; state[idCube]=message[3]; update[idCube] = true; break; } } } }
void main() { static EventSensor event; event.install(); //add motion detection //SendInitialData(); for (int i = 0; i < NUM_CUBES; i++) { CubeID cube(i); uint64_t hwid = cube.hwID(); LOG("Cube %d connected\n", i); vbuf[i].attach(i); vbuf[i].initMode(BG0_SPR_BG1); vbuf[i].bg0.image(vec(0,0), Data); motion[i].attach(i); //drawing to bg1 //vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,4), vec(12,3)))); //for the text //init to SQFT /* param[i][0] = 'S'; param[i][1] = 'Q'; param[i][2] = 'F'; param[i][3] = 'T'; */ minVal[i][0] = ' '; minVal[i][1] = '0'; minVal[i][2] = ' '; maxVal[i][0] = '0'; maxVal[i][1] = '.'; maxVal[i][2] = '1'; Val[i][0] = '0'; Val[i][1] = '.'; Val[i][2] = '0'; //add numbers for status bar vbuf[i].bg1.text(vec(2,4), Font, Val[i]); update[i] = false; } //needed to actually use usb pipe usbPipe.attach(); //register with event Events::usbReadAvailable.set(&ReadPacket); SendInitialData(); // run loop while(1) { //iterate through the cubes to determine if they need updated for (int i = 0; i < NUM_CUBES; i++) { if (update[i]) { vbuf[i].bg0.erase(); vbuf[i].bg1.erase(); //show the background depending on what it is bound to /*if(boundTo[i]==0){ //not bound to anything //not tilted vbuf[i].bg0.image(vec(0,0), Molecule_select); if(tilt[i].x==1){ vbuf[i].bg0.image(vec(0,0), Molecule_select); }else vbuf[i].bg0.image(vec(0,0), Enzyme_select); }else if(boundTo[i]==1){ //bound to a molecule vbuf[i].bg0.image(vec(0,0), Molecule_bound_bckg); //define the space vbuf[i].bg1.setMask((BG1Mask::filled(vec(5,5), vec(10,3)))); //for the name vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration //write vbuf[i].bg1.text(vec(5,5), Font, "M"); vbuf[i].bg1.text(vec(2,9), Font, Val[i]); }else if(boundTo[i]==2){ //bound to an enzyme vbuf[i].bg0.image(vec(0,0), Enzyme_bound_bckg); vbuf[i].bg1.setMask((BG1Mask::filled(vec(5,5), vec(10,3)))); //for the name vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration vbuf[i].bg1.text(vec(5,5), Font, "E"); vbuf[i].bg1.text(vec(2,9), Font, Val[i]); }else { //bound to a reaction vbuf[i].bg0.image(vec(0,0), Reaction_bckg); vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,4), vec(10,3)))); //for the reaction constant vbuf[i].bg1.text(vec(2,4), Font, Val[i]); }*/ switch(state[i]){ case 0: // Data vbuf[i].bg0.image(vec(0,0), Data); break; case 1: //Model vbuf[i].bg0.image(vec(0,0), Model); break; case 2: //CSV vbuf[i].bg0.image(vec(0,0), CSV); break; case 3: //RMS vbuf[i].bg0.image(vec(0,0), RMS); break; case 4: //Molecule vbuf[i].bg0.image(vec(0,0), Molecule); break; case 5: //Enzyme vbuf[i].bg0.image(vec(0,0), Enzyme); break; case 6: //MolOverview vbuf[i].bg0.image(vec(0,0), MolOverview); vbuf[i].bg1.setMask((BG1Mask::filled(vec(5,5), vec(10,3)))); //for the name vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration //write vbuf[i].bg1.text(vec(5,5), Font, "M"); vbuf[i].bg1.text(vec(2,9), Font, Val[i]); break; case 7: //MolConc vbuf[i].bg0.image(vec(0,0), MolConc); break; case 8: //MolGraph vbuf[i].bg0.image(vec(0,0), MolGraph); break; case 9: //MolEquation vbuf[i].bg0.image(vec(0,0), MolEquation); break; case 10: //EnzOverview vbuf[i].bg0.image(vec(0,0), EnzOverview); vbuf[i].bg1.setMask((BG1Mask::filled(vec(5,5), vec(10,3)))); //for the name vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration vbuf[i].bg1.text(vec(5,5), Font, "E"); vbuf[i].bg1.text(vec(2,9), Font, Val[i]); break; case 11: //EnzConc vbuf[i].bg0.image(vec(0,0), EnzConc); break; case 12: //RctOverview vbuf[i].bg0.image(vec(0,0), RctOverview); vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration vbuf[i].bg1.text(vec(2,9), Font, Val[i]); break; case 13: //RctRate vbuf[i].bg0.image(vec(0,0), RctRate); break; case 14: //MolConcSelected vbuf[i].bg0.image(vec(0,0), MolConcSelected); vbuf[i].bg1.setMask((BG1Mask::filled(vec(5,5), vec(10,3)))); //for the name vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration //write vbuf[i].bg1.text(vec(5,5), Font, "M"); vbuf[i].bg1.text(vec(2,9), Font, Val[i]); break; case 15: //EnzConcSelected vbuf[i].bg0.image(vec(0,0), EnzConcSelected); vbuf[i].bg1.setMask((BG1Mask::filled(vec(5,5), vec(10,3)))); //for the name vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,9), vec(12,3)))); //for the concentration vbuf[i].bg1.text(vec(5,5), Font, "E"); vbuf[i].bg1.text(vec(2,9), Font, Val[i]); break; case 16: //RctRateSelected vbuf[i].bg0.image(vec(0,0), RctRateSelected); vbuf[i].bg1.setMask((BG1Mask::filled(vec(2,4), vec(10,3)))); //for the reaction constant vbuf[i].bg1.text(vec(2,4), Font, Val[i]); break; case 17://Direction vbuf[i].bg0.image(vec(0,0), Direction); break; case 18: //selectCSV vbuf[i].bg0.image(vec(0,0), SelectCSV); break; case 19: //Play the simulation vbuf[i].bg0.image(vec(0,0), Play); break; case 20: //Stop Simulation vbuf[i].bg0.image(vec(0,0), Stop); break; case 21: //Quit Pathways vbuf[i].bg0.image(vec(0,0), Quit); break; case 22: //Reaction vbuf[i].bg0.image(vec(0,0), Reaction); break; } update[i] = false; } } System::paint(); } }