/**
* BlueCove - Java library for Bluetooth
* Copyright (C) 2006-2009 Vlad Skarzhevskyy
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
* @author vlads
* @version $Id$
*/
package net.sf.bluecove.tests;
import java.io.IOException;
import org.bluecove.tester.log.Logger;
import org.bluecove.tester.util.IOUtils;
import org.bluecove.tester.util.RuntimeDetect;
import org.bluecove.tester.util.TimeUtils;
import net.sf.bluecove.CommunicationTesterL2CAP;
import net.sf.bluecove.Configuration;
import net.sf.bluecove.ConnectionHolderL2CAP;
import net.sf.bluecove.TestStatus;
import net.sf.bluecove.util.TimeStatistic;
/**
*
*
*/
public class L2TrafficGenerator {
static final int sequenceSizeMin = 16;
private static class Config {
int sequenceSleep = 0;
int sequenceSize = 0;
int durationMSec = 0;
boolean init(byte[] initialData, boolean server, String messagePrefix) throws IOException {
if (server) {
if (initialData != null) {
if (initialData.length >= 1) {
sequenceSleep = IOUtils.byteToUnsignedInt(initialData[0]);
}
if (initialData.length >= 2) {
sequenceSize = IOUtils.byteToUnsignedInt(initialData[1]);
}
if (initialData.length >= 3) {
durationMSec = IOUtils.byteToUnsignedInt(initialData[2]);
}
}
} else {
sequenceSize = Configuration.tgSize & 0xFF;
sequenceSleep = Configuration.tgSleep & 0xFF;
durationMSec = Configuration.tgDurationMin;
}
sequenceSleep = sequenceSleep * 10;
if (sequenceSize < sequenceSizeMin) {
sequenceSize = sequenceSizeMin;
}
switch (sequenceSize) {
case 251:
// 1K
sequenceSize = 0x400;
break;
case 252:
// 2K
sequenceSize = 0x800;
break;
case 253:
// 3K
sequenceSize = 0xC00;
break;
case 254:
// 4K
sequenceSize = 0x1000;
break;
case 255:
// 5K
sequenceSize = 0x1400;
break;
}
Logger.debug(messagePrefix + " size selected " + sequenceSize + " byte");
Logger.debug(messagePrefix + " duration " + durationMSec + " minutes");
durationMSec *= 60000;
return true;
}
}
public static void trafficGeneratorClientInit(ConnectionHolderL2CAP c, int testType) throws IOException {
byte sequenceSleep = (byte) (Configuration.tgSleep & 0xFF);
byte sequenceSize = (byte) (Configuration.tgSize & 0xFF);
byte durationMin = (byte) (Configuration.tgDurationMin & 0xFF);
c.channel.send(CommunicationTesterL2CAP.startPrefix(testType, new byte[] { sequenceSleep, sequenceSize,
durationMin }));
}
public static void trafficGeneratorWrite(ConnectionHolderL2CAP c, byte[] initialData, boolean server,
final TestStatus testStatus) throws IOException {
Config cf = new Config();
if (!cf.init(initialData, server, "L2 write")) {
return;
}
if (cf.sequenceSleep > 0) {
Logger.debug("write sleep selected " + cf.sequenceSleep + " msec");
} else {
Logger.debug("write no sleep");
}
int transmitMTU = c.channel.getTransmitMTU();
if (transmitMTU < cf.sequenceSize) {
Logger.warn("L2 write size " + cf.sequenceSize + " is greater then MTU " + transmitMTU);
cf.sequenceSize = transmitMTU;
}
long sequenceSentCount = 0;
int reportedSize = 0;
// Create test data
byte[] data = new byte[cf.sequenceSize];
for (int i = 1; i < cf.sequenceSize; i++) {
data[i] = (byte) i;
}
long start = System.currentTimeMillis();
long reported = start;
try {
mainLoop: do {
IOUtils.long2Bytes(sequenceSentCount, 8, data, 0);
long sendTime = System.currentTimeMillis();
IOUtils.long2Bytes(sendTime, 8, data, 8);
c.channel.send(data);
sequenceSentCount++;
reportedSize += cf.sequenceSize;
c.active();
long now = System.currentTimeMillis();
if (now - reported > 5 * 1000) {
Logger
.debug("L2 Sent " + sequenceSentCount + " packet(s) "
+ TimeUtils.bps(reportedSize, reported));
reported = now;
reportedSize = 0;
}
if ((cf.durationMSec != 0) && (now > start + cf.durationMSec)) {
break;
}
if (cf.sequenceSleep > 0) {
try {
Thread.sleep(cf.sequenceSleep);
} catch (InterruptedException e) {
break mainLoop;
}
c.active();
}
} while (c.isConnectionOpen() && (!testStatus.isRunCompleate()));
} finally {
testStatus.setRunCompleate();
Logger.debug("L2 Total " + sequenceSentCount + " packet(s)");
Logger.debug("L2 Total write speed " + TimeUtils.bps(sequenceSentCount * cf.sequenceSize, start));
}
}
public static void trafficGeneratorStatusReadStart(final ConnectionHolderL2CAP c, final TestStatus testStatus) {
Runnable r = new Runnable() {
public void run() {
try {
trafficGeneratorStatusRead(c, testStatus);
} catch (IOException e) {
Logger.error("reader", e);
}
}
};
Thread t = RuntimeDetect.cldcStub.createNamedThread(r, "L2tgStatusReciver");
t.start();
}
public static void trafficGeneratorStatusRead(ConnectionHolderL2CAP c, final TestStatus testStatus)
throws IOException {
try {
int receiveMTU = c.channel.getReceiveMTU();
byte[] dataReceived = new byte[receiveMTU];
mainLoop: do {
if (!c.channel.ready()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
break mainLoop;
}
} else {
c.channel.receive(dataReceived);
c.active();
}
} while (c.isConnectionOpen() && (!testStatus.isRunCompleate()));
} finally {
testStatus.setRunCompleate();
}
}
public static void trafficGeneratorReadStart(final ConnectionHolderL2CAP c, final byte[] initialData,
final TestStatus testStatus) {
Runnable r = new Runnable() {
public void run() {
try {
trafficGeneratorRead(c, initialData, testStatus);
} catch (IOException e) {
Logger.error("reader", e);
}
}
};
Thread t = RuntimeDetect.cldcStub.createNamedThread(r, "L2tgReciver");
t.start();
}
public static void trafficGeneratorRead(ConnectionHolderL2CAP c, byte[] initialData, final TestStatus testStatus)
throws IOException {
long sequenceRecivedCount = 0;
long sequenceRecivedNumberLast = -1;
long sequenceOutOfOrderCount = 0;
TimeStatistic delay = new TimeStatistic();
long start = System.currentTimeMillis();
long reported = start;
long receiveTimeLast = 0;
long reportedSize = 0;
long totalSize = 0;
try {
int receiveMTU = c.channel.getReceiveMTU();
mainLoop: do {
if (!c.channel.ready()) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
break mainLoop;
}
continue;
}
byte[] dataReceived = new byte[receiveMTU];
int lengthdataReceived = c.channel.receive(dataReceived);
c.active();
long receiveTime = System.currentTimeMillis();
sequenceRecivedCount++;
long sendTime = 0;
reportedSize += lengthdataReceived;
totalSize += lengthdataReceived;
if (lengthdataReceived > 8) {
long sequenceRecivedNumber = IOUtils.bytes2Long(dataReceived, 0, 8);
if (sequenceRecivedNumberLast + 1 != sequenceRecivedNumber) {
sequenceOutOfOrderCount++;
} else if (lengthdataReceived > 18) {
sendTime = IOUtils.bytes2Long(dataReceived, 8, 8);
}
sequenceRecivedNumberLast = sequenceRecivedNumber;
} else {
sequenceOutOfOrderCount++;
}
if (receiveTimeLast != 0) {
delay.add(receiveTimeLast - receiveTime);
receiveTimeLast = receiveTime;
}
long now = receiveTime;
if (now - reported > 5 * 1000) {
Logger.debug("L2 Received " + sequenceRecivedCount + "/" + sequenceOutOfOrderCount
+ "(er) packet(s) " + delay.avg() + " msec");
Logger.debug("L2 Received " + TimeUtils.bps(reportedSize, reported));
reported = now;
reportedSize = 0;
}
} while (c.isConnectionOpen() && (!testStatus.isRunCompleate()));
} finally {
testStatus.setRunCompleate();
Logger.debug("L2 Total Received " + sequenceRecivedCount + " packet(s)");
Logger.debug("L2 Total Misplaced " + sequenceOutOfOrderCount + " packet(s)");
Logger.debug("L2 avg interval " + delay.avg() + " msec");
Logger.debug("L2 Total read speed " + TimeUtils.bps(totalSize, start));
}
}
}