mirror of
https://github.com/dandri/PricehaxBT.git
synced 2026-03-30 09:39:51 +00:00
Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40f0aa3c6f | ||
|
|
581184a691 | ||
|
|
10f5abd1c6 | ||
|
|
02770aa909 | ||
|
|
330a66d5b0 | ||
|
|
ee57c80db8 | ||
|
|
e34eb7278f | ||
|
|
ee38b97de8 | ||
|
|
4ee9a9451a | ||
|
|
3fccdd32a0 | ||
|
|
0c95e04c94 | ||
|
|
0f28b9c155 | ||
|
|
50be98fe86 | ||
|
|
20a1f0bcee | ||
|
|
9e02ac3953 | ||
|
|
29f1c6f202 | ||
|
|
85e16b72e4 | ||
|
|
d787599873 | ||
|
|
b7fce4bfbf | ||
|
|
a618faaffe | ||
|
|
33d79571b6 | ||
|
|
c856a39c8e | ||
|
|
0a110abb02 | ||
|
|
c808e0ed4e | ||
|
|
d1b40b377e | ||
|
|
4499bfbf9f | ||
|
|
1a84c610ba | ||
|
|
5b673317cc | ||
|
|
f337b93d25 | ||
|
|
615d7a2909 | ||
|
|
07c5ece3aa | ||
|
|
d33ef3e10a | ||
|
|
cf7ec44431 | ||
|
|
5782df9f38 | ||
|
|
607680fe40 | ||
|
|
b59400eb22 | ||
|
|
05efc0e52b | ||
|
|
22f00ef100 | ||
|
|
d026ecf2c7 | ||
|
|
517a3ef667 | ||
|
|
4fa5487e9c | ||
|
|
d9f2e28c8f | ||
|
|
8935edb14a |
3
.idea/.gitignore
generated
vendored
Normal file
3
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
9
.idea/PricehaxBT.iml
generated
Normal file
9
.idea/PricehaxBT.iml
generated
Normal file
@@ -0,0 +1,9 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/PricehaxBT.iml" filepath="$PROJECT_DIR$/.idea/PricehaxBT.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
BIN
PricehaxBT.apk
Normal file
BIN
PricehaxBT.apk
Normal file
Binary file not shown.
96
README.md
96
README.md
@@ -1,45 +1,91 @@
|
||||
# Pricehax BT
|
||||
Working prototype of the ESL hack project of furrtek (https://github.com/furrtek/PrecIR) using Pricehax BT app, Arduino Nano board and HC-06 (or HC-05) module for bluetooth communication.
|
||||
Prototype of the ESL hack project done by Furrtek (https://github.com/furrtek/PrecIR) using the Pricehax BT Android app, Arduino Nano board and HC-06 (or HC-05) module for Bluetooth communication.
|
||||
|
||||
Videos about this project are archived in this [playlist](https://www.youtube.com/playlist?list=PLhEz48id1qqD27sRc73mDFfBpu_RcLxfZ) (most in French).
|
||||
**Disclaimer:** For educational purposes and fun only. Both Furrtek and I decline all responsability for any kind of issues related to an illegal use of this repo. Be smart, the prices in the store's database won't change, you have been warned.
|
||||
|
||||
Furrtek's videos of this project are archived in this [playlist](https://www.youtube.com/playlist?list=PLhEz48id1qqD27sRc73mDFfBpu_RcLxfZ) (most in French, auto-translated subtitles are enabled but they are far from perfect).
|
||||
|
||||
<img src="PricehaxBT.jpg" width="640" alt="PricehaxBT">
|
||||
|
||||
## Build
|
||||
- Create the dongle on breadboard following the schematic (or order the pcb and solder the components)
|
||||
- Using AT commands, change the name of the HC-05/HC-06 module to "PRICEHAX TX V3" and its baud rate to 57600bps (115200bps and more will not work because of the SoftwareSerial library usage that produces errors at those rates)
|
||||
- Using the AT commands, change the name of the HC-05/HC-06 module to "PRICEHAX TX V3" and its baudrate to 115200bps
|
||||
- Program the arduino nano with the included sketch
|
||||
- Install the android app, pair the dongle and enjoy ;-)
|
||||
- Download and install the [Android app](https://github.com/dandri/PricehaxBT/releases/latest), pair the dongle and enjoy ;-)
|
||||
|
||||
## Android app improvements
|
||||
**Version 18.0**
|
||||
- Fixed ST HD150 and ST HD200 definition
|
||||
- Red (and yellow ?) ESLs are supported : https://youtu.be/0PFMIiDluDw
|
||||
- Improved Bluetooth transmission reliability : comparison of received checksum and calculated checksum by the dongle
|
||||
- Added the possibility to stop current image send
|
||||
## Android app changelog
|
||||
|
||||
**Version 17.0**
|
||||
- Fixed some bugs and crashes
|
||||
### Version 1.4
|
||||
|
||||
Added support for:
|
||||
- HD 150
|
||||
- HD 200
|
||||
- 1624 Freezer
|
||||
- 1628 (B407047372716287)
|
||||
- 1639 (A406048236716396)
|
||||
- 1243 Continuum E4 HCW (F45324224927123434)
|
||||
- 1627 (D4611412853816278)
|
||||
|
||||
### Version 1.3 (21)
|
||||
|
||||
**Features**
|
||||
- Added PP16 IR Protocol support (not full speed, see [Notes](https://github.com/david4599/PricehaxBT#notes)): [speed comparison video](https://youtu.be/DFfLOQh_ERs)
|
||||
- Updated camera autofocus handling by using continuous focus modes if available
|
||||
- Improved Bluetooth transmission reliability: the whole data (Pricehax header + PPM frame) is sent to the dongle with a basic checksum instead of using the PPM frame CRC that won't verify the header
|
||||
|
||||
**Fixes**
|
||||
- Fixed bug that was sometimes stopping the image transmission just after the wake-up frame
|
||||
- Fixed camera preview rotation in reverse landscape and reverse portrait orientations
|
||||
- Fixed waiting time when sending an image in 2 parts (due to 64kB limit)
|
||||
|
||||
### Version 1.2 (20)
|
||||
|
||||
**Features**
|
||||
- Added 1370 and 1371 ESL types (ST HD L Red and ST HD150 Red black housing versions)
|
||||
- Added checksum verification of the ESL barcode
|
||||
|
||||
**Fixes**
|
||||
- Fixed SmartTag HD T definition in information label
|
||||
|
||||
### Version 1.2 (19)
|
||||
|
||||
**Features**
|
||||
- Added a mode to enter the barcode manually
|
||||
|
||||
### Version 1.1 (18)
|
||||
|
||||
**Features**
|
||||
- Red (yellow not tested) ESLs are supported: https://youtu.be/0PFMIiDluDw
|
||||
- Improved Bluetooth transmission reliability: comparison of received checksum and calculated checksum by the dongle
|
||||
- Added the possibility to stop sending the current image
|
||||
|
||||
**Fixes**
|
||||
- Fixed ST HD150 and ST HD200 definitions
|
||||
|
||||
### Version 1.1 (17)
|
||||
|
||||
**Features**
|
||||
- Added the ability to scroll if pages are greater than the height of the screen (especially in landscape mode)
|
||||
- Display debug infos for 24h
|
||||
- Hide debug infos feature added
|
||||
- Ability to blink the green LED on ST ESLs (not working yet on some) : https://youtu.be/b0Rn40alxQg
|
||||
- Start autofocus by touching the preview screen on "PLID Scan" tab
|
||||
- Ability to blink the green LED on ST ESLs (not working yet on some): https://youtu.be/b0Rn40alxQg
|
||||
- Start autofocus by touching the preview screen on "PLID Scan" tab (not working sometimes?)
|
||||
- ESL types added (mainly graphic ESLs, not tested on the most of them but it should work)
|
||||
- Automatically choose sending compressed or raw data to graphic ESLs
|
||||
- Ability to force not compressed data sending to graphic ESLs
|
||||
- The number of repeats of frames for graphic ESLs can be chosen (speed transmission vs reliability)
|
||||
- The dongle can be manually connected or disconnected in "Config" page
|
||||
- Ability to force sending uncompressed data to graphic ESLs
|
||||
- The number of frames repeats for graphic ESLs can be chosen (speed transmission vs reliability)
|
||||
- The dongle can be manually connected or disconnected in "Config" tab
|
||||
|
||||
**Fixes**
|
||||
- Fixed some bugs and app crashes
|
||||
|
||||
## Notes
|
||||
- Android app sources are included
|
||||
- I didn't write the app, I only decompiled sources of the apk, imported them on Android Studio and rebuilt the app
|
||||
- The app supports only Bluetooth communication
|
||||
- Furrtek had already code Bluetooth feature in the original app, I just made some changes for that feature works with my dongle
|
||||
- I am not a programming or electronic expert, so maybe I made some mistakes on coding or making the schematic...
|
||||
- The implemented PP4C and PP16 protocols are not transmitting data at their maximum speeds. In theory, they should be around 10kbps for PP4C and 38kbps for PP16 (in reality, they are measured at 9kbps and 31kbps). Pricehax BT seems to do only 6kbps and 11kbps if my calculations are correct
|
||||
- I didn't write the app, I just decompiled the sources from the apk (that's why the code is a bit of a mess). Then, I imported them on Android Studio and fixed the decompilation errors preventing the re-compilation
|
||||
- The app supports Bluetooth communication only, the original communication using audio has been disabled (not the goal of this repo)
|
||||
- Furrtek did code the Bluetooth feature in the original app, I just made some changes so the feature works with my dongle
|
||||
- I am not a programming or electronic expert, so the code and the schematic might be better...
|
||||
|
||||
#
|
||||
|
||||
Both furrtek and me decline all responsability for any kind of issues related by an illegal use of this project.
|
||||
|
||||
Copyright (c) furrtek 2014 - david4599 2019
|
||||
Copyright (c) Furrtek 2014 & david4599 2019 - 2022
|
||||
|
||||
Binary file not shown.
@@ -6,8 +6,8 @@ android {
|
||||
applicationId "org.furrtek.pricehaxbt"
|
||||
minSdkVersion 15
|
||||
targetSdkVersion 28
|
||||
versionCode 18
|
||||
versionName "1.1"
|
||||
versionCode 21
|
||||
versionName "1.4"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
|
||||
8
app/src/app/local.properties
Normal file
8
app/src/app/local.properties
Normal file
@@ -0,0 +1,8 @@
|
||||
## This file must *NOT* be checked into Version Control Systems,
|
||||
# as it contains information specific to your local configuration.
|
||||
#
|
||||
# Location of the SDK. This is only used by Gradle.
|
||||
# For customization when using a Version Control System, please read the
|
||||
# header note.
|
||||
#Thu Apr 20 13:49:00 GMT 2023
|
||||
sdk.dir=C\:\\Users\\dandri\\AppData\\Local\\Android\\Sdk
|
||||
@@ -1,10 +1,13 @@
|
||||
package org.furrtek.pricehaxbt;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.hardware.Camera;
|
||||
import android.hardware.Camera.CameraInfo;
|
||||
import android.hardware.Camera.AutoFocusCallback;
|
||||
import android.hardware.Camera.PreviewCallback;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceHolder.Callback;
|
||||
import android.view.SurfaceView;
|
||||
@@ -18,29 +21,50 @@ public class CameraPreview extends SurfaceView implements Callback {
|
||||
private Camera mCamera;
|
||||
private SurfaceHolder mHolder = getHolder();
|
||||
private PreviewCallback previewCallback;
|
||||
private boolean oldAutoFocusMode;
|
||||
private Context context;
|
||||
private int cameraId;
|
||||
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
checkOrientation(newConfig);
|
||||
}
|
||||
|
||||
private void checkOrientation(Configuration newConfig) {
|
||||
if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
|
||||
this.mCamera.setDisplayOrientation(90);
|
||||
} else {
|
||||
this.mCamera.setDisplayOrientation(0);
|
||||
}
|
||||
setCameraDisplayOrientation((Activity) this.context, this.cameraId, this.mCamera);
|
||||
}
|
||||
|
||||
public CameraPreview(Context context, Camera camera, PreviewCallback previewCb, AutoFocusCallback autoFocusCb) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
|
||||
this.mCamera = camera;
|
||||
this.previewCallback = previewCb;
|
||||
this.autoFocusCallback = autoFocusCb;
|
||||
this.mHolder.addCallback(this);
|
||||
this.mHolder.setType(3);
|
||||
|
||||
this.cameraId = getBackCameraId();
|
||||
|
||||
// The old mode uses the onAutoFocus function and makes a timer to try to focus periodically.
|
||||
// The drawback is the hunting of the camera.
|
||||
// This can be "smoothed" by using either FOCUS_MODE_CONTINUOUS_PICTURE or FOCUS_MODE_CONTINUOUS_VIDEO parameters instead (if available).
|
||||
Camera.Parameters params = this.mCamera.getParameters();
|
||||
|
||||
this.oldAutoFocusMode = false;
|
||||
if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) {
|
||||
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE);
|
||||
}
|
||||
else if (params.getSupportedFocusModes().contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO)) {
|
||||
params.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_VIDEO);
|
||||
}
|
||||
else {
|
||||
this.oldAutoFocusMode = true;
|
||||
}
|
||||
|
||||
this.mCamera.setParameters(params);
|
||||
}
|
||||
|
||||
public boolean isOldAutoFocusMode() {
|
||||
return this.oldAutoFocusMode;
|
||||
}
|
||||
|
||||
public void surfaceCreated(SurfaceHolder holder) {
|
||||
@@ -63,16 +87,61 @@ public class CameraPreview extends SurfaceView implements Callback {
|
||||
} catch (Exception e) {
|
||||
}
|
||||
try {
|
||||
if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
|
||||
this.mCamera.setDisplayOrientation(90);
|
||||
}
|
||||
setCameraDisplayOrientation((Activity) this.context, this.cameraId, this.mCamera);
|
||||
|
||||
this.mCamera.setPreviewDisplay(this.mHolder);
|
||||
this.mCamera.setPreviewCallback(this.previewCallback);
|
||||
this.mCamera.startPreview();
|
||||
this.mCamera.autoFocus(this.autoFocusCallback);
|
||||
|
||||
if (this.oldAutoFocusMode) {
|
||||
this.mCamera.autoFocus(this.autoFocusCallback);
|
||||
}
|
||||
|
||||
} catch (Exception e2) {
|
||||
Log.d("DBG", "Error starting camera preview: " + e2.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Adapted from Android SDK API sample code
|
||||
// https://github.com/Miserlou/Android-SDK-Samples/blob/master/ApiDemos/src/com/example/android/apis/graphics/CameraPreview.java
|
||||
private int getBackCameraId() {
|
||||
int numberOfCameras = Camera.getNumberOfCameras();
|
||||
|
||||
CameraInfo cameraInfo = new CameraInfo();
|
||||
for (int i = 0; i < numberOfCameras; i++) {
|
||||
Camera.getCameraInfo(i, cameraInfo);
|
||||
if (cameraInfo.facing == CameraInfo.CAMERA_FACING_BACK) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sample code from Android Developer documentation
|
||||
// https://developer.android.com/reference/android/hardware/Camera#setDisplayOrientation%28int%29
|
||||
public static void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
|
||||
android.hardware.Camera.CameraInfo info = new android.hardware.Camera.CameraInfo();
|
||||
android.hardware.Camera.getCameraInfo(cameraId, info);
|
||||
|
||||
int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
|
||||
int degrees = 0;
|
||||
switch (rotation) {
|
||||
case Surface.ROTATION_0: degrees = 0; break;
|
||||
case Surface.ROTATION_90: degrees = 90; break;
|
||||
case Surface.ROTATION_180: degrees = 180; break;
|
||||
case Surface.ROTATION_270: degrees = 270; break;
|
||||
}
|
||||
|
||||
int result;
|
||||
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
|
||||
result = (info.orientation + degrees) % 360;
|
||||
result = (360 - result) % 360; // compensate the mirror
|
||||
} else { // back-facing
|
||||
result = (info.orientation - degrees + 360) % 360;
|
||||
}
|
||||
|
||||
camera.setDisplayOrientation(result);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,31 +1,44 @@
|
||||
package org.furrtek.pricehaxbt;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.media.AudioTrack;
|
||||
import android.media.AudioTrack.OnPlaybackPositionUpdateListener;
|
||||
import android.support.v4.view.MotionEventCompat;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
public class PP4C {
|
||||
public class PPM {
|
||||
static AudioManager mAudioManager;
|
||||
static int origVolume;
|
||||
static double[] sample = new double[48000];
|
||||
|
||||
private static void sendData(byte[] tmp) {
|
||||
Log.d("BT SEND", "SENDING DATA...");
|
||||
private static void sendData(MainActivity mainActivity, byte[] tmp) {
|
||||
//Log.d("BT SEND", "SENDING DATA...");
|
||||
try {
|
||||
byte[] buffer = new byte[128];
|
||||
int timeout = 20;
|
||||
int timeoutRead = 2000;
|
||||
|
||||
do {
|
||||
MainActivity.outStream.write(tmp);
|
||||
do {
|
||||
} while (MainActivity.inStream.available() <= 0);
|
||||
|
||||
int res = MainActivity.inStream.read(buffer);
|
||||
for (int i = timeoutRead; i > 0; i--) {
|
||||
if (MainActivity.inStream.available() > 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (!mainActivity.isSendImageThreadRunning()) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Thread.sleep(1);
|
||||
} catch (InterruptedException e22) {
|
||||
e22.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
MainActivity.inStream.read(buffer);
|
||||
timeout--;
|
||||
} while (buffer[0] == (byte) 49 && timeout >= 0);
|
||||
|
||||
@@ -36,25 +49,40 @@ public class PP4C {
|
||||
}
|
||||
}
|
||||
|
||||
static void sendPP4C(Context context, byte[] hcode, int length, int donglever, int rpt, AudioTrack audioTrack, int nbRepeatFrame) {
|
||||
static void sendPPM(MainActivity mainActivity, byte[] hcode, boolean pp16Mode, int length, int donglever, int rpt, AudioTrack audioTrack, int nbRepeatFrame) {
|
||||
double[] pcode = new double[256];
|
||||
byte[] generatedSnd = new byte[96000];
|
||||
if (donglever == 3) {
|
||||
int cp;
|
||||
byte[] btdata = new byte[58];
|
||||
btdata[0] = (byte) -86;
|
||||
byte[] btdata = new byte[60];
|
||||
btdata[0] = (byte) 170; // The first 4 bytes are only used by the dongle, they are not part of the PPM protocol
|
||||
|
||||
if (pp16Mode) {
|
||||
btdata[0] = (byte) 171;
|
||||
}
|
||||
|
||||
btdata[1] = (byte) (nbRepeatFrame >> 8);
|
||||
btdata[2] = (byte) (nbRepeatFrame & MotionEventCompat.ACTION_MASK);
|
||||
btdata[2] = (byte) (nbRepeatFrame & 0xFF);
|
||||
btdata[3] = (byte) length;
|
||||
for (cp = 0; cp < length; cp++) {
|
||||
btdata[cp + 4] = hcode[cp];
|
||||
}
|
||||
String plHexString = "";
|
||||
for (cp = 0; cp < btdata.length; cp++) {
|
||||
plHexString = plHexString + String.format("%02X", new Object[]{Byte.valueOf(btdata[cp])});
|
||||
|
||||
int basicChecksum = 0;
|
||||
for(byte i = 0; i < 4 + length; i++){
|
||||
basicChecksum += (btdata[i] & 0xFF); // " & 0xFF" is here to convert to unsigned byte because btdata[i] is a signed byte
|
||||
}
|
||||
sendData(btdata);
|
||||
Log.d("DATA", "SENT " + plHexString);
|
||||
|
||||
// Should not overflow since the max possible checksum should be less than 16384 (if all bytes are 255, 255 * 64 = 16320)
|
||||
btdata[4 + length] = (byte) (basicChecksum >> 8);
|
||||
btdata[4 + length + 1] = (byte) (basicChecksum & 0xFF);
|
||||
|
||||
//String plHexString = "";
|
||||
//for (cp = 0; cp < btdata.length; cp++) {
|
||||
// plHexString = plHexString + String.format("%02X", new Object[]{Byte.valueOf(btdata[cp])});
|
||||
//}
|
||||
sendData(mainActivity, btdata);
|
||||
//Log.d("DATA", "SENT " + plHexString);
|
||||
}
|
||||
if (donglever < 3) {
|
||||
int i;
|
||||
@@ -78,7 +106,7 @@ public class PP4C {
|
||||
pcode[(i * 4) + 3] = (double) ((hcode[i] >> 6) & 3);
|
||||
}
|
||||
}
|
||||
mAudioManager = (AudioManager) context.getSystemService("audio");
|
||||
mAudioManager = (AudioManager) mainActivity.at.getApplicationContext().getSystemService("audio");
|
||||
origVolume = mAudioManager.getStreamVolume(3);
|
||||
mAudioManager.setStreamVolume(3, (int) (((double) mAudioManager.getStreamMaxVolume(3)) * (((double) (((float) MainActivity.transmitVolume) / 100.0f)) + 0.6d)), 0);
|
||||
for (int r = 0; r < 48000; r++) {
|
||||
@@ -165,7 +193,7 @@ public class PP4C {
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
PP4C.mAudioManager.setStreamVolume(3, PP4C.origVolume, 0);
|
||||
PPM.mAudioManager.setStreamVolume(3, PPM.origVolume, 0);
|
||||
}
|
||||
|
||||
public void onPeriodicNotification(AudioTrack track) {
|
||||
@@ -112,7 +112,7 @@
|
||||
android:id="@id/raddur7"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:layout_marginBottom="40dp"
|
||||
android:text="1h30"
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
@@ -120,7 +120,7 @@
|
||||
android:id="@id/raddur8"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Display debug infos"
|
||||
android:text="Show debug infos *"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="12.0sp" />
|
||||
|
||||
@@ -129,7 +129,7 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:text="Hide debug infos"
|
||||
android:text="Hide debug infos *"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="12.0sp" />
|
||||
|
||||
@@ -137,7 +137,7 @@
|
||||
android:id="@id/raddur10"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="SmartTag LED low flash *"
|
||||
android:text="SmartTag LED weak flash **"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="12.0sp" />
|
||||
|
||||
@@ -148,7 +148,7 @@
|
||||
android:layout_below="@id/chkrepeatdm"
|
||||
android:layout_alignStart="@id/radgDurations"
|
||||
android:layout_alignLeft="@id/radgDurations"
|
||||
android:text="SmartTag LED high flash *"
|
||||
android:text="SmartTag LED strong flash **"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="12.0sp" />
|
||||
</RadioGroup>
|
||||
@@ -207,14 +207,25 @@
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<TextView
|
||||
android:id="@id/txtvledflash"
|
||||
android:id="@id/txtdebug"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/radgDurations"
|
||||
android:layout_alignLeft="@id/txtvPageDur"
|
||||
android:layout_alignRight="@id/button2"
|
||||
android:layout_marginTop="16.0dip"
|
||||
android:text="* Not working yet on some SmartTag ESLs"
|
||||
android:text="* DotMatrix ESLs only"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="11.0sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@id/txtvledflash"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/txtdebug"
|
||||
android:layout_alignLeft="@id/txtvPageDur"
|
||||
android:layout_alignRight="@id/button2"
|
||||
android:text="** Not working yet on some SmartTag ESLs"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="11.0sp" />
|
||||
|
||||
@@ -226,7 +237,7 @@
|
||||
android:layout_alignLeft="@id/txtvPageDur"
|
||||
android:layout_alignRight="@id/button2"
|
||||
android:layout_marginTop="6.0dip"
|
||||
android:text="Use the 'Page number' field to define the number of times the LED will flash (0 = always)"
|
||||
android:text="Use the 'Page number' field to define the number of times the LED will flash (between 1 and 9, 0 = always)"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="11.0sp" />
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
android:layout_height="192.0dip"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="8.0dip"
|
||||
android:onClick="doAutoFocusOnTouch"/>
|
||||
android:onClick="doOldAutoFocusOnTouch"/>
|
||||
|
||||
<Button
|
||||
android:id="@id/scan_button"
|
||||
android:layout_width="200.0dip"
|
||||
android:layout_width="264.0dip"
|
||||
android:layout_height="50.0dip"
|
||||
android:layout_below="@id/cameraPreview"
|
||||
android:layout_centerHorizontal="true"
|
||||
@@ -29,6 +29,40 @@
|
||||
android:text="Scan ESL barcode"
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/manual_barcode_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8.0dip"
|
||||
android:layout_below="@id/scan_button"
|
||||
android:text="Enter ESL barcode"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:visibility="gone"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="18.0sp" />
|
||||
|
||||
<EditText
|
||||
android:id="@+id/barcode_edittext"
|
||||
android:layout_width="300.0dp"
|
||||
android:layout_height="40.0dp"
|
||||
android:layout_marginTop="8.0dip"
|
||||
android:layout_below="@id/manual_barcode_title"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:visibility="gone"
|
||||
android:hint="e.g. A0123456789012345"
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/set_barcode_button"
|
||||
android:layout_width="200.0dip"
|
||||
android:layout_height="50.0dip"
|
||||
android:layout_below="@id/barcode_edittext"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="8.0dip"
|
||||
android:text="Set ESL barcode"
|
||||
android:visibility="gone"
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@id/llESLInfo"
|
||||
android:layout_width="wrap_content"
|
||||
@@ -51,11 +85,21 @@
|
||||
android:id="@id/eslinfo_barcode"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/scan_button"
|
||||
android:layout_below="@id/set_barcode_button"
|
||||
android:layout_toEndOf="@id/llESLInfo"
|
||||
android:layout_toRightOf="@id/llESLInfo"
|
||||
android:text="ESL barcode"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="10.0sp" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/manual_scan_button"
|
||||
android:layout_width="300.0dip"
|
||||
android:layout_height="50.0dip"
|
||||
android:layout_below="@id/eslinfo_type"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="30.0dip"
|
||||
android:text="Enter barcode manually"
|
||||
android:textColor="@color/textcolor" />
|
||||
</RelativeLayout>
|
||||
</ScrollView>
|
||||
@@ -33,14 +33,50 @@
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginLeft="8.0dip"
|
||||
android:layout_marginTop="8.0dip"
|
||||
android:layout_marginBottom="16.0dip"
|
||||
android:text="Segment bitstream: "
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvppmversion"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/label_dbgbs"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:text="PPM mode for DotMatrix ESLs:"
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/ppmversion"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/tvppmversion"
|
||||
android:layout_marginTop="8.0dip"
|
||||
android:layout_marginBottom="32.0dip"
|
||||
android:layout_centerHorizontal="true">
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radpp16"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:checked="true"
|
||||
android:text="PP16 (faster)"
|
||||
android:textColor="@color/textcolor" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radpp4c"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="PP4C"
|
||||
android:textColor="@color/textcolor" />
|
||||
</RadioGroup>
|
||||
|
||||
|
||||
<CheckBox
|
||||
android:id="@id/chk_donglever"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/label_dbgbs"
|
||||
android:layout_below="@id/ppmversion"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="25.0dip"
|
||||
android:checked="true"
|
||||
@@ -117,7 +153,7 @@
|
||||
android:id="@+id/btnPairBT"
|
||||
android:layout_below="@id/tvbtt"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:onClick="pairBTTransmitter"
|
||||
android:textColor="@color/textcolor" />
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="48.0dip"
|
||||
android:gravity="center_horizontal"
|
||||
android:text="Version 1.1 BT (18.0)"
|
||||
android:text="Version 1.3 BT (21)"
|
||||
android:textColor="@color/textcolor"
|
||||
android:textSize="15.0sp" />
|
||||
|
||||
|
||||
@@ -127,4 +127,5 @@
|
||||
<item type="id" name="txtwork" />
|
||||
<item type="id" name="force_raw_sending_mode" />
|
||||
<item type="id" name="action_settings" />
|
||||
<item type="id" name="txtdebug" />
|
||||
</resources>
|
||||
|
||||
@@ -1,161 +0,0 @@
|
||||
/*
|
||||
* Pricehax BT IR dongle (for Pricehax Version 1.1 BT (18.0))
|
||||
* furrtek 2014
|
||||
* david4599 2019
|
||||
*/
|
||||
|
||||
#define F_CPU 16000000L
|
||||
#define NOP __asm__ __volatile__ ("nop\n\t")
|
||||
|
||||
#define BT_RXPIN 10
|
||||
#define BT_TXPIN 12
|
||||
#define LEDPIN 2
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
SoftwareSerial BT(BT_RXPIN, BT_TXPIN);
|
||||
|
||||
boolean sendframe = false;
|
||||
uint8_t b, cnt, data[54], datalength;
|
||||
uint16_t s, sym_count, r, repeat = 0, result, poly;
|
||||
|
||||
|
||||
|
||||
void CRCCalc() {
|
||||
result = 0x8408;
|
||||
poly = 0x8408;
|
||||
|
||||
for (int i = 0; i < datalength-2; i++) {
|
||||
result ^= data[i];
|
||||
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (result & 1) {
|
||||
result >>= 1;
|
||||
result ^= poly;
|
||||
}
|
||||
else {
|
||||
result >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void burst() { // Create 40us burst at around 1.25MHz
|
||||
for(int i = 0; i < 50; i++){
|
||||
PORTD ^= (1 << LEDPIN);
|
||||
NOP;
|
||||
NOP;
|
||||
PORTD ^= (1 << LEDPIN);
|
||||
NOP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void getData() { // Get frames from Pricehax sent over Bluetooth
|
||||
if (BT.read() == 170) { // First byte sent is an ID to avoid unwanted values sent from the bluetooth module itself
|
||||
cnt = 0;
|
||||
|
||||
// Reset data array
|
||||
memset(data, 0, sizeof(data));
|
||||
|
||||
_delay_ms(1);
|
||||
|
||||
while (BT.available()) {
|
||||
if (cnt == 0) { // Read header data
|
||||
// Get the number of times the frame will be transmitted
|
||||
repeat = (byte) BT.read() << 8;
|
||||
repeat |= (byte) BT.read();
|
||||
|
||||
// Get the data length of the frame
|
||||
datalength = (byte) BT.read();
|
||||
}
|
||||
|
||||
if (cnt == datalength) { // Read unneeded bytes after the end of the frame
|
||||
while (BT.available()) {
|
||||
BT.read();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
data[cnt] = (byte) BT.read(); // Get the next byte of the frame
|
||||
cnt++;
|
||||
}
|
||||
|
||||
sendframe = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void IRSend() { // Send a frame following the IR protocol
|
||||
sym_count = datalength << 2;
|
||||
|
||||
for (r = 0; r < (unsigned int) repeat; r++) {
|
||||
for (s = 0; s < sym_count; s++) {
|
||||
if ((s & 3) == 0) {
|
||||
b = data[s >> 2];
|
||||
}
|
||||
|
||||
burst();
|
||||
|
||||
switch(b & 3) {
|
||||
case 0:
|
||||
_delay_us(56);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
_delay_us(237);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
_delay_us(117);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
_delay_us(178);
|
||||
break;
|
||||
}
|
||||
|
||||
b >>= 2;
|
||||
}
|
||||
|
||||
burst();
|
||||
|
||||
_delay_ms(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
DDRD |= (1 << LEDPIN); // Define led pin as output
|
||||
PORTD &= (0 << LEDPIN); // Set led pin to low state
|
||||
|
||||
BT.begin(57600);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop() {
|
||||
if (BT.available()) {
|
||||
getData();
|
||||
CRCCalc();
|
||||
|
||||
if (data[datalength-2] != (uint8_t) result || data[datalength-1] != (uint8_t) (result >> 8)) {
|
||||
BT.write("1");
|
||||
sendframe = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (sendframe) {
|
||||
IRSend();
|
||||
|
||||
BT.write("0"); // Send an answer to Pricehax once the frame is transmitted
|
||||
sendframe = false;
|
||||
}
|
||||
|
||||
_delay_ms(1);
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* Pricehax BT IR dongle (for Pricehax Version 1.3 BT (21))
|
||||
* furrtek 2014
|
||||
* david4599 2019 - 2022
|
||||
*/
|
||||
|
||||
|
||||
#define F_CPU 16000000UL
|
||||
#define NOP __asm__ __volatile__ ("nop")
|
||||
|
||||
#define BT_RX_PIN 10
|
||||
#define BT_TX_PIN 12
|
||||
#define LED_PIN 2
|
||||
|
||||
#define PULSES_PP4C 50
|
||||
#define PULSES_PP16 26
|
||||
#define FRAME_MAX_LENGTH 58
|
||||
|
||||
// Specific to Pricehax
|
||||
#define PHX_CODE_PP4C 170
|
||||
#define PHX_CODE_PP16 171
|
||||
|
||||
|
||||
#include <SoftwareSerial.h>
|
||||
|
||||
|
||||
SoftwareSerial BT(BT_RX_PIN, BT_TX_PIN);
|
||||
|
||||
uint8_t gData[FRAME_MAX_LENGTH], gDataLength;
|
||||
uint16_t gRepeat = 0;
|
||||
boolean gModePP16 = false, gSendFrame = false, gSentOk = false;
|
||||
|
||||
uint8_t gDataTemp[FRAME_MAX_LENGTH], gDataLengthTemp;
|
||||
uint16_t gRepeatTemp = 0;
|
||||
boolean gModePP16Temp = false;
|
||||
|
||||
|
||||
// Mandatory header for PP16 protocol, not included in the frame CRC16
|
||||
const uint8_t gPP16Header[4] = {
|
||||
0x00,
|
||||
0x00,
|
||||
0x00,
|
||||
0x40
|
||||
};
|
||||
|
||||
// The timings offsets (especially for PP16) may need to be adjusted again if another uC is used
|
||||
const uint8_t gOffPP4C = -5;
|
||||
const uint8_t gOffPP16 = -5;
|
||||
|
||||
// PP4C symbols timings
|
||||
const uint8_t gPP4C[4] = {
|
||||
61 + gOffPP4C,
|
||||
244 + gOffPP4C,
|
||||
122 + gOffPP4C,
|
||||
183 + gOffPP4C
|
||||
};
|
||||
|
||||
// PP16 symbols timings
|
||||
const uint8_t gPP16[16] = {
|
||||
27 + gOffPP16,
|
||||
51 + gOffPP16,
|
||||
35 + gOffPP16,
|
||||
43 + gOffPP16,
|
||||
147 + gOffPP16,
|
||||
123 + gOffPP16,
|
||||
139 + gOffPP16,
|
||||
131 + gOffPP16,
|
||||
83 + gOffPP16,
|
||||
59 + gOffPP16,
|
||||
75 + gOffPP16,
|
||||
67 + gOffPP16,
|
||||
91 + gOffPP16,
|
||||
115 + gOffPP16,
|
||||
99 + gOffPP16,
|
||||
107 + gOffPP16
|
||||
};
|
||||
|
||||
|
||||
|
||||
// Check the whole Bluetooth data with a basic checksum implementation
|
||||
boolean isPhxChecksumValid(uint16_t checksumToVerify) {
|
||||
uint8_t phxCode = PHX_CODE_PP4C, length = gDataLengthTemp, start = 0;
|
||||
uint16_t calcChecksum = 0;
|
||||
|
||||
if (gModePP16Temp) {
|
||||
// Skip the PP16 header
|
||||
phxCode = PHX_CODE_PP16;
|
||||
length = gDataLengthTemp - 4;
|
||||
start = 4;
|
||||
}
|
||||
|
||||
// Add frame parameters to the checksum
|
||||
calcChecksum += phxCode;
|
||||
calcChecksum += (uint8_t) (gRepeatTemp >> 8);
|
||||
calcChecksum += (uint8_t) (gRepeatTemp & 0xFF);
|
||||
calcChecksum += length;
|
||||
|
||||
for (uint8_t i = start; i < 4 + length; i++) {
|
||||
calcChecksum += gDataTemp[i];
|
||||
}
|
||||
|
||||
return calcChecksum == checksumToVerify;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
// Check the PPM frame CRC16 (replaced by isPhxChecksumValid())
|
||||
boolean isCRCValid() {
|
||||
uint16_t result = 0x8408, poly = 0x8408, offset = 0;
|
||||
|
||||
// Skip the PP16 header
|
||||
if (gModePP16Temp)
|
||||
offset = 4;
|
||||
|
||||
for (uint16_t i = offset; i < gDataLengthTemp - 2; i++) {
|
||||
result ^= gDataTemp[i];
|
||||
|
||||
for (uint8_t j = 0; j < 8; j++) {
|
||||
if (result & 1) {
|
||||
result >>= 1;
|
||||
result ^= poly;
|
||||
}
|
||||
else {
|
||||
result >>= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (gDataTemp[gDataLengthTemp - 2] != (uint8_t) result)
|
||||
return false;
|
||||
|
||||
if (gDataTemp[gDataLengthTemp - 1] != (uint8_t) (result >> 8))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
// Get a frame from Pricehax sent over Bluetooth
|
||||
boolean getFrame() {
|
||||
uint8_t phxCode, counter;
|
||||
uint16_t checksum;
|
||||
|
||||
// First byte sent is an ID to avoid unwanted values sent from the Bluetooth module itself
|
||||
phxCode = BT.read();
|
||||
if (phxCode == PHX_CODE_PP4C || phxCode == PHX_CODE_PP16) {
|
||||
counter = 0;
|
||||
|
||||
// Reset the temp data array
|
||||
memset(gDataTemp, 0, sizeof(gDataTemp));
|
||||
|
||||
while (BT.available()) {
|
||||
if (counter == 0) { // Read header data
|
||||
gModePP16Temp = false;
|
||||
|
||||
// Get the number of times the frame will be transmitted
|
||||
gRepeatTemp = (uint8_t) BT.read() << 8;
|
||||
gRepeatTemp |= (uint8_t) BT.read();
|
||||
|
||||
// Get the data length of the frame
|
||||
gDataLengthTemp = (uint8_t) BT.read();
|
||||
|
||||
if (phxCode == PHX_CODE_PP16) {
|
||||
// Add the PP16 header
|
||||
gModePP16Temp = true;
|
||||
memcpy(gDataTemp, gPP16Header, sizeof(gPP16Header));
|
||||
gDataLengthTemp += 4;
|
||||
counter += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (counter == gDataLengthTemp) {
|
||||
// Get the basic Pricehax checksum
|
||||
checksum = (uint8_t) BT.read() << 8;
|
||||
checksum |= (uint8_t) BT.read();
|
||||
|
||||
while (BT.available()) { // Read unneeded bytes after the end of the frame
|
||||
BT.read();
|
||||
}
|
||||
|
||||
return isPhxChecksumValid(checksum);
|
||||
}
|
||||
|
||||
gDataTemp[counter] = (uint8_t) BT.read(); // Get the next byte of the frame
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Create a burst (40us for PP4C, 21us for PP16) at around 1.25MHz (16MHz/13 = 1.23MHz)
|
||||
// The number of assembly instructions of the whole loop once compiled is critical
|
||||
// If the function is changed, the timings will need to be adjusted by adding or removing NOPs
|
||||
void sendPPMBurst(uint8_t pulses) {
|
||||
for(uint8_t i = 0; i < pulses; i++){
|
||||
PORTD ^= (1 << LED_PIN);
|
||||
NOP;
|
||||
NOP;
|
||||
PORTD ^= (1 << LED_PIN);
|
||||
NOP;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Send a frame using the PP4C protocol
|
||||
void sendPP4CFrame() {
|
||||
uint8_t currentByte;
|
||||
uint16_t repeat, symNumber, symCount;
|
||||
|
||||
// Get the number of PP4C symbols the frame contains
|
||||
symCount = gDataLength << 2;
|
||||
|
||||
for (repeat = 0; repeat < gRepeat; repeat++) {
|
||||
cli(); // Stop all interrupts to avoid added delay that will interfere with the PPM signal
|
||||
for (symNumber = 0; symNumber < symCount; symNumber++) {
|
||||
|
||||
// Switch to the next byte once the 4 2-bit symbols of the current byte are transmitted
|
||||
if ((symNumber & 3) == 0) {
|
||||
currentByte = gData[symNumber >> 2];
|
||||
}
|
||||
|
||||
sendPPMBurst(PULSES_PP4C);
|
||||
|
||||
switch(currentByte & 3) {
|
||||
case 0:
|
||||
_delay_us(gPP4C[0]);
|
||||
break;
|
||||
case 1:
|
||||
_delay_us(gPP4C[1]);
|
||||
break;
|
||||
case 2:
|
||||
_delay_us(gPP4C[2]);
|
||||
break;
|
||||
case 3:
|
||||
_delay_us(gPP4C[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Switch to the next symbol
|
||||
currentByte >>= 2;
|
||||
}
|
||||
|
||||
sendPPMBurst(PULSES_PP4C);
|
||||
sei(); // Allow interrupts
|
||||
|
||||
_delay_ms(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Send a frame using the PP16 protocol
|
||||
void sendPP16Frame() {
|
||||
uint8_t currentByte;
|
||||
uint16_t repeat, symNumber, symCount;
|
||||
|
||||
// Get the number of PP16 symbols the frame contains
|
||||
symCount = gDataLength << 1;
|
||||
|
||||
for (repeat = 0; repeat < gRepeat; repeat++) {
|
||||
cli(); // Stop all interrupts to avoid added delay that will interfere with the PPM signal
|
||||
for (symNumber = 0; symNumber < symCount; symNumber++) {
|
||||
|
||||
// Switch to the next byte once the 2 4-bit symbols of the current byte are transmitted
|
||||
if ((symNumber & 1) == 0) {
|
||||
currentByte = gData[symNumber >> 1];
|
||||
}
|
||||
|
||||
sendPPMBurst(PULSES_PP16);
|
||||
|
||||
switch(currentByte & 15) {
|
||||
case 0:
|
||||
_delay_us(gPP16[0]);
|
||||
break;
|
||||
case 1:
|
||||
_delay_us(gPP16[1]);
|
||||
break;
|
||||
case 2:
|
||||
_delay_us(gPP16[2]);
|
||||
break;
|
||||
case 3:
|
||||
_delay_us(gPP16[3]);
|
||||
break;
|
||||
case 4:
|
||||
_delay_us(gPP16[4]);
|
||||
break;
|
||||
case 5:
|
||||
_delay_us(gPP16[5]);
|
||||
break;
|
||||
case 6:
|
||||
_delay_us(gPP16[6]);
|
||||
break;
|
||||
case 7:
|
||||
_delay_us(gPP16[7]);
|
||||
break;
|
||||
case 8:
|
||||
_delay_us(gPP16[8]);
|
||||
break;
|
||||
case 9:
|
||||
_delay_us(gPP16[9]);
|
||||
break;
|
||||
case 10:
|
||||
_delay_us(gPP16[10]);
|
||||
break;
|
||||
case 11:
|
||||
_delay_us(gPP16[11]);
|
||||
break;
|
||||
case 12:
|
||||
_delay_us(gPP16[12]);
|
||||
break;
|
||||
case 13:
|
||||
_delay_us(gPP16[13]);
|
||||
break;
|
||||
case 14:
|
||||
_delay_us(gPP16[14]);
|
||||
break;
|
||||
case 15:
|
||||
_delay_us(gPP16[15]);
|
||||
break;
|
||||
}
|
||||
|
||||
// Switch to the next symbol
|
||||
currentByte >>= 4;
|
||||
}
|
||||
|
||||
sendPPMBurst(PULSES_PP16);
|
||||
sei(); // Allow interrupts
|
||||
|
||||
_delay_ms(2);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void setup() {
|
||||
DDRD |= (1 << LED_PIN); // Define led pin as output
|
||||
PORTD &= (0 << LED_PIN); // Set led pin to low state
|
||||
|
||||
cli(); // Stop all interrupts
|
||||
// Set bit TOIE0 in the TIMSK0 register to zero to disable timer0 interrupt
|
||||
// This was causing randomly and unwanted 5-6us added delay to _delay_us() due to timer overflow
|
||||
TIMSK0 &= ~(1 << TOIE0);
|
||||
sei(); // Allow interrupts
|
||||
|
||||
BT.begin(115200);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void loop() {
|
||||
if (BT.available()) {
|
||||
if (getFrame()) {
|
||||
// Set new PPM frame parameters
|
||||
memcpy(gData, gDataTemp, sizeof(gDataTemp));
|
||||
gDataLength = gDataLengthTemp;
|
||||
gRepeat = gRepeatTemp;
|
||||
gModePP16 = gModePP16Temp;
|
||||
gSendFrame = true;
|
||||
gSentOk = false;
|
||||
}
|
||||
else {
|
||||
// Read all garbage data the Bluetooth module itself may send
|
||||
while (BT.available()) {
|
||||
BT.read();
|
||||
}
|
||||
|
||||
BT.write("1"); // Send an error message to Pricehax if the frame is not properly transmitted
|
||||
|
||||
gSendFrame = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (gSendFrame) {
|
||||
if (gModePP16)
|
||||
sendPP16Frame();
|
||||
else
|
||||
sendPP4CFrame();
|
||||
|
||||
if (!gSentOk) {
|
||||
BT.write("0"); // Send an OK message to Pricehax once the frame is transmitted
|
||||
gSentOk = true;
|
||||
gSendFrame = false;
|
||||
}
|
||||
|
||||
gDataLengthTemp = 0;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user