Skip to content

Commit a26aa70

Browse files
authored
feat: added functionality for Wave Generator (#2826)
1 parent a79ee67 commit a26aa70

15 files changed

+1652
-322
lines changed

assets/icons/ic_pwm_pic.png

1.35 KB
Loading

assets/images/sin_wave_circuit.png

38.5 KB
Loading

assets/images/square_wave_circuit.png

5.11 KB
Loading

lib/communication/science_lab.dart

Lines changed: 277 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ class ScienceLab {
157157
for (String temp in ['CH1', 'CH2']) {
158158
await setGain(temp, 0, true);
159159
}
160-
for (String temp in ['SI1', 'SI1']) {
160+
for (String temp in ['SI1', 'SI2']) {
161161
await loadEquation(temp, 'sine');
162162
}
163163
}
@@ -1090,6 +1090,282 @@ class ScienceLab {
10901090
}
10911091
}
10921092

1093+
Future<double> setSI1(double frequency, String? waveType) async {
1094+
double freqLowLimit = 0.1;
1095+
int highRes, tableSize;
1096+
1097+
if (frequency < freqLowLimit) {
1098+
logger.e("frequency too low");
1099+
return -1;
1100+
} else if (frequency < 1100) {
1101+
highRes = 1;
1102+
tableSize = 512;
1103+
} else {
1104+
highRes = 0;
1105+
tableSize = 32;
1106+
}
1107+
1108+
if (waveType != null) {
1109+
if (waveType == "sine" || waveType == "tria") {
1110+
if (this.waveType["SI1"] != waveType) {
1111+
loadEquation("SI1", waveType);
1112+
}
1113+
} else {
1114+
logger.e("Not a valid waveform. try sine or tria");
1115+
}
1116+
}
1117+
1118+
List<int> p = [1, 8, 64, 256];
1119+
int prescalar = 0;
1120+
int wavelength = 0;
1121+
1122+
while (prescalar <= 3) {
1123+
wavelength = (64e6 ~/ frequency ~/ p[prescalar] ~/ tableSize);
1124+
frequency = 64e6 / wavelength / p[prescalar] / tableSize;
1125+
if (wavelength < 65525) break;
1126+
prescalar++;
1127+
}
1128+
1129+
if (prescalar == 4) {
1130+
logger.e("Out of range");
1131+
return -1;
1132+
}
1133+
1134+
try {
1135+
mPacketHandler.sendByte(mCommandsProto.wavegen);
1136+
mPacketHandler.sendByte(mCommandsProto.setSine1);
1137+
mPacketHandler.sendByte(highRes | (prescalar << 1));
1138+
mPacketHandler.sendInt(wavelength - 1);
1139+
await mPacketHandler.getAcknowledgement();
1140+
1141+
sin1Frequency = frequency;
1142+
return sin1Frequency;
1143+
} catch (e) {
1144+
logger.e("Error setting SI1: $e");
1145+
}
1146+
1147+
return -1;
1148+
}
1149+
1150+
Future<double> setSI2(double frequency, String? waveType) async {
1151+
double freqLowLimit = 0.1;
1152+
int highRes, tableSize;
1153+
1154+
if (frequency < freqLowLimit) {
1155+
logger.e("frequency too low");
1156+
return -1;
1157+
} else if (frequency < 1100) {
1158+
highRes = 1;
1159+
tableSize = 512;
1160+
} else {
1161+
highRes = 0;
1162+
tableSize = 32;
1163+
}
1164+
1165+
if (waveType != null) {
1166+
if (waveType == "sine" || waveType == "tria") {
1167+
if (this.waveType["SI2"] != waveType) {
1168+
loadEquation("SI2", waveType);
1169+
}
1170+
} else {
1171+
logger.e("Not a valid waveform. try sine or tria");
1172+
}
1173+
}
1174+
1175+
List<int> p = [1, 8, 64, 256];
1176+
int prescalar = 0;
1177+
int wavelength = 0;
1178+
1179+
while (prescalar <= 3) {
1180+
wavelength = (64e6 ~/ frequency ~/ p[prescalar] ~/ tableSize);
1181+
frequency = 64e6 / wavelength / p[prescalar] / tableSize;
1182+
if (wavelength < 65525) break;
1183+
prescalar++;
1184+
}
1185+
1186+
if (prescalar == 4) {
1187+
logger.e("Out of range");
1188+
return -1;
1189+
}
1190+
1191+
try {
1192+
mPacketHandler.sendByte(mCommandsProto.wavegen);
1193+
mPacketHandler.sendByte(mCommandsProto.setSine2);
1194+
mPacketHandler.sendByte(highRes | (prescalar << 1));
1195+
mPacketHandler.sendInt(wavelength - 1);
1196+
await mPacketHandler.getAcknowledgement();
1197+
1198+
sin2Frequency = frequency;
1199+
return sin2Frequency;
1200+
} catch (e) {
1201+
logger.e("Error setting SI2: $e");
1202+
}
1203+
1204+
return -1;
1205+
}
1206+
1207+
Future<double> setWaves(
1208+
double frequency, double phase, double frequency2) async {
1209+
int highRes, tableSize, highRes2, tableSize2;
1210+
int wavelength = 0, wavelength2 = 0;
1211+
1212+
if (frequency2 == -1) frequency2 = frequency;
1213+
1214+
if (frequency < 0.1) {
1215+
logger.e("frequency 1 too low");
1216+
return -1;
1217+
} else if (frequency < 1100) {
1218+
highRes = 1;
1219+
tableSize = 512;
1220+
} else {
1221+
highRes = 0;
1222+
tableSize = 32;
1223+
}
1224+
1225+
if (frequency2 < 0.1) {
1226+
logger.e("frequency 2 too low");
1227+
return -1;
1228+
} else if (frequency2 < 1100) {
1229+
highRes2 = 1;
1230+
tableSize2 = 512;
1231+
} else {
1232+
highRes2 = 0;
1233+
tableSize2 = 32;
1234+
}
1235+
1236+
if (frequency < 1 || frequency2 < 1) {
1237+
logger.e(
1238+
"extremely low frequencies will have reduced amplitudes due to AC coupling restrictions");
1239+
}
1240+
1241+
List<int> p = [1, 8, 64, 256];
1242+
1243+
int prescalar = 0;
1244+
double retFrequency = 0;
1245+
while (prescalar <= 3) {
1246+
wavelength = (64e6 ~/ frequency ~/ p[prescalar] ~/ tableSize);
1247+
retFrequency = 64e6 / wavelength / p[prescalar] / tableSize;
1248+
if (wavelength < 65525) break;
1249+
prescalar++;
1250+
}
1251+
if (prescalar == 4) {
1252+
logger.e("#1 out of range");
1253+
return -1;
1254+
}
1255+
1256+
int prescalar2 = 0;
1257+
double retFrequency2 = 0;
1258+
while (prescalar2 <= 3) {
1259+
wavelength2 = (64e6 ~/ frequency2 ~/ p[prescalar2] ~/ tableSize2);
1260+
retFrequency2 = 64e6 / wavelength2 / p[prescalar2] / tableSize2;
1261+
if (wavelength2 < 65525) break;
1262+
prescalar2++;
1263+
}
1264+
if (prescalar2 == 4) {
1265+
logger.e("#2 out of range");
1266+
return -1;
1267+
}
1268+
1269+
int phaseCoarse = (tableSize2 * (phase) / 360).toInt();
1270+
int phaseFine = (wavelength2 *
1271+
(phase - (phaseCoarse) * 360 / tableSize2) /
1272+
(360 / tableSize2))
1273+
.toInt();
1274+
1275+
try {
1276+
mPacketHandler.sendByte(mCommandsProto.wavegen);
1277+
mPacketHandler.sendByte(mCommandsProto.setBothWg);
1278+
mPacketHandler.sendInt(wavelength - 1);
1279+
mPacketHandler.sendInt(wavelength2 - 1);
1280+
mPacketHandler.sendInt(phaseCoarse);
1281+
mPacketHandler.sendInt(phaseFine);
1282+
mPacketHandler.sendByte(
1283+
(prescalar2 << 4) | (prescalar << 2) | (highRes2 << 1) | (highRes));
1284+
await mPacketHandler.getAcknowledgement();
1285+
1286+
sin1Frequency = retFrequency;
1287+
sin2Frequency = retFrequency2;
1288+
return retFrequency;
1289+
} catch (e) {
1290+
logger.e("Error setting waves: $e");
1291+
}
1292+
1293+
return -1;
1294+
}
1295+
1296+
Future<double> sqrPWM(
1297+
double frequency,
1298+
double h0,
1299+
double p1,
1300+
double h1,
1301+
double p2,
1302+
double h2,
1303+
double p3,
1304+
double h3,
1305+
bool pulse,
1306+
) async {
1307+
if (frequency == 0) return -1;
1308+
1309+
if (h0 == 0) h0 = 0.1;
1310+
if (h1 == 0) h1 = 0.1;
1311+
if (h2 == 0) h2 = 0.1;
1312+
if (h3 == 0) h3 = 0.1;
1313+
1314+
if (frequency > 10e6) {
1315+
logger.e(
1316+
"Frequency is greater than 10MHz. Please use map_reference_clock for 16 & 32MHz outputs",
1317+
);
1318+
return -1;
1319+
}
1320+
1321+
List<int> p = [1, 8, 64, 256];
1322+
int prescalar = 0;
1323+
int wavelength = 0;
1324+
1325+
while (prescalar <= 3) {
1326+
wavelength = (64e6 ~/ frequency ~/ p[prescalar]);
1327+
if (wavelength < 65525) break;
1328+
prescalar++;
1329+
}
1330+
1331+
if (prescalar == 4 || wavelength == 0) {
1332+
logger.e("Out of Range");
1333+
return -1;
1334+
}
1335+
1336+
if (!pulse) prescalar |= (1 << 5);
1337+
1338+
int a1 = ((p1 % 1) * wavelength).toInt();
1339+
int b1 = (((h1 + p1) % 1) * wavelength).toInt();
1340+
int a2 = ((p2 % 1) * wavelength).toInt();
1341+
int b2 = (((h2 + p2) % 1) * wavelength).toInt();
1342+
int a3 = ((p3 % 1) * wavelength).toInt();
1343+
int b3 = (((h3 + p3) % 1) * wavelength).toInt();
1344+
1345+
try {
1346+
mPacketHandler.sendByte(mCommandsProto.wavegen);
1347+
mPacketHandler.sendByte(mCommandsProto.sqr4);
1348+
mPacketHandler.sendInt(wavelength - 1);
1349+
mPacketHandler.sendInt((wavelength * h0).toInt() - 1);
1350+
mPacketHandler.sendInt(a1 > 0 ? a1 - 1 : 0);
1351+
mPacketHandler.sendInt(b1 > 1 ? b1 - 1 : 1);
1352+
mPacketHandler.sendInt(a2 > 0 ? a2 - 1 : 0);
1353+
mPacketHandler.sendInt(b2 > 1 ? b2 - 1 : 1);
1354+
mPacketHandler.sendInt(a3 > 0 ? a3 - 1 : 0);
1355+
mPacketHandler.sendInt(b3 > 1 ? b3 - 1 : 1);
1356+
mPacketHandler.sendByte(prescalar);
1357+
await mPacketHandler.getAcknowledgement();
1358+
} catch (e) {
1359+
logger.e("Error sending data: $e");
1360+
}
1361+
1362+
for (var channel in ["SQR1", "SQR2", "SQR3", "SQR4"]) {
1363+
squareWaveFrequency[channel] = 64e6 / wavelength / p[prescalar & 0x3];
1364+
}
1365+
1366+
return (64e6 / wavelength / p[prescalar & 0x3]);
1367+
}
1368+
10931369
Future<void> servo4(
10941370
double? angle1,
10951371
double? angle2,

lib/l10n/app_en.arb

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,31 @@
111111
"phase": "Phase",
112112
"duty": "Duty",
113113
"produceSound": "Produce Sound",
114+
"frequency": "Frequency",
115+
"phaseOffset": "Phase Offset",
116+
"unitDeg": "°",
117+
"unitPercentage": "%",
118+
"sine": "Sine",
119+
"tri": "Tri",
120+
"pwm": "pwm",
121+
"waveGeneratorIntro": "The wave generator can be used to generate different types of waves like Sine wave, square wave and saw-tooth wave allow us to change their characteristics like frequency, phase and duty. It also allows us to produce PWM signals having different phase and duty.",
122+
"sineWaveCaption": "To generate Sine wave or Saw-Tooth wave:",
123+
"sineWaveBulletPoint1": "Connect the Wave pins S1 and S2 to the channel pins CH1, CH2 as shown in the above figure.",
124+
"sineWaveBulletPoint2": "Select the Wave1 button for S1 pin and Wave2 button for S2 pin.",
125+
"sineWaveBulletPoint3": "Press Sine image button for Sine wave and Saw-Tooth image button for Saw-Tooth wave.",
126+
"sineWaveBulletPoint4": "Set their respective frequencies and phase difference(optional) using buttons in waveform panel.",
127+
"sineWaveBulletPoint5": "Press the View button to view the waves in oscilloscope.",
128+
"squareWaveCaption": "To generate Square wave:",
129+
"squareWaveBulletPoint1": "Connect the Wave pins SQ1 to the channel pin CH1 as shown in the above figure.",
130+
"squareWaveBulletPoint2": "Ensure the mode is selected to the Square, if not press the mode button to switch to Square mode.",
131+
"squareWaveBulletPoint3": "Select the SQ1 button",
132+
"squareWaveBulletPoint4": "Set its Frequency and Duty Cycle",
133+
"squareWaveBulletPoint5": "Press the View button to view the square wave in oscilloscope.",
134+
"pwmCaption": "Similarly, to produce four different PWM signals:",
135+
"pwmBulletPoint1": "Switch over to PWM mode(In this mode S1 and S2 pin will be disabled).",
136+
"pwmBulletPoint2": "Set the common frequency for all the SQ pins.",
137+
"pwmBulletPoint3": "Set the duty and phase for all the SQ pins.",
138+
"pwmBulletPoint4": "Press View button to generate the PWM signals.",
114139
"analyze": "Analyze",
115140
"settings": "Settings",
116141
"autoStart": "Auto Start",

0 commit comments

Comments
 (0)