c++/lpt-signal-generator/lpt.cpp
changeset 52 6b5c6a26693f
parent 51 514b9b433dc2
child 53 516358e07f9d
     1.1 --- a/c++/lpt-signal-generator/lpt.cpp	Sun Jun 11 13:07:53 2017 +0200
     1.2 +++ b/c++/lpt-signal-generator/lpt.cpp	Sun Jun 11 13:11:58 2017 +0200
     1.3 @@ -51,121 +51,121 @@
     1.4   * mode info: https://blog.frantovo.cz/c/358/Paraleln%C3%AD%20port%20jako%20gener%C3%A1tor%20sign%C3%A1lu
     1.5   */
     1.6  int main() {
     1.7 -  //cout << "LPT!" << endl; // same as using printf → breaks all folllowing wprintf() calls, see note above
     1.8 +	//cout << "LPT!" << endl; // same as using printf → breaks all folllowing wprintf() calls, see note above
     1.9  
    1.10 -  /*
    1.11 -   * if setlocale() is missing, unicode characters are replaced with ? or „→“ with „->“ because C/POSIX locale is used, 
    1.12 -   * see man setlocale:
    1.13 -   * > On startup of the main program, the portable "C" locale is selected as default.
    1.14 -   * > If locale is an empty string, "", each part of the locale that should be modified is set according to the environment variables.
    1.15 -   */
    1.16 -  setlocale(LC_ALL,"");
    1.17 +	/*
    1.18 +	 * if setlocale() is missing, unicode characters are replaced with ? or „→“ with „->“ because C/POSIX locale is used, 
    1.19 +	 * see man setlocale:
    1.20 +	 * > On startup of the main program, the portable "C" locale is selected as default.
    1.21 +	 * > If locale is an empty string, "", each part of the locale that should be modified is set according to the environment variables.
    1.22 +	 */
    1.23 +	setlocale(LC_ALL,"");
    1.24  
    1.25  
    1.26 -  // configuration ----
    1.27 -  int addr = 0xe400; // parallel port address; first number of given port in: cat /proc/ioports | grep parport
    1.28 -  int baseFreq = 10000; // base frequency in Hz, should be between 5 000 between 10 000 Hz; lower frequency leads to dashed/dotted lines instead of greyscale
    1.29 -  int outputPower = 20; // duty cycle; 100 = 100 %
    1.30 -  int duration = 1; // in seconds; total sleep time, see note above
    1.31 -  // ------------------
    1.32 +	// configuration ----
    1.33 +	int addr = 0xe400; // parallel port address; first number of given port in: cat /proc/ioports | grep parport
    1.34 +	int baseFreq = 10000; // base frequency in Hz, should be between 5 000 between 10 000 Hz; lower frequency leads to dashed/dotted lines instead of greyscale
    1.35 +	int outputPower = 20; // duty cycle; 100 = 100 %
    1.36 +	int duration = 1; // in seconds; total sleep time, see note above
    1.37 +	// ------------------
    1.38  
    1.39  
    1.40 -  int valueWidth =  10; // just for padding of printed values
    1.41 -  int labelWidth = -15; // just for padding of printed labels
    1.42 +	int valueWidth =  10; // just for padding of printed values
    1.43 +	int labelWidth = -15; // just for padding of printed labels
    1.44  
    1.45 -  // ' = thousand separator
    1.46 -  // * = padding
    1.47 -  wprintf(L"%*ls %*x\n", labelWidth, L"Parallel port:", valueWidth, addr); // or %#*x – adds 0x prefix
    1.48 -  wprintf(L"%*ls %'*d Hz\n", labelWidth, L"Base frequency:", valueWidth, baseFreq);
    1.49 -  wprintf(L"%*ls %*d %% duty cycle\n",  labelWidth, L"Output power:", valueWidth, outputPower);
    1.50 -  wprintf(L"%*ls %'*d s\n", labelWidth, L"Duration:", valueWidth, duration);
    1.51 +	// ' = thousand separator
    1.52 +	// * = padding
    1.53 +	wprintf(L"%*ls %*x\n", labelWidth, L"Parallel port:", valueWidth, addr); // or %#*x – adds 0x prefix
    1.54 +	wprintf(L"%*ls %'*d Hz\n", labelWidth, L"Base frequency:", valueWidth, baseFreq);
    1.55 +	wprintf(L"%*ls %*d %% duty cycle\n",  labelWidth, L"Output power:", valueWidth, outputPower);
    1.56 +	wprintf(L"%*ls %'*d s\n", labelWidth, L"Duration:", valueWidth, duration);
    1.57  
    1.58 -  // in microseconds:
    1.59 -  auto oneSecond = 1000 * 1000;
    1.60 -  auto timeOn =  oneSecond *        outputPower  / 100 / baseFreq;
    1.61 -  auto timeOff = oneSecond * (100 - outputPower) / 100 / baseFreq;
    1.62 +	// in microseconds:
    1.63 +	auto oneSecond = 1000 * 1000;
    1.64 +	auto timeOn =  oneSecond *        outputPower  / 100 / baseFreq;
    1.65 +	auto timeOff = oneSecond * (100 - outputPower) / 100 / baseFreq;
    1.66  
    1.67 -  auto cycleCount = duration * baseFreq;
    1.68 -  wprintf(L"%*ls %'*d ×\n", labelWidth, L"Cycle count:", valueWidth, cycleCount);
    1.69 -  wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Time on:",  valueWidth, timeOn);
    1.70 -  wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Time off:", valueWidth, timeOff);
    1.71 +	auto cycleCount = duration * baseFreq;
    1.72 +	wprintf(L"%*ls %'*d ×\n", labelWidth, L"Cycle count:", valueWidth, cycleCount);
    1.73 +	wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Time on:",  valueWidth, timeOn);
    1.74 +	wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Time off:", valueWidth, timeOff);
    1.75  
    1.76 -  //wprintf(L"%*ls %*ls\n", labelWidth, L"unicode test:", valueWidth, L"čeština → …");
    1.77 +	//wprintf(L"%*ls %*ls\n", labelWidth, L"unicode test:", valueWidth, L"čeština → …");
    1.78  
    1.79 -  wprintf(L"\n");
    1.80 +	wprintf(L"\n");
    1.81  
    1.82 -  // TODO: test whether this address is an parallel port
    1.83 -  if (ioperm(addr,1,1)) { fwprintf(stderr, L"Access denied to port %#x\n", addr), exit(1); }
    1.84 +	// TODO: test whether this address is an parallel port
    1.85 +	if (ioperm(addr,1,1)) { fwprintf(stderr, L"Access denied to port %#x\n", addr), exit(1); }
    1.86  
    1.87  
    1.88 -  // calibration
    1.89 -  auto startTimestamp = chrono::high_resolution_clock::now();
    1.90 -  auto calibrationCycles = 10000;
    1.91 -  auto calibrationSleepTime = 10;
    1.92 +	// calibration
    1.93 +	auto startTimestamp = chrono::high_resolution_clock::now();
    1.94 +	auto calibrationCycles = 10000;
    1.95 +	auto calibrationSleepTime = 10;
    1.96  
    1.97 -  for (auto i = calibrationCycles; i > 0; i--) {
    1.98 -    outb(0b00000000, addr);
    1.99 -    usleep(calibrationSleepTime);
   1.100 -    outb(0b00000000, addr);
   1.101 -    usleep(calibrationSleepTime);
   1.102 -  }
   1.103 +	for (auto i = calibrationCycles; i > 0; i--) {
   1.104 +		outb(0b00000000, addr);
   1.105 +		usleep(calibrationSleepTime);
   1.106 +		outb(0b00000000, addr);
   1.107 +		usleep(calibrationSleepTime);
   1.108 +	}
   1.109  
   1.110 -  auto finishTimestamp = chrono::high_resolution_clock::now();
   1.111 -  auto measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
   1.112 +	auto finishTimestamp = chrono::high_resolution_clock::now();
   1.113 +	auto measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
   1.114  
   1.115 -  auto singleOutbCostNano = (measuredDuration - calibrationCycles*2*calibrationSleepTime*1000)/calibrationCycles/2;
   1.116 -  auto singleOutbCostMicro = singleOutbCostNano/1000;
   1.117 +	auto singleOutbCostNano = (measuredDuration - calibrationCycles*2*calibrationSleepTime*1000)/calibrationCycles/2;
   1.118 +	auto singleOutbCostMicro = singleOutbCostNano/1000;
   1.119  
   1.120 -  wprintf(L"%*ls %'*d μs 2× in each calibration cycle\n", labelWidth, L"Single outb():", valueWidth, singleOutbCostMicro);
   1.121 -  wprintf(L"%*ls %'*d ns 2× in each calibration cycle\n", labelWidth, L"Single outb():", valueWidth, singleOutbCostNano);
   1.122 +	wprintf(L"%*ls %'*d μs 2× in each calibration cycle\n", labelWidth, L"Single outb():", valueWidth, singleOutbCostMicro);
   1.123 +	wprintf(L"%*ls %'*d ns 2× in each calibration cycle\n", labelWidth, L"Single outb():", valueWidth, singleOutbCostNano);
   1.124  
   1.125 -  auto minPower = 100*singleOutbCostNano/(1000*1000*1000/baseFreq);
   1.126 -  auto maxPower = 100-minPower;
   1.127 -  wprintf(L"%*ls %*d %% feasible duty cycle\n",  labelWidth, L"Minimum power:", valueWidth, minPower);
   1.128 -  wprintf(L"%*ls %*d %% feasible duty cycle\n",  labelWidth, L"Maximum power:", valueWidth, maxPower);
   1.129 +	auto minPower = 100*singleOutbCostNano/(1000*1000*1000/baseFreq);
   1.130 +	auto maxPower = 100-minPower;
   1.131 +	wprintf(L"%*ls %*d %% feasible duty cycle\n",  labelWidth, L"Minimum power:", valueWidth, minPower);
   1.132 +	wprintf(L"%*ls %*d %% feasible duty cycle\n",  labelWidth, L"Maximum power:", valueWidth, maxPower);
   1.133  
   1.134 -  if (singleOutbCostMicro < timeOn && singleOutbCostMicro < timeOff) {
   1.135 -    wprintf(L"%*ls %*ls both frequency and duty cycle should be correct\n",  labelWidth, L"Calibration:", valueWidth, L"OK");
   1.136 -    timeOn  -= singleOutbCostMicro;
   1.137 -    timeOff -= singleOutbCostMicro;
   1.138 -  } else if (2*singleOutbCostMicro < (timeOn + timeOff)) {
   1.139 -    wprintf(L"%*ls %*ls frequency should be OK, but duty cycle is not feasible\n",  labelWidth, L"Calibration:", valueWidth, L"WARNING");
   1.140 -    timeOn  -= singleOutbCostMicro;
   1.141 -    timeOff -= singleOutbCostMicro;
   1.142 +	if (singleOutbCostMicro < timeOn && singleOutbCostMicro < timeOff) {
   1.143 +		wprintf(L"%*ls %*ls both frequency and duty cycle should be correct\n",  labelWidth, L"Calibration:", valueWidth, L"OK");
   1.144 +		timeOn  -= singleOutbCostMicro;
   1.145 +		timeOff -= singleOutbCostMicro;
   1.146 +	} else if (2*singleOutbCostMicro < (timeOn + timeOff)) {
   1.147 +		wprintf(L"%*ls %*ls frequency should be OK, but duty cycle is not feasible\n",  labelWidth, L"Calibration:", valueWidth, L"WARNING");
   1.148 +		timeOn  -= singleOutbCostMicro;
   1.149 +		timeOff -= singleOutbCostMicro;
   1.150  
   1.151 -    if (timeOn < 0) {
   1.152 -      timeOff -= timeOn;
   1.153 -      timeOn = 0;
   1.154 -    } else {
   1.155 -      timeOn -= timeOff;
   1.156 -      timeOff = 0;
   1.157 -    }
   1.158 -  } else {
   1.159 -    wprintf(L"%*ls %*ls both frequency and duty cycle are not feasible\n",  labelWidth, L"Calibration:", valueWidth, L"ERROR");
   1.160 -    timeOn  = 0;
   1.161 -    timeOff = 0;
   1.162 -  }
   1.163 +		if (timeOn < 0) {
   1.164 +			timeOff -= timeOn;
   1.165 +			timeOn = 0;
   1.166 +		} else {
   1.167 +			timeOn -= timeOff;
   1.168 +			timeOff = 0;
   1.169 +		}
   1.170 +	} else {
   1.171 +		wprintf(L"%*ls %*ls both frequency and duty cycle are not feasible\n",  labelWidth, L"Calibration:", valueWidth, L"ERROR");
   1.172 +		timeOn  = 0;
   1.173 +		timeOff = 0;
   1.174 +	}
   1.175  
   1.176 -  wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Sleep on:",  valueWidth, timeOn);
   1.177 -  wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Sleep off:", valueWidth, timeOff);
   1.178 +	wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Sleep on:",  valueWidth, timeOn);
   1.179 +	wprintf(L"%*ls %'*d μs 1× in each cycle\n", labelWidth, L"Sleep off:", valueWidth, timeOff);
   1.180  
   1.181 -  wprintf(L"\n");
   1.182 +	wprintf(L"\n");
   1.183  
   1.184  
   1.185 -  // actual signal generation
   1.186 -  startTimestamp = chrono::high_resolution_clock::now();
   1.187 +	// actual signal generation
   1.188 +	startTimestamp = chrono::high_resolution_clock::now();
   1.189  
   1.190 -  for (auto i = cycleCount; i > 0;  i--) {
   1.191 -    outb(0b00000001, addr); // first data out pin = data out 0 = pin 2 on DB-25 connector
   1.192 -    usleep(timeOn);
   1.193 -    outb(0b00000000, addr);
   1.194 -    usleep(timeOff);
   1.195 -  }
   1.196 +	for (auto i = cycleCount; i > 0;  i--) {
   1.197 +		outb(0b00000001, addr); // first data out pin = data out 0 = pin 2 on DB-25 connector
   1.198 +		usleep(timeOn);
   1.199 +		outb(0b00000000, addr);
   1.200 +		usleep(timeOff);
   1.201 +	}
   1.202  
   1.203 -  finishTimestamp = chrono::high_resolution_clock::now();
   1.204 -  measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
   1.205 +	finishTimestamp = chrono::high_resolution_clock::now();
   1.206 +	measuredDuration = chrono::duration_cast<chrono::nanoseconds>(finishTimestamp - startTimestamp).count();
   1.207  
   1.208 -  wprintf(L"%*ls %'*d μs in total\n", labelWidth, L"Deviation:", valueWidth, (measuredDuration-duration*oneSecond*1000)/1000);
   1.209 -  wprintf(L"%*ls %'*d ns in each cycle\n", labelWidth, L"Deviation:", valueWidth, (measuredDuration-duration*oneSecond*1000)/cycleCount);
   1.210 +	wprintf(L"%*ls %'*d μs in total\n", labelWidth, L"Deviation:", valueWidth, (measuredDuration-duration*oneSecond*1000)/1000);
   1.211 +	wprintf(L"%*ls %'*d ns in each cycle\n", labelWidth, L"Deviation:", valueWidth, (measuredDuration-duration*oneSecond*1000)/cycleCount);
   1.212  
   1.213  }