| | |
| | | <component name="ProjectCodeStyleConfiguration"> |
| | | <code_scheme name="Project" version="173"> |
| | | <Objective-C-extensions> |
| | | <file> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" /> |
| | | </file> |
| | | <class> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" /> |
| | | <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" /> |
| | | </class> |
| | | <extensions> |
| | | <pair source="cpp" header="h" fileNamingConvention="NONE" /> |
| | | <pair source="c" header="h" fileNamingConvention="NONE" /> |
| | | </extensions> |
| | | </Objective-C-extensions> |
| | | <codeStyleSettings language="XML"> |
| | | <arrangement> |
| | | <rules> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>xmlns:android</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>^$</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>xmlns:.*</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>^$</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | <order>BY_NAME</order> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>.*:id</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>.*:name</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>name</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>^$</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>style</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>^$</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>.*</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>^$</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | <order>BY_NAME</order> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>.*</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>http://schemas.android.com/apk/res/android</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | <order>ANDROID_ATTRIBUTE_ORDER</order> |
| | | </rule> |
| | | </section> |
| | | <section> |
| | | <rule> |
| | | <match> |
| | | <AND> |
| | | <NAME>.*</NAME> |
| | | <XML_ATTRIBUTE /> |
| | | <XML_NAMESPACE>.*</XML_NAMESPACE> |
| | | </AND> |
| | | </match> |
| | | <order>BY_NAME</order> |
| | | </rule> |
| | | </section> |
| | | </rules> |
| | | </arrangement> |
| | | </codeStyleSettings> |
| | | </code_scheme> |
| | | </component> |
| | |
| | | |
| | | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" |
| | | |
| | | externalNativeBuild { |
| | | cmake { |
| | | cppFlags "" |
| | | } |
| | | } |
| | | ndk { |
| | | // Specifies the ABI configurations of your native |
| | | // libraries Gradle should build and package with your APK. |
| | | abiFilters 'armeabi-v7a','arm64-v8a' |
| | | } |
| | | } |
| | | |
| | | buildTypes { |
| | |
| | | } |
| | | } |
| | | |
| | | externalNativeBuild { |
| | | cmake { |
| | | path "src/main/cpp/CMakeLists.txt" |
| | | } |
| | | } |
| | | } |
| | | |
| | | dependencies { |
New file |
| | |
| | | # For more information about using CMake with Android Studio, read the |
| | | # documentation: https://d.android.com/studio/projects/add-native-code.html |
| | | |
| | | # Sets the minimum version of CMake required to build the native library. |
| | | |
| | | cmake_minimum_required(VERSION 3.4.1) |
| | | |
| | | # Creates and names a library, sets it as either STATIC |
| | | # or SHARED, and provides the relative paths to its source code. |
| | | # You can define multiple libraries, and CMake builds them for you. |
| | | # Gradle automatically packages shared libraries with your APK. |
| | | |
| | | add_library( # Sets the name of the library. |
| | | native-lib |
| | | |
| | | # Sets the library as a shared library. |
| | | SHARED |
| | | |
| | | # Provides a relative path to your source file(s). |
| | | native-lib.cpp |
| | | common/serial_port.cpp |
| | | common/net.cpp |
| | | common/apptimer.cpp |
| | | rtk_platform/parse_net.cpp |
| | | rtk_platform/platform.cpp |
| | | rtk_module/parse_gps.cpp |
| | | Geometry.cpp |
| | | driver_test.cpp |
| | | mcu/mcu_if.cpp |
| | | test_items/error_list.cpp |
| | | test_items/park_edge.cpp |
| | | test_items/park_bottom.cpp |
| | | test_items/stop_and_start.cpp |
| | | test_items/driving_curve.cpp |
| | | test_items/turn_a90.cpp |
| | | rtk_module/rtk.cpp |
| | | |
| | | utils/crc16.cpp |
| | | utils/num.cpp) |
| | | |
| | | # Searches for a specified prebuilt library and stores the path as a |
| | | # variable. Because CMake includes system libraries in the search path by |
| | | # default, you only need to specify the name of the public NDK library |
| | | # you want to add. CMake verifies that the library exists before |
| | | # completing its build. |
| | | |
| | | find_library( # Sets the name of the path variable. |
| | | log-lib |
| | | |
| | | # Specifies the name of the NDK library that |
| | | # you want CMake to locate. |
| | | log) |
| | | |
| | | # Specifies libraries CMake should link to your target library. You |
| | | # can link multiple libraries, such as libraries you define in this |
| | | # build script, prebuilt third-party libraries, or system libraries. |
| | | |
| | | target_link_libraries( # Specifies the target library. |
| | | native-lib |
| | | |
| | | # Links the target library to the log library |
| | | # included in the NDK. |
| | | ${log-lib}) |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/4/30. |
| | | // |
| | | |
| | | #include "defs.h" |
| | | #include "Geometry.h" |
| | | #include <stdbool.h> |
| | | #include <stdint.h> |
| | | #include <cmath> |
| | | #include <jni.h> |
| | | #include <malloc.h> |
| | | #include <initializer_list> |
| | | |
| | | #include "jni_log.h" |
| | | |
| | | using namespace std; |
| | | |
| | | const double EPSILON = 1e-6; |
| | | |
| | | inline bool isEqual(double a, double b) |
| | | { |
| | | return (fabs(a - b) <= EPSILON); |
| | | } |
| | | |
| | | inline double toRadians(double degree) |
| | | { |
| | | return (degree * M_PI) / 180.0; |
| | | } |
| | | |
| | | inline double toDegree(double radians) |
| | | { |
| | | return (radians * 180.0) / M_PI; |
| | | } |
| | | |
| | | void MakeLine(Line *line, const PointF *p1, const PointF *p2) |
| | | { |
| | | line->X1 = p1->X; |
| | | line->Y1 = p1->Y; |
| | | line->X2 = p2->X; |
| | | line->Y2 = p2->Y; |
| | | } |
| | | |
| | | void MakePolygon(Polygon *polygon, std::initializer_list<PointF> point_set) |
| | | { |
| | | int n = 0; |
| | | |
| | | polygon->point = (PointF *)malloc(point_set.size() * sizeof(PointF)); |
| | | |
| | | for (auto ptr : point_set) { |
| | | polygon->point[n++] = ptr; |
| | | } |
| | | polygon->num = n; |
| | | } |
| | | |
| | | void MakeHidePoint(PointF *point, const PointF *bp, const Line *bl) |
| | | { |
| | | point->X = (bl->X1 + bl->X2) - bp->X; |
| | | point->Y = (bl->Y1 + bl->Y2) - bp->Y; |
| | | } |
| | | |
| | | void CleanPolygon(Polygon *polygon) |
| | | { |
| | | if (polygon->point != NULL) { |
| | | free(polygon->point); |
| | | polygon->point = NULL; |
| | | } |
| | | polygon->num = 0; |
| | | } |
| | | |
| | | Relation IntersectionOf(const Polygon *polygon1, const Polygon *polygon2) |
| | | { |
| | | bool inside = false, outside = false, tangent = false; |
| | | |
| | | if (polygon1->num == 0 || polygon2->num == 0) { |
| | | return GM_None; |
| | | } |
| | | |
| | | for (int idx = 0; idx < polygon1->num; ++idx) { |
| | | Relation relation = IntersectionOf(polygon1->point[idx], polygon2); |
| | | |
| | | if (relation == GM_Containment) { |
| | | inside = true; |
| | | } else if (relation == GM_None) { |
| | | outside = true; |
| | | } else { |
| | | tangent = true; |
| | | } |
| | | |
| | | if (inside && outside) { |
| | | break; |
| | | } |
| | | } |
| | | |
| | | if (inside && outside) { |
| | | return GM_Intersection; |
| | | } else if (tangent) { |
| | | return GM_Tangent; |
| | | } else if (inside) { |
| | | return GM_Containment; |
| | | } |
| | | return GM_None; |
| | | } |
| | | |
| | | Relation IntersectionOf(Line line, const Polygon *polygon) |
| | | { |
| | | if (polygon->num == 0) { |
| | | return GM_None; |
| | | } |
| | | |
| | | if (polygon->num == 1) { |
| | | return IntersectionOf(polygon->point[0], line); |
| | | } |
| | | |
| | | bool tangent = false; |
| | | for (int index = 0; index < polygon->num; index++) { |
| | | int index2 = (index + 1) % polygon->num; |
| | | Line line2; |
| | | |
| | | line2.X1 = polygon->point[index].X; |
| | | line2.Y1 = polygon->point[index].Y; |
| | | line2.X2 = polygon->point[index2].X; |
| | | line2.Y2 = polygon->point[index2].Y; |
| | | |
| | | // LOGD("line1(%d %d - %d %d) line2(%d %d - %d %d)", line.X1, line.Y1, line.X2, line.Y2, |
| | | // line2.X1, line2.Y1, line2.X2, line2.Y2); |
| | | |
| | | Relation relation = IntersectionOf(line, line2); |
| | | |
| | | // LOGD("relation = %d", relation); |
| | | |
| | | if (relation == GM_Intersection) { |
| | | return relation; |
| | | } |
| | | if (relation == GM_Tangent) { |
| | | tangent = true; |
| | | } |
| | | } |
| | | |
| | | PointF point2; |
| | | |
| | | point2.X = line.X1; |
| | | point2.Y = line.Y1; |
| | | |
| | | return tangent ? GM_Tangent : IntersectionOf(point2, polygon); |
| | | } |
| | | |
| | | Relation IntersectionOf(PointF point, const Polygon *polygon) |
| | | { |
| | | switch (polygon->num) |
| | | { |
| | | case 0: |
| | | return GM_None; |
| | | case 1: |
| | | if (isEqual(polygon->point[0].X, point.X) && |
| | | isEqual(polygon->point[0].Y, point.Y)) { |
| | | return GM_Tangent; |
| | | } |
| | | else { |
| | | return GM_None; |
| | | } |
| | | case 2: { |
| | | Line line2; |
| | | |
| | | line2.X1 = polygon->point[0].X; |
| | | line2.Y1 = polygon->point[0].Y; |
| | | line2.X2 = polygon->point[1].X; |
| | | line2.Y2 = polygon->point[1].Y; |
| | | return IntersectionOf(point, line2); |
| | | } |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | int counter = 0; |
| | | int i; |
| | | PointF p1; |
| | | int n = polygon->num; |
| | | |
| | | p1.X = polygon->point[0].X; |
| | | p1.Y = polygon->point[0].Y; |
| | | |
| | | if (isEqual(point.X, p1.X) && isEqual(point.Y, p1.Y)) { |
| | | return GM_Tangent; |
| | | } |
| | | |
| | | for (i = 1; i <= n; i++) { |
| | | PointF p2; |
| | | |
| | | p2.X = polygon->point[i % n].X; |
| | | p2.Y = polygon->point[i % n].Y; |
| | | |
| | | if (isEqual(point.X, p2.X) && isEqual(point.Y, p2.Y)) { |
| | | return GM_Tangent; |
| | | } |
| | | |
| | | if (point.Y > fmin(p1.Y, p2.Y)) { |
| | | if (point.Y <= fmax(p1.Y, p2.Y)) { |
| | | if (point.X <= fmax(p1.X, p2.X)) { |
| | | if (p1.Y != p2.Y) { |
| | | double xinters = (point.Y - p1.Y) * (p2.X - p1.X) / (p2.Y - p1.Y) + p1.X; |
| | | |
| | | if (isEqual(p1.X, p2.X) || point.X <= xinters) |
| | | counter++; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | p1 = p2; |
| | | } |
| | | |
| | | return (counter % 2 == 1) ? GM_Containment : GM_None; |
| | | } |
| | | |
| | | Relation IntersectionOf(PointF point, Line line) |
| | | { |
| | | double bottomY = fmin(line.Y1, line.Y2); |
| | | double topY = fmax(line.Y1, line.Y2); |
| | | bool heightIsRight = point.Y >= bottomY && |
| | | point.Y <= topY; |
| | | //Vertical line, slope is divideByZero error! |
| | | if (isEqual(line.X1, line.X2)) { |
| | | if (isEqual(point.X, line.X1) && heightIsRight) { |
| | | return GM_Tangent; |
| | | } else { |
| | | return GM_None; |
| | | } |
| | | } |
| | | |
| | | double slope = (line.X2 - line.X1) / (line.Y2 - line.Y1); |
| | | bool onLine = isEqual(line.Y1 - point.Y, slope * (line.X1 - point.X)); |
| | | |
| | | if (onLine && heightIsRight) { |
| | | return GM_Tangent; |
| | | } else { |
| | | return GM_None; |
| | | } |
| | | } |
| | | |
| | | Relation IntersectionOf(Line line1, Line line2) |
| | | { |
| | | // Fail if either line segment is zero-length. |
| | | if ((isEqual(line1.X1, line1.X2) && isEqual(line1.Y1, line1.Y2)) || (isEqual(line2.X1, line2.X2) && isEqual(line2.Y1, line2.Y2))) |
| | | return GM_None; |
| | | |
| | | if ((isEqual(line1.X1, line2.X1) && isEqual(line1.Y1, line2.Y1)) || (isEqual(line1.X2, line2.X1) && isEqual(line1.Y2, line2.Y1))) |
| | | return GM_Intersection; |
| | | |
| | | if ((isEqual(line1.X1, line2.X2) && isEqual(line1.Y1, line2.Y2)) || (isEqual(line1.X2, line2.X2) && isEqual(line1.Y2, line2.Y2))) |
| | | return GM_Intersection; |
| | | |
| | | // (1) Translate the system so that point A is on the origin. |
| | | line1.X2 -= line1.X1; line1.Y2 -= line1.Y1; |
| | | line2.X1 -= line1.X1; line2.Y1 -= line1.Y1; |
| | | line2.X2 -= line1.X1; line2.Y2 -= line1.Y1; |
| | | |
| | | // Discover the length of segment A-B. |
| | | double distAB = sqrt(line1.X2 * line1.X2 + line1.Y2 * line1.Y2); |
| | | |
| | | // (2) Rotate the system so that point B is on the positive X axis. |
| | | double theCos = line1.X2 / distAB; |
| | | double theSin = line1.Y2 / distAB; |
| | | double newX = line2.X1 * theCos + line2.Y1 * theSin; |
| | | |
| | | line2.Y1 = line2.Y1 * theCos - line2.X1 * theSin; |
| | | line2.X1 = newX; |
| | | newX = line2.X2 * theCos + line2.Y2 * theSin; |
| | | line2.Y2 = line2.Y2 * theCos - line2.X2 * theSin; |
| | | line2.X2 = newX; |
| | | |
| | | // Fail if segment C-D doesn't cross line A-B. |
| | | if ((line2.Y1 < 0 && line2.Y2 < 0) || (line2.Y1 >= 0 && line2.Y2 >= 0)) { |
| | | return GM_None; |
| | | } |
| | | |
| | | // (3) Discover the position of the intersection point along line A-B. |
| | | double posAB = line2.X2 + (line2.X1 - line2.X2) * line2.Y2 / (line2.Y2 - line2.Y1); |
| | | |
| | | // Fail if segment C-D crosses line A-B outside of segment A-B. |
| | | if (posAB < 0 || posAB > distAB) { |
| | | return GM_None; |
| | | } |
| | | // (4) Apply the discovered position to line A-B in the original coordinate system. |
| | | return GM_Intersection; |
| | | } |
| | | |
| | | double DistanceOf(PointF point1, PointF point2) |
| | | { |
| | | return sqrt((point1.X-point2.X)*(point1.X-point2.X) + (point1.Y-point2.Y)*(point1.Y-point2.Y)); |
| | | } |
| | | |
| | | double DistanceOf(PointF point, Line line) |
| | | { |
| | | // float a = sqrt((point.X-line.X1)*(point.X-line.X1) + (point.Y-line.Y1)*(point.Y-line.Y1)); |
| | | // float b = sqrt((point.X-line.X2)*(point.X-line.X2) + (point.Y-line.Y2)*(point.Y-line.Y2)); |
| | | double c = sqrt((line.X1-line.X2)*(line.X1-line.X2) + (line.Y1-line.Y2)*(line.Y1-line.Y2)); |
| | | |
| | | // float p = (a+b+c)/2; |
| | | |
| | | // dis = 2 * sqrt(p*(p-a)*(p-b)*(p-c)) / c; |
| | | |
| | | return fabs(point.X*line.Y1 + point.Y*line.X2 + line.X1*line.Y2 - line.X2*line.Y1 - line.X1*point.Y - point.X*line.Y2) / c; |
| | | } |
| | | |
| | | /********************************************************** |
| | | * base 和 dest的第二点重合时形成的夹角 |
| | | * @param base |
| | | * @param dest |
| | | * @return |
| | | */ |
| | | double CalculateAngle(Line base, Line dest) |
| | | { |
| | | double angle = 0; |
| | | |
| | | double dx = base.X2 - dest.X2; |
| | | double dy = base.Y2 - dest.Y2; |
| | | |
| | | dest.X1 += dx; |
| | | dest.Y1 += dy; |
| | | |
| | | double c2 = pow((dest.X1 - base.X1), 2) + pow((dest.Y1 - base.Y1), 2); |
| | | double a2 = pow((base.X1 - base.X2), 2) + pow((base.Y1 - base.Y2), 2); |
| | | double b2 = pow((dest.X1 - base.X2), 2) + pow((dest.Y1 - base.Y2), 2); |
| | | |
| | | angle = acos((a2 + b2 - c2) / (2 * sqrt(a2) * sqrt(b2))); |
| | | |
| | | return toDegree(angle); |
| | | } |
| | | |
| | | PointF rotatePoint(PointF oldPoint, PointF centre, double degree) { |
| | | PointF newPoint; |
| | | newPoint.X = (oldPoint.X-centre.X)*cos(toRadians(degree)) - (oldPoint.Y-centre.Y)*sin(toRadians(degree)) + centre.X; |
| | | newPoint.Y = (oldPoint.X-centre.X)*sin(toRadians(degree)) + (oldPoint.Y-centre.Y)*cos(toRadians(degree)) + centre.Y; |
| | | return newPoint; |
| | | } |
| | | |
| | | // All in |
| | | bool InsidePolygon(const Polygon *t1, const Polygon *t2) { |
| | | for (int i = 0; i < t1->num; ++i) { |
| | | if (IntersectionOf(t1->point[i], t2) != GM_Containment) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // Any part inside |
| | | bool PartInsidePolygon(const Polygon *t1, const Polygon *t2) { |
| | | for (int i = 0; i < t1->num; ++i) { |
| | | if (IntersectionOf(t1->point[i], t2) == GM_Containment) { |
| | | return true; |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | // All out |
| | | bool OutsidePolygon(const Polygon *t1, const Polygon *t2) { |
| | | for (int i = 0; i < t1->num; ++i) { |
| | | if (IntersectionOf(t1->point[i], t2) != GM_None) { |
| | | return false; |
| | | } |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | /*************************************************************** |
| | | * @brief p3位于由p1->p2构成的射线,左侧还是右侧,同向,反向 |
| | | * @param p1 |
| | | * @param p2 |
| | | * @param p3 |
| | | * @return 0 - straight, 1 - left, -1 - right, 2 - front, -2 - back |
| | | */ |
| | | int IntersectionOfLine(PointF p1, PointF p2, PointF p3) |
| | | { |
| | | double lr = (p1.X-p3.X)*(p2.Y-p3.Y) - (p1.Y-p3.Y)*(p2.X-p3.X); |
| | | |
| | | if (fabs(lr) <= EPSILON) { |
| | | double fb = (p2.X-p1.X)*(p3.X-p1.X) + (p2.Y-p1.Y)*(p3.Y-p1.Y); |
| | | if (fabs(fb) <= EPSILON) |
| | | return 0; |
| | | else if (fb > 0) |
| | | return 2; |
| | | else |
| | | return -2; |
| | | } else if (lr > 0) { |
| | | return 1; |
| | | } else { |
| | | return -1; |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/4/30. |
| | | // |
| | | |
| | | #ifndef GUI_GEOMETRY_H |
| | | #define GUI_GEOMETRY_H |
| | | |
| | | #include <stdint.h> |
| | | #include <initializer_list> |
| | | |
| | | enum Relation |
| | | { |
| | | GM_None, |
| | | GM_Tangent, |
| | | GM_Intersection, |
| | | GM_Containment |
| | | }; |
| | | |
| | | typedef struct PointF_ { |
| | | double X; |
| | | double Y; |
| | | } PointF; |
| | | |
| | | typedef struct Line_ { |
| | | double X1; |
| | | double Y1; |
| | | double X2; |
| | | double Y2; |
| | | } Line; |
| | | |
| | | typedef struct Polygon_ { |
| | | int num; |
| | | PointF *point; |
| | | } Polygon; |
| | | |
| | | inline double toRadians(double degree); |
| | | inline double toDegree(double radians); |
| | | inline bool isEqual(double a, double b); |
| | | void MakeLine(Line *line, const PointF *p1, const PointF *p2); |
| | | void MakePolygon(Polygon *polygon, std::initializer_list<PointF> point_set); |
| | | void CleanPolygon(Polygon *polygon); |
| | | void MakeHidePoint(PointF *point, const PointF *bp, const Line *bl); |
| | | |
| | | Relation IntersectionOf(const Polygon *polygon1, const Polygon *polygon2); |
| | | Relation IntersectionOf(Line line, const Polygon *polygon); |
| | | Relation IntersectionOf(PointF point, const Polygon *polygon); |
| | | Relation IntersectionOf(PointF point, Line line); |
| | | Relation IntersectionOf(Line line1, Line line2); |
| | | double DistanceOf(PointF point1, PointF point2); |
| | | double DistanceOf(PointF point, Line line); |
| | | double CalculateAngle(Line base, Line dest); |
| | | PointF rotatePoint(PointF oldPoint, PointF centre, double degree); |
| | | bool InsidePolygon(const Polygon *t1, const Polygon *t2); |
| | | bool PartInsidePolygon(const Polygon *t1, const Polygon *t2); |
| | | bool OutsidePolygon(const Polygon *t1, const Polygon *t2); |
| | | int IntersectionOfLine(PointF p1, PointF p2, PointF p3); |
| | | |
| | | #endif //GUI_GEOMETRY_H |
New file |
| | |
| | | //POSIX.1b Timer |
| | | #include <jni.h> |
| | | #include <stdbool.h> |
| | | #include <stdint.h> |
| | | #include <stdio.h> |
| | | #include <stdlib.h> |
| | | #include <unistd.h> |
| | | #include <signal.h> |
| | | #include <string.h> |
| | | #include <sys/time.h> |
| | | #include <pthread.h> |
| | | #include <errno.h> |
| | | #include <time.h> |
| | | #include "../jni_log.h" |
| | | #include "apptimer.h" |
| | | |
| | | #define MAX_TIMER 32 |
| | | |
| | | static struct { |
| | | timer_t timerId; |
| | | |
| | | void (*func)(union sigval sig); |
| | | |
| | | int value; |
| | | uint8_t *user_data; |
| | | } AppTimer[MAX_TIMER]; |
| | | |
| | | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | |
| | | static int createTimer(timer_t *timerId, void (*func)(union sigval sig), |
| | | int value, |
| | | uint8_t *usr_data, int usr_data_length, |
| | | uint8_t **usr_data_ptr) { |
| | | struct sigevent sev; |
| | | pthread_attr_t attr; |
| | | |
| | | // Register printMsg to SIGALRM |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | |
| | | memset(&sev, 0, sizeof(sev)); |
| | | |
| | | sev.sigev_notify = SIGEV_THREAD; |
| | | sev.sigev_notify_function = func; |
| | | sev.sigev_notify_attributes = &attr; |
| | | |
| | | if (usr_data != NULL && usr_data_length != 0) { |
| | | if ((sev.sigev_value.sival_ptr = malloc(usr_data_length)) != NULL) { |
| | | *usr_data_ptr = (uint8_t *) sev.sigev_value.sival_ptr; |
| | | memcpy(sev.sigev_value.sival_ptr, usr_data, usr_data_length); //Copy usr data |
| | | sev.sigev_value.sival_int = usr_data_length; |
| | | } else { |
| | | return -1; |
| | | } |
| | | } else { |
| | | sev.sigev_value.sival_int = value; |
| | | } |
| | | |
| | | /* create timer */ |
| | | if (timer_create(CLOCK_REALTIME, &sev, timerId) == -1) { |
| | | return -1; |
| | | } |
| | | // LOGD("timer_create\n"); |
| | | return 0; |
| | | } |
| | | |
| | | static int setTimer(timer_t timerId, int timeMSec) { |
| | | struct itimerspec its; |
| | | |
| | | /* Start the timer */ |
| | | its.it_value.tv_sec = timeMSec / 1000; |
| | | its.it_value.tv_nsec = (timeMSec % 1000) * 1000000; |
| | | |
| | | its.it_interval.tv_sec = 0; |
| | | its.it_interval.tv_nsec = 0; |
| | | |
| | | if (timer_settime(timerId, 0, &its, NULL) == -1) { |
| | | return -1; |
| | | } |
| | | // LOGD("timer_settime\n"); |
| | | return 0; |
| | | } |
| | | |
| | | void AppTimer_Init(void) { |
| | | memset(AppTimer, 0, sizeof(AppTimer)); |
| | | pthread_mutex_init(&mutex, NULL); |
| | | } |
| | | |
| | | void AppTimer_add(void (*func)(union sigval), int timeMS) { |
| | | int i; |
| | | // LOGD("AppTimer_add\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == NULL) { |
| | | if (createTimer(&(AppTimer[i].timerId), func, 0, NULL, 0, &(AppTimer[i].user_data)) == 0) { |
| | | AppTimer[i].func = func; |
| | | |
| | | if (setTimer(AppTimer[i].timerId, timeMS) != |
| | | 0) { //Set timer fail, delele it |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | void AppTimer_add(void (*func)(union sigval), int timeMS, uint8_t *data, int length) { |
| | | int i; |
| | | // LOGD("AppTimer_add\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == NULL) { |
| | | if (createTimer(&(AppTimer[i].timerId), func, 0, data, length, &(AppTimer[i].user_data)) == 0) { |
| | | AppTimer[i].func = func; |
| | | |
| | | if (setTimer(AppTimer[i].timerId, timeMS) != |
| | | 0) { //Set timer fail, delele it |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | void AppTimer_add(void (*func)(union sigval), int timeMS, int value) { |
| | | int i; |
| | | // LOGD("AppTimer_add\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == NULL) { |
| | | if (createTimer(&(AppTimer[i].timerId), func, value, NULL, 0, &(AppTimer[i].user_data)) == 0) { |
| | | AppTimer[i].func = func; |
| | | |
| | | if (setTimer(AppTimer[i].timerId, timeMS) != |
| | | 0) { //Set timer fail, delele it |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | void AppTimer_delete(void (*func)(union sigval)) { |
| | | int i; |
| | | // LOGD("AppTimer_delete\n"); |
| | | pthread_mutex_lock(&mutex); |
| | | for (i = 0; i < MAX_TIMER; i++) { |
| | | if (AppTimer[i].func == func) { |
| | | timer_delete(AppTimer[i].timerId); |
| | | if (AppTimer[i].user_data != NULL) { |
| | | free(AppTimer[i].user_data); |
| | | AppTimer[i].user_data = NULL; |
| | | } |
| | | AppTimer[i].func = NULL; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&mutex); |
| | | } |
| | | |
| | | uint32_t AppTimer_GetTickCount(void) |
| | | { |
| | | struct timespec ts; |
| | | |
| | | clock_gettime(CLOCK_MONOTONIC, &ts); |
| | | |
| | | return (ts.tv_sec * 1000 + ts.tv_nsec / 1000000); |
| | | } |
New file |
| | |
| | | #ifndef _APPTIMER_H_ |
| | | #define _APPTIMER_H_ |
| | | |
| | | #include <stdint.h> |
| | | #include <signal.h> |
| | | |
| | | #define D_SEC(n) ((n)*1000UL) |
| | | #define D_MIN(n) ((n)*1000UL*60UL) |
| | | #define D_HOUR(n) ((n)*1000UL*60UL*60UL) |
| | | |
| | | extern void AppTimer_Init(void); |
| | | |
| | | extern void AppTimer_add(void (*func)(union sigval), int timeMS); |
| | | |
| | | extern void AppTimer_add(void (*func)(union sigval), int timeMS, uint8_t *data, int length); |
| | | |
| | | extern void AppTimer_add(void (*func)(union sigval), int timeMS, int value); |
| | | |
| | | extern void AppTimer_delete(void (*func)(union sigval)); |
| | | |
| | | extern uint32_t AppTimer_GetTickCount(void); |
| | | |
| | | #endif |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/9/29. |
| | | // |
| | | |
| | | #include <netdb.h> |
| | | #include <cstring> |
| | | #include <netinet/tcp.h> |
| | | #include <unistd.h> |
| | | #include <netinet/in.h> |
| | | #include <cstdio> |
| | | #include <cerrno> |
| | | #include <sys/select.h> |
| | | #include <arpa/inet.h> |
| | | #include <regex> |
| | | #include <pthread.h> |
| | | |
| | | #include "net.h" |
| | | #include "../jni_log.h" |
| | | |
| | | using namespace std; |
| | | |
| | | /************************************************************* |
| | | host_name:domain name |
| | | net_addr:return numbers-and-dots notation |
| | | */ |
| | | int GetHostIP(const char *host_name, char *net_addr) |
| | | { |
| | | struct hostent *hptr; |
| | | char **pptr; |
| | | char str[32]; |
| | | bool found_first = false; |
| | | |
| | | if ((hptr = gethostbyname(host_name)) == NULL) { |
| | | LOGE("gethostbyname error\n"); |
| | | return -1; |
| | | } |
| | | |
| | | LOGD("official hostname: %s\n", hptr->h_name); |
| | | |
| | | for (pptr = hptr->h_aliases; *pptr != NULL; pptr++) { |
| | | LOGD("alias:%s\n", *pptr); |
| | | } |
| | | |
| | | switch(hptr->h_addrtype) |
| | | { |
| | | case AF_INET: |
| | | { |
| | | for (pptr = hptr->h_addr_list; *pptr != NULL; pptr++) { |
| | | LOGD("addrsss:%s\n", inet_ntop(hptr->h_addrtype, *pptr, str, sizeof(str))); |
| | | if (!found_first) { |
| | | strcpy(net_addr, str); |
| | | found_first = true; |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | case AF_INET6: |
| | | default: |
| | | LOGD("unknown address type\n"); |
| | | break; |
| | | } |
| | | |
| | | if (found_first == true) { |
| | | return 0; |
| | | } |
| | | return -2; |
| | | } |
| | | |
| | | static bool is_domain_name(const char *ip) |
| | | { |
| | | regex pattern0("^((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})(\\.((2(5[0-5]|[0-4]\\d))|[0-1]?\\d{1,2})){3}$"); |
| | | string target(ip); |
| | | |
| | | return !regex_match(target, pattern0); |
| | | } |
| | | |
| | | static int socket_set_keepalive(int fd) |
| | | { |
| | | int alive, idle, cnt, intv; |
| | | |
| | | // int value, value_len; |
| | | // getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &value, &value_len); |
| | | // LOGD("keepalive 0 %d", value); |
| | | |
| | | // value = 128; |
| | | // setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, sizeof(value)); |
| | | // LOGD("keepalive 1 %d", value); |
| | | |
| | | // getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &value, &value_len); |
| | | // LOGD("keepalive 1 %d", value); |
| | | |
| | | |
| | | /* Set: use keepalive on fd, default 0 */ |
| | | alive = 1; |
| | | if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &alive, sizeof(alive)) != 0) |
| | | { |
| | | LOGE("TCP Set keepalive error"); |
| | | return -1; |
| | | } |
| | | /* 20 Seconds not data, send keeplive packet, default 7200 */ |
| | | idle = 20; |
| | | if (setsockopt (fd, SOL_TCP, TCP_KEEPIDLE, &idle, sizeof(idle)) != 0) |
| | | { |
| | | LOGE("TCP Set keepalive idle error"); |
| | | return -1; |
| | | } |
| | | /* If not recv respond, After 5 seconds retry, default 75 */ |
| | | intv = 5; |
| | | if (setsockopt (fd, SOL_TCP, TCP_KEEPINTVL, &intv, sizeof(intv)) != 0) |
| | | { |
| | | LOGE("TCP Set keepalive intv error"); |
| | | return -1; |
| | | } |
| | | /* If try 9 times and fail, we consider the tcp is disconnected, default 9 */ |
| | | cnt = 9; |
| | | if (setsockopt (fd, SOL_TCP, TCP_KEEPCNT, &cnt, sizeof(cnt)) != 0) |
| | | { |
| | | LOGE("TCP Set keepalive cnt error"); |
| | | return -1; |
| | | } |
| | | |
| | | /* int timeout = 10000; // 10秒 |
| | | if (setsockopt (fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &timeout, sizeof(timeout)) != 0) |
| | | { |
| | | LOGE("TCP Set keepalive timeout error"); |
| | | return -1; |
| | | }*/ |
| | | |
| | | LOGD("TCP Set keepalive OK"); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int tcp_connect(char *ip, uint16_t port) |
| | | { |
| | | struct sockaddr_in server_sockaddr; |
| | | int soc; |
| | | int ret, fds_ret; |
| | | struct timeval tv; |
| | | fd_set rdfds; |
| | | long arg; |
| | | int error_value; |
| | | socklen_t error_value_len; |
| | | |
| | | LOGI("%s", __func__); |
| | | |
| | | error_value_len = sizeof( error_value ); |
| | | |
| | | if((soc = socket(PF_INET, SOCK_STREAM, 0)) == -1) |
| | | { |
| | | LOGE("%s: socket", __func__); |
| | | return -1; |
| | | } |
| | | |
| | | server_sockaddr.sin_family = AF_INET; |
| | | server_sockaddr.sin_addr.s_addr = inet_addr(ip);//htonl(ip);//inet_addr("192.168.1.37"); |
| | | server_sockaddr.sin_port = htons(port); |
| | | bzero(&server_sockaddr.sin_zero, 8); |
| | | |
| | | // Set non-blocking |
| | | if( (arg = fcntl(soc, F_GETFL, NULL)) < 0) |
| | | { |
| | | LOGE("%s: fcntl( F_GETFL ) error", __func__); |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | |
| | | if( fcntl(soc, F_SETFL, arg | O_NONBLOCK) < 0) |
| | | { |
| | | LOGE( "%s: fcntl( F_SETFL ) error", __func__); |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | |
| | | ret = connect(soc, (struct sockaddr*)&server_sockaddr, sizeof(struct sockaddr)); |
| | | |
| | | if(ret < 0) |
| | | { |
| | | if(errno != EINPROGRESS) //It usually return this error! |
| | | { |
| | | /* |
| | | * connect error: Connection refused |
| | | * |
| | | * perror( "connect error" ); |
| | | */ |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | } |
| | | else if(ret == 0) |
| | | { |
| | | goto TCP_CONNECT_0; |
| | | } |
| | | |
| | | tv.tv_sec = 10; //Connect Timeout |
| | | tv.tv_usec = 0; |
| | | FD_ZERO(&rdfds); |
| | | FD_SET(soc, &rdfds); |
| | | |
| | | fds_ret = select(soc + 1, NULL, &rdfds, NULL, &tv); |
| | | |
| | | if(fds_ret < 0) |
| | | { |
| | | LOGE( "%s: TCP select error", __func__); |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | else if(fds_ret == 0) |
| | | { |
| | | LOGE("%s: TCP Connect Timeout %ld", __func__, tv.tv_sec); |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | else if(FD_ISSET(soc, &rdfds)) |
| | | { |
| | | if(getsockopt(soc, SOL_SOCKET, SO_ERROR, &error_value, &error_value_len) < 0) |
| | | { |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LOGE("%s: some error occur in tcp_connect()", __func__); |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | |
| | | TCP_CONNECT_0: |
| | | // if ( fcntl( soc, F_SETFL, arg ) < 0 ) |
| | | // { |
| | | // perror( "fcntl( F_SETFL ) error" ); |
| | | // goto TCP_CONNECT_1; |
| | | // } |
| | | |
| | | if ( error_value != 0 ) |
| | | { |
| | | /* |
| | | * Error: Connection refused |
| | | * |
| | | * fprintf( stderr, "Error: %s", strerror( error_value ) ); |
| | | */ |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | |
| | | if(socket_set_keepalive(soc) != 0) |
| | | { |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | |
| | | arg &= ~O_NONBLOCK; |
| | | if( fcntl(soc, F_SETFL, arg) < 0) |
| | | { |
| | | LOGE( "%s: fcntl( F_SETFL ) error", __func__); |
| | | goto TCP_CONNECT_1; |
| | | } |
| | | |
| | | LOGI("%s: tcp connected %s: %d", __func__, ip, port); |
| | | |
| | | return( soc ); |
| | | |
| | | TCP_CONNECT_1: |
| | | close( soc ); |
| | | return( -1 ); |
| | | } |
| | | |
| | | static int udp_connect(const char *ip, uint16_t port) { |
| | | struct sockaddr_in server_sockaddr; |
| | | int soc; |
| | | int opt; |
| | | int arg; |
| | | |
| | | if ((soc = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { |
| | | return -1; |
| | | } |
| | | |
| | | /*Enable send broadcast packet*/ |
| | | opt = 1; |
| | | if (setsockopt(soc, SOL_SOCKET, SO_BROADCAST, &opt, sizeof(opt)) != 0) { |
| | | perror("setsockopt"); |
| | | close(soc); |
| | | return -1; |
| | | } |
| | | |
| | | // Set non-blocking |
| | | if( (arg = fcntl(soc, F_GETFL, NULL)) < 0 ) { |
| | | close(soc); |
| | | return -1; |
| | | } |
| | | |
| | | if ( fcntl(soc, F_SETFL, arg | O_NONBLOCK) < 0 ) { |
| | | close(soc); |
| | | return -1; |
| | | } |
| | | |
| | | server_sockaddr.sin_family = AF_INET; |
| | | server_sockaddr.sin_addr.s_addr = inet_addr(ip);//htonl(INADDR_ANY); |
| | | server_sockaddr.sin_port = htons(port); |
| | | bzero(&server_sockaddr.sin_zero, 8); |
| | | |
| | | return soc; |
| | | } |
| | | |
| | | int WriteTCP(int fd, const uint8_t * buf, uint32_t len) |
| | | { |
| | | int ret = 0; |
| | | int fds_ret; |
| | | struct timeval tv; |
| | | fd_set rdfds; |
| | | |
| | | if (fd < 0) |
| | | return -2; |
| | | |
| | | /******************************************************* |
| | | TCP send with nonblock, if occur failure(such as line disconnect...), |
| | | will send timeout, so terminate TCP. |
| | | */ |
| | | tv.tv_sec = 5; |
| | | tv.tv_usec = 0; |
| | | |
| | | FD_ZERO(&rdfds); //clean |
| | | FD_SET(fd, &rdfds); //set |
| | | |
| | | fds_ret = select(fd + 1, NULL, &rdfds, NULL, &tv); |
| | | |
| | | if (fds_ret < 0) { |
| | | LOGE("tcp error send select error"); |
| | | return -1; |
| | | } else if(fds_ret == 0) { |
| | | LOGE("tcp error Occur failure(such as line disconnect)"); |
| | | //Occur failure(such as line disconnect) |
| | | ret = -1; |
| | | } else if(FD_ISSET(fd, &rdfds)) { |
| | | ret = send(fd, buf, len, 0); |
| | | if(ret == -1) { |
| | | LOGE("tcp error TCP Send Error"); |
| | | } |
| | | } else { |
| | | LOGE("tcp error tcp send has error\n"); |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | int ReadTCP(int fd, uint8_t * buf, uint32_t len) |
| | | { |
| | | if (fd < 0) { |
| | | return -2; |
| | | } |
| | | |
| | | int recvLen = recv(fd, buf, len, 0); //read socket data from server |
| | | |
| | | if (recvLen == 0) { |
| | | LOGW("tcp error TCP disconnected 0 errno = %d", errno); |
| | | return -1; |
| | | } else if (recvLen < 0) { |
| | | if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) { |
| | | return 0; |
| | | } else { |
| | | LOGW("tcp error TCP disconnected errno = %d", errno);; |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | return recvLen; |
| | | } |
| | | |
| | | int ConnectTCP(const char *ip, uint16_t port) |
| | | { |
| | | char net_addr[32] = {0}; |
| | | |
| | | if (is_domain_name(ip)) { |
| | | if (GetHostIP(ip, net_addr) != 0) { |
| | | return -3; |
| | | } |
| | | } else { |
| | | strcpy(net_addr, ip); |
| | | } |
| | | |
| | | return tcp_connect(net_addr, port); |
| | | } |
| | | |
| | | void DisconnectTCP(int fd) |
| | | { |
| | | LOGI("DisconnectTCP fd = %d", fd); |
| | | if (fd >= 0) { |
| | | shutdown(fd, SHUT_RDWR); |
| | | close(fd); |
| | | } |
| | | } |
| | | |
| | | int EstablishUDP(const char *ip, uint16_t port) |
| | | { |
| | | char net_addr[32] = {0}; |
| | | |
| | | if (is_domain_name(ip)) { |
| | | if (GetHostIP(ip, net_addr) != 0) { |
| | | return -3; |
| | | } |
| | | } else { |
| | | strcpy(net_addr, ip); |
| | | } |
| | | |
| | | return udp_connect(net_addr, port); |
| | | } |
| | | |
| | | void RemoveUDP(int fd) |
| | | { |
| | | close(fd); |
| | | } |
| | | |
| | | int WriteUDP(int fd, char *ip, uint16_t port, const uint8_t * buf, uint32_t len) |
| | | { |
| | | int ret = 0; |
| | | int fds_ret; |
| | | struct timeval tv; |
| | | fd_set rdfds; |
| | | |
| | | if (fd < 0) |
| | | return -2; |
| | | |
| | | /******************************************************* |
| | | TCP send with nonblock, if occur failure(such as line disconnect...), |
| | | will send timeout, so terminate TCP. |
| | | */ |
| | | tv.tv_sec = 5; |
| | | tv.tv_usec = 0; |
| | | |
| | | FD_ZERO(&rdfds); //clean |
| | | FD_SET(fd, &rdfds); //set |
| | | |
| | | fds_ret = select(fd + 1, NULL, &rdfds, NULL, &tv); |
| | | |
| | | if (fds_ret < 0) |
| | | { |
| | | LOGE("UDP send select error"); |
| | | return -1; |
| | | } |
| | | else if(fds_ret == 0) |
| | | { |
| | | LOGE("Occur failure(such as line disconnect)"); |
| | | ret = -1; |
| | | } |
| | | else if(FD_ISSET(fd, &rdfds)) |
| | | { |
| | | struct sockaddr_in server_sockaddr; |
| | | |
| | | server_sockaddr.sin_family = AF_INET; |
| | | server_sockaddr.sin_addr.s_addr = inet_addr(ip);//htonl(INADDR_ANY); |
| | | server_sockaddr.sin_port = htons(port); |
| | | bzero(&server_sockaddr.sin_zero, 8); |
| | | |
| | | ret = sendto(fd, buf, len, 0, (struct sockaddr *)&server_sockaddr, sizeof(struct sockaddr_in)); |
| | | |
| | | if(ret == -1) |
| | | { |
| | | LOGE("UDP Send Error"); |
| | | } |
| | | } |
| | | else |
| | | { |
| | | LOGE("UDP send has error\n"); |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | int ReadUDP(int fd, uint8_t * buf, uint32_t len) |
| | | { |
| | | struct sockaddr_in from_addr; |
| | | socklen_t from_len; |
| | | |
| | | int recvLen = recvfrom(fd, buf, len, 0, |
| | | (struct sockaddr *) &from_addr, |
| | | &from_len);//read socket data from server// |
| | | |
| | | if (recvLen == 0) { |
| | | return 0; |
| | | } else if (recvLen < 0) { |
| | | if (errno == EINTR || errno == EWOULDBLOCK || errno == EAGAIN) { |
| | | return 0; |
| | | } else { |
| | | LOGE("UDP ERROR!! = %d", errno); |
| | | return -1; |
| | | } |
| | | } |
| | | |
| | | return recvLen; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/9/29. |
| | | // |
| | | |
| | | #ifndef RTKBASESTATION_NET_H |
| | | #define RTKBASESTATION_NET_H |
| | | |
| | | int WriteTCP(int fd, const uint8_t * buf, uint32_t len); |
| | | int ReadTCP(int fd, uint8_t * buf, uint32_t len); |
| | | int ConnectTCP(const char *ip, uint16_t port); |
| | | void DisconnectTCP(int fd); |
| | | int EstablishUDP(const char *ip, uint16_t port); |
| | | void RemoveUDP(int fd); |
| | | int WriteUDP(int fd, char *ip, uint16_t port, const uint8_t * buf, uint32_t len); |
| | | int ReadUDP(int fd, uint8_t * buf, uint32_t len); |
| | | |
| | | #endif //RTKBASESTATION_NET_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2017/9/5. |
| | | // |
| | | |
| | | #include <jni.h> |
| | | #include <string> |
| | | |
| | | #include <sys/stat.h> |
| | | #include <stdbool.h> |
| | | #include <stdint.h> |
| | | #include <termios.h> |
| | | #include <android/log.h> |
| | | #include <sys/ioctl.h> |
| | | #include <unistd.h> |
| | | #include <sys/types.h> |
| | | #include <sys/stat.h> |
| | | #include <fcntl.h> |
| | | #include <pthread.h> |
| | | #include "../jni_log.h" |
| | | #include "serial_port.h" |
| | | |
| | | using namespace std; |
| | | |
| | | static volatile int serial_port_fd[2] = {0, 0}; |
| | | static pthread_mutex_t mutex[2] = {PTHREAD_MUTEX_INITIALIZER, PTHREAD_MUTEX_INITIALIZER}; |
| | | |
| | | int setRTS(int fd, int level) |
| | | { |
| | | int status; |
| | | |
| | | if (ioctl(fd, TIOCMGET, &status) == -1) { |
| | | LOGD("setRTS(): TIOCMGET"); |
| | | return 0; |
| | | } |
| | | if (level) |
| | | status |= TIOCM_RTS; |
| | | else |
| | | status &= ~TIOCM_RTS; |
| | | |
| | | if (ioctl(fd, TIOCMSET, &status) == -1) { |
| | | LOGD("setRTS(): TIOCMSET"); |
| | | return 0; |
| | | } |
| | | return 1; |
| | | } |
| | | |
| | | /********************************************************************* |
| | | * PUBLIC FUNCTIONS |
| | | */ |
| | | static int SetSerialPort(int fd, int speed, int databits, char parity, int stopbits, int flowctrl) { |
| | | int status = 0; |
| | | struct termios opt; |
| | | int speed_arr[] = {B921600, B576000, B500000, B460800, B230400, B115200, B38400, B19200, |
| | | B9600, B4800, B2400, B1200, B300}; |
| | | int name_arr[] = {921600, 576000, 500000, 460800, 230400, 115200, 38400, 19200, 9600, 4800, |
| | | 2400, 1200, 300}; |
| | | |
| | | status = tcgetattr(fd, &opt); |
| | | if (status != 0) { |
| | | goto SET_SERIAL_PORT_END; |
| | | } |
| | | |
| | | status = tcflush(fd, TCIOFLUSH); |
| | | if (status != 0) { |
| | | goto SET_SERIAL_PORT_END; |
| | | } |
| | | //Set baud |
| | | for (int i = 0; i < sizeof(speed_arr) / sizeof(int); i++) { |
| | | if (speed == name_arr[i]) { |
| | | cfsetispeed(&opt, speed_arr[i]); |
| | | cfsetospeed(&opt, speed_arr[i]); |
| | | break; |
| | | } |
| | | } |
| | | |
| | | //Set databit |
| | | opt.c_cflag &= ~CSIZE; |
| | | |
| | | if (databits == 7) { |
| | | opt.c_cflag |= CS7; |
| | | } else { |
| | | opt.c_cflag |= CS8; |
| | | } |
| | | //Set parity |
| | | switch (parity) { |
| | | case 'E': |
| | | case 'e': |
| | | opt.c_cflag |= PARENB; /*Enable parity*/ |
| | | opt.c_cflag &= ~PARODD; |
| | | opt.c_iflag |= INPCK; /*Enable pairty checking*/ |
| | | break; |
| | | case 'O': |
| | | case 'o': |
| | | opt.c_cflag |= PARENB | PARODD; |
| | | opt.c_iflag |= INPCK; |
| | | break; |
| | | |
| | | case 'N': |
| | | case 'n': |
| | | default: |
| | | opt.c_cflag &= ~PARENB; |
| | | opt.c_iflag &= ~INPCK; |
| | | break; |
| | | } |
| | | //Set stop |
| | | if (stopbits == 2) { |
| | | opt.c_cflag |= CSTOPB; |
| | | } else { |
| | | opt.c_cflag &= ~CSTOPB; |
| | | } |
| | | |
| | | opt.c_cflag |= CLOCAL | CREAD; |
| | | |
| | | //Set raw mode |
| | | opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); /*Input*/ |
| | | opt.c_oflag &= ~OPOST; /*Output*/ |
| | | opt.c_iflag &= ~(IXON | IXOFF | IXANY | ICRNL); //Disable XON/XOFF flowcontrol |
| | | opt.c_iflag &= ~(ICRNL | INLCR); //Disable 0x0d and 0x0a convert |
| | | |
| | | opt.c_cc[VTIME] = 0;//150; //15 seconds 150x100ms = 15s |
| | | opt.c_cc[VMIN] = 1; //Recv one char, read() will return |
| | | |
| | | if (flowctrl) { |
| | | opt.c_cflag |= CRTSCTS; |
| | | } else { |
| | | opt.c_cflag &= ~CRTSCTS; //Disable hard flowcontrol |
| | | } |
| | | |
| | | tcflush(fd, TCIOFLUSH); |
| | | |
| | | status = tcsetattr(fd, TCSANOW, &opt); |
| | | |
| | | SET_SERIAL_PORT_END: |
| | | if (status != 0) { |
| | | LOGD("Serial Port set fail"); |
| | | } else { |
| | | LOGD("Serial Port set success"); |
| | | } |
| | | |
| | | // setRTS(fd, 1); |
| | | |
| | | return status; |
| | | } |
| | | |
| | | static int OpenSerialPort(const char *name) { |
| | | int uart_fd; |
| | | |
| | | // uart_fd = open(name, O_RDWR /*| O_NONBLOCK/*| O_NOCTTY | O_NDELAY*/); |
| | | uart_fd = open(name, O_RDWR | O_NOCTTY); |
| | | LOGD("open serial port fd = %d", uart_fd); |
| | | return uart_fd; |
| | | } |
| | | |
| | | static void CloseSerialPort(int fd) { |
| | | close(fd); |
| | | } |
| | | |
| | | int WriteSerialPort(int id, const void *buf, int len) { |
| | | int ret = -1; |
| | | int fds_ret; |
| | | int fd = GetSerialPort(id); |
| | | |
| | | struct timeval tv; |
| | | fd_set wrfds; |
| | | |
| | | if (fd <= 0) { |
| | | return -1; |
| | | } |
| | | |
| | | tv.tv_sec = 1; |
| | | tv.tv_usec = 0; |
| | | |
| | | FD_ZERO(&wrfds); //clean |
| | | FD_SET(fd, &wrfds); //set |
| | | |
| | | pthread_mutex_lock(&mutex[id]); |
| | | |
| | | fds_ret = select(fd + 1, NULL, &wrfds, NULL, &tv); |
| | | |
| | | if (fds_ret < 0) { |
| | | LOGE("Serial port select error\n"); |
| | | } |
| | | else if(fds_ret == 0) { |
| | | LOGE("Serial port write timeout\n"); |
| | | } |
| | | else if(FD_ISSET(fd, &wrfds)) { |
| | | ret = write(fd, buf, len); //serial write data |
| | | if (ret != len ) { |
| | | LOGE("Serial Port Error\n"); |
| | | tcflush(fd, TCOFLUSH); |
| | | } |
| | | } |
| | | else { |
| | | LOGE("Serial Port error 2\n"); |
| | | } |
| | | |
| | | pthread_mutex_unlock(&mutex[id]); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | int GetSerialPort(int id) { |
| | | return serial_port_fd[id]; |
| | | } |
| | | |
| | | int InitSerialPort(int id, int baud, int dataBits, char parity, int stopBits, int flowctrl) |
| | | { |
| | | char name[32]; |
| | | |
| | | if (id == UART_0) { |
| | | strcpy(name, "/dev/ttyHSL0"); |
| | | } else if (id == UART_1) { |
| | | strcpy(name, "/dev/ttyHSL1"); |
| | | } else { |
| | | return -1; |
| | | } |
| | | |
| | | UninitSerialPort(id); |
| | | |
| | | serial_port_fd[id] = OpenSerialPort(name); |
| | | if (serial_port_fd[id] <= 0) { |
| | | return -1; |
| | | } |
| | | |
| | | if (SetSerialPort(serial_port_fd[id], baud, dataBits, parity, stopBits, flowctrl) != 0) { |
| | | return -2; |
| | | } |
| | | pthread_mutex_init(&mutex[id], NULL); |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | void UninitSerialPort(int id) |
| | | { |
| | | if (serial_port_fd[id] > 0) { |
| | | CloseSerialPort(serial_port_fd[id]); |
| | | pthread_mutex_destroy(&mutex[id]); |
| | | serial_port_fd[id] = 0; |
| | | } |
| | | } |
| | | |
| | | int ReadSerialPort(int id, uint8_t *out, uint16_t length) |
| | | { |
| | | if (serial_port_fd[id] <= 0) return 0; |
| | | return read(serial_port_fd[id], out, length); |
| | | } |
| | | |
| | | //extern "C" |
| | | //JNIEXPORT jint JNICALL |
| | | //Java_com_example_yy_jnicallback_MyService_InitSerialPort( |
| | | // JNIEnv *env, |
| | | // jobject /* this */, |
| | | // jstring name, |
| | | // jint baud, |
| | | // jint dataBits, |
| | | // jbyte parity, |
| | | // jint stopBits) { |
| | | // |
| | | // const char *s = env->GetStringUTFChars(name, 0); |
| | | // char item_value[128]; |
| | | // strcpy(item_value, s); |
| | | // env->ReleaseStringUTFChars(name, s); |
| | | // LOGD("serial port = %s", item_value); |
| | | // |
| | | // if (serial_port_fd > 0) { |
| | | // CloseSerialPort(serial_port_fd); |
| | | // pthread_mutex_destroy(&mutex); |
| | | // serial_port_fd = 0; |
| | | // } |
| | | // |
| | | // serial_port_fd = OpenSerialPort(item_value); |
| | | // if (serial_port_fd <= 0) { |
| | | // return -1; |
| | | // } |
| | | // |
| | | // if (SetSerialPort(serial_port_fd, baud, dataBits, parity, stopBits) != 0) { |
| | | // return -2; |
| | | // } |
| | | // pthread_mutex_init(&mutex, NULL); |
| | | // return 0; |
| | | //} |
| | | // |
| | | //extern "C" |
| | | //JNIEXPORT void JNICALL |
| | | //Java_com_example_yy_jnicallback_MyService_MonitSerialPort( |
| | | // JNIEnv *env, |
| | | // jobject /* this */) { |
| | | // if (serial_port_fd > 0) { |
| | | // uint8_t UartRxBuf[4096]; |
| | | // |
| | | ///* uint8_t pkt[] = {0x7E, 0x80, 0x02, 0x00, 0x00, 0x26, 0x00, 0x00, 0x01, 0x38, 0x20, 0x20, |
| | | // 0x55, 0x45, 0x04, 0x4E, |
| | | // 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x02, 0x61, 0x63, |
| | | // 0x0C, 0x06, 0xEA, 0x04, |
| | | // 0xFE, 0x00, 0x00, 0x01, 0x63, 0x00, 0xB4, 0x13, 0x03, 0x05, 0x18, 0x18, |
| | | // 0x52, 0x01, 0x04, 0x00, |
| | | // 0x00, 0x00, 0x00, 0x05, 0x02, 0x00, 0x00, 0x4D, 0x7E}; |
| | | // WriteSerialPort(serial_port_fd, pkt, sizeof(pkt));*/ |
| | | // |
| | | // int length = read(serial_port_fd, UartRxBuf, sizeof(UartRxBuf)); |
| | | // |
| | | // if (length > 0) { |
| | | // Parse(DATA_ACCESS_MCU, UartRxBuf, length); |
| | | // } |
| | | // } |
| | | //} |
New file |
| | |
| | | // |
| | | // Created by YY on 2017/9/5. |
| | | // |
| | | |
| | | #ifndef JNICALLBACK_SERIAL_PORT_H |
| | | #define JNICALLBACK_SERIAL_PORT_H |
| | | |
| | | #include <stdint.h> |
| | | |
| | | #define UART_0 0 |
| | | #define UART_1 1 |
| | | |
| | | struct serial_config { |
| | | char name[32]; |
| | | int baud; |
| | | int data_bit; |
| | | char verify_bit; |
| | | int stop_bit; |
| | | int flow_ctrl; |
| | | }; |
| | | |
| | | int InitSerialPort(int id, int baud, int dataBits, char parity, int stopBits, int flowctrl); |
| | | void UninitSerialPort(int id); |
| | | |
| | | int GetSerialPort(int id); |
| | | int ReadSerialPort(int id, uint8_t *out, uint16_t length); |
| | | int WriteSerialPort(int id, const void *buf, int len); |
| | | int setRTS(int fd, int level); |
| | | |
| | | #endif //JNICALLBACK_SERIAL_PORT_H |
New file |
| | |
| | | #ifndef _DEFS_H_ |
| | | #define _DEFS_H_ |
| | | |
| | | #include <stdint.h> |
| | | #include <stdbool.h> |
| | | |
| | | #define ENABLE_DEBUG |
| | | |
| | | #ifdef ENABLE_DEBUG |
| | | |
| | | #define xENABLE_DEBUG_MAIN |
| | | #define ENABLE_DEBUG_BT |
| | | #define xENABLE_DEBUG_EX_OBD |
| | | #define xENABLE_DEBUG_CV520 |
| | | |
| | | #endif/*ENABLE_DEBUG*/ |
| | | |
| | | /* takes a byte out of a uint32_t : var - uint32_t, ByteNum - byte to take out (0 - 3) */ |
| | | #define BREAK_UINT32( var, ByteNum ) \ |
| | | (uint8_t)((uint32_t)(((var) >>((ByteNum) * 8)) & 0x00FF)) |
| | | |
| | | #define BUILD_UINT32(Byte0, Byte1, Byte2, Byte3) \ |
| | | ((uint32_t)((uint32_t)((Byte0) & 0x00FF) \ |
| | | + ((uint32_t)((Byte1) & 0x00FF) << 8) \ |
| | | + ((uint32_t)((Byte2) & 0x00FF) << 16) \ |
| | | + ((uint32_t)((Byte3) & 0x00FF) << 24))) |
| | | |
| | | #define BUILD_UINT16(loByte, hiByte) \ |
| | | ((uint16_t)(((loByte) & 0x00FF) + (((hiByte) & 0x00FF) << 8))) |
| | | |
| | | #define HI_UINT16(a) (((a) >> 8) & 0xFF) |
| | | #define LO_UINT16(a) ((a) & 0xFF) |
| | | |
| | | #ifndef BV |
| | | #define BV(n) (1ul << (n)) |
| | | #endif |
| | | |
| | | #ifndef ABS |
| | | #define ABS(n) (((n) < 0) ? -(n) : (n)) |
| | | #endif |
| | | |
| | | #ifndef MAX |
| | | #define MAX(a, b) ((a >= b) ? (a) : (b)) |
| | | #endif |
| | | |
| | | #ifndef MIN |
| | | #define MIN(a, b) ((a < b) ? (a) : (b)) |
| | | #endif |
| | | |
| | | const double GLB_EPSILON = 1e-6; |
| | | |
| | | //#define htonl(a) ((((uint32_t)(a) & 0xff000000) >> 24) | \ |
| | | // (((uint32_t)(a) & 0x00ff0000) >> 8) | \ |
| | | // (((uint32_t)(a) & 0x0000ff00) << 8) | \ |
| | | // (((uint32_t)(a) & 0x000000ff) << 24)) |
| | | //#define htons(a) ((((uint16_t)(a) & 0xff00) >> 8) | (((uint16_t)(a) & 0x00ff) << 8)) |
| | | //#define ntohl(a) htonl(a) |
| | | //#define ntohs(a) htons(a) |
| | | |
| | | |
| | | #endif |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/21. |
| | | // Units note: distance - metre |
| | | // speed - metre per second |
| | | // angle - DEGREES |
| | | // |
| | | |
| | | #include <cstdlib> |
| | | #include <cmath> |
| | | #include <semaphore.h> |
| | | #include <pthread.h> |
| | | #include <cstring> |
| | | #include <vector> |
| | | #include "driver_test.h" |
| | | #include "defs.h" |
| | | #include "Geometry.h" |
| | | #include "common/apptimer.h" |
| | | #include "jni_log.h" |
| | | #include "test_items/park_edge.h" |
| | | #include "native-lib.h" |
| | | #include "test_items/park_bottom.h" |
| | | #include "test_items/park_edge.h" |
| | | #include "test_items/error_list.h" |
| | | #include "test_items/turn_a90.h" |
| | | #include "test_items/driving_curve.h" |
| | | #include "test_items/stop_and_start.h" |
| | | |
| | | using namespace std; |
| | | |
| | | #define RTK_INVALID 0 |
| | | #define RTK_SINGLE_POINT 1 |
| | | #define RTK_DIFF 2 |
| | | #define RTK_FIX 3 |
| | | #define RTK_FLOAT 4 |
| | | |
| | | #define CAR_MODEL_POINT_NUM 32 |
| | | |
| | | enum { |
| | | TEST_NONE, |
| | | TEST_PARK_EDGE, |
| | | TEST_PARK_BOTTOM, |
| | | TEST_TUNE_90, |
| | | TEST_S_CURVE, |
| | | TEST_SLOPE, |
| | | TEST_SIMPLE, |
| | | TEST_END |
| | | }; |
| | | |
| | | static bool TestStart = false; |
| | | static int TestItem = TEST_NONE; |
| | | static int CarInArea = 0; |
| | | int errs = 0; |
| | | |
| | | vector<int> ErrorList; |
| | | |
| | | static Polygon theParkEdgeMap; // 侧位停车地图 |
| | | static Polygon theTurn90Map; |
| | | static Polygon theSSMap; |
| | | |
| | | #define CAR_COORD_STORE_SIZE 10 |
| | | |
| | | struct car_coord_ { |
| | | uint32_t uptime; |
| | | double azimuth; |
| | | PointF coord; |
| | | }; |
| | | |
| | | struct car_desc_ { |
| | | double distance; // 距离主天线的距离 |
| | | double angle; // 从中轴线逆时针形成的角度 |
| | | }; |
| | | |
| | | struct car_desc_ *CarDesc = NULL; |
| | | |
| | | struct car_coord_ *CarCoord = NULL; |
| | | static double currSpeed = 0, currAzimuth = 0; |
| | | static PointF currCoord; |
| | | static int prevDirect = 0, currDirect = 0; |
| | | |
| | | static int car_coord_num = 0, car_coord_in = 0; |
| | | |
| | | #define MOV_AVG_SIZE 1 |
| | | #define RTK_HISTORY_SIZE 1000 |
| | | #define CAR_MODEL_CACHE_SIZE 10 |
| | | |
| | | struct rtk_info_ { |
| | | int qf; |
| | | time_t uptime; |
| | | double azimuth; |
| | | PointF coord; |
| | | }; |
| | | |
| | | static struct rtk_info_ *RTKHistory = NULL; |
| | | static int rtk_history_num = 0, rtk_history_in = 0; |
| | | static pthread_mutex_t add_rtk_history_mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | |
| | | static carModelDesc_t *carModelDescFile = NULL; |
| | | |
| | | static car_model_cache_t carModelCache[CAR_MODEL_CACHE_SIZE]; |
| | | static int carModelCacheIn, carModelCacheNum; |
| | | |
| | | static void UpdateCarBodyCoord(double azimuth, PointF coord); |
| | | static void UpdateCarBodyCoord(double azimuth, PointF coord, car_model_cache_t *carModel, int &carModelIn, int &carModelNum); |
| | | static bool FrontTireEnterArea(const Polygon *car, const Polygon *map); |
| | | |
| | | void DriverTestInit(void) |
| | | { |
| | | carModelDescFile = (carModelDesc_t *)malloc(sizeof(carModelDesc_t)); |
| | | |
| | | carModelDescFile->body_num = 6; |
| | | carModelDescFile->body[0] = 0; |
| | | carModelDescFile->body[1] = 1; |
| | | carModelDescFile->body[2] = 2; |
| | | carModelDescFile->body[3] = 3; |
| | | carModelDescFile->body[4] = 4; |
| | | carModelDescFile->body[5] = 5; |
| | | |
| | | carModelDescFile->front_left_tire[0] = 1; |
| | | carModelDescFile->front_left_tire[1] = 1; |
| | | carModelDescFile->front_right_tire[0] = 5; |
| | | carModelDescFile->front_right_tire[1] = 5; |
| | | carModelDescFile->rear_left_tire[0] = 2; |
| | | carModelDescFile->rear_left_tire[1] = 2; |
| | | carModelDescFile->rear_right_tire[0] = 4; |
| | | carModelDescFile->rear_right_tire[1] = 4; |
| | | |
| | | memset(&carModelCache, 0, sizeof(carModelCache)); |
| | | carModelCacheIn = carModelCacheNum = 0; |
| | | |
| | | CarDesc = (struct car_desc_ *) malloc(sizeof(struct car_desc_) * 6); |
| | | CarDesc[0].distance = 0.2465; |
| | | CarDesc[0].angle = 0; |
| | | |
| | | CarDesc[1].distance = 0.2635; |
| | | CarDesc[1].angle = 20.7; |
| | | |
| | | CarDesc[2].distance = 0.14; |
| | | CarDesc[2].angle = 138.9; |
| | | |
| | | CarDesc[3].distance = 0.1055; |
| | | CarDesc[3].angle = 180.0; |
| | | |
| | | CarDesc[4].distance = 0.14; |
| | | CarDesc[4].angle = 221.1; |
| | | |
| | | CarDesc[5].distance = 0.2635; |
| | | CarDesc[5].angle = 339.3; |
| | | |
| | | memset(&theParkEdgeMap, 0, sizeof(theParkEdgeMap)); |
| | | theParkEdgeMap.num = 8; |
| | | theParkEdgeMap.point = (PointF *)malloc(theParkEdgeMap.num * sizeof(PointF)); |
| | | |
| | | theParkEdgeMap.point[0].Y = 28.013; |
| | | theParkEdgeMap.point[0].X = -11.9669; |
| | | |
| | | theParkEdgeMap.point[1].Y = 27.137; |
| | | theParkEdgeMap.point[1].X = -11.5114; |
| | | |
| | | theParkEdgeMap.point[2].Y = 27.5039; |
| | | theParkEdgeMap.point[2].X = -10.8069; |
| | | |
| | | theParkEdgeMap.point[3].Y = 26.4212; |
| | | theParkEdgeMap.point[3].X = -10.2969; |
| | | |
| | | theParkEdgeMap.point[4].Y = 26.8894; |
| | | theParkEdgeMap.point[4].X = -9.2102; |
| | | |
| | | theParkEdgeMap.point[5].Y = 28.0027; |
| | | theParkEdgeMap.point[5].X = -9.6513; |
| | | |
| | | theParkEdgeMap.point[6].Y = 28.3797; |
| | | theParkEdgeMap.point[6].X = -8.9758; |
| | | |
| | | theParkEdgeMap.point[7].Y = 29.3232; |
| | | theParkEdgeMap.point[7].X = -9.5057; |
| | | |
| | | memset(&theTurn90Map, 0, sizeof(theTurn90Map)); |
| | | theTurn90Map.num = 6; |
| | | theTurn90Map.point = (PointF *)malloc(theTurn90Map.num * sizeof(PointF)); |
| | | |
| | | theTurn90Map.point[0].Y = 10; |
| | | theTurn90Map.point[0].X = 10; |
| | | |
| | | theTurn90Map.point[1].Y = 12.5; |
| | | theTurn90Map.point[1].X = 10; |
| | | |
| | | theTurn90Map.point[2].Y = 12.5; |
| | | theTurn90Map.point[2].X = 12.5; |
| | | |
| | | theTurn90Map.point[3].Y = 15; |
| | | theTurn90Map.point[3].X = 12.5; |
| | | |
| | | theTurn90Map.point[4].Y = 15; |
| | | theTurn90Map.point[4].X = 15; |
| | | |
| | | theTurn90Map.point[5].Y = 10; |
| | | theTurn90Map.point[5].X = 15; |
| | | |
| | | memset(&theSSMap, 0, sizeof(theSSMap)); |
| | | theSSMap.num = 9; |
| | | theSSMap.point = (PointF *)malloc(theSSMap.num * sizeof(PointF)); |
| | | |
| | | theSSMap.point[0].Y = 10; |
| | | theSSMap.point[0].X = 10; |
| | | |
| | | theSSMap.point[8].Y = 10; |
| | | theSSMap.point[8].X = 15; |
| | | |
| | | theSSMap.point[1].Y = 10; |
| | | theSSMap.point[1].X = 11.5; |
| | | |
| | | theSSMap.point[4].Y = 10; |
| | | theSSMap.point[4].X = 12.5; |
| | | |
| | | theSSMap.point[5].Y = 10; |
| | | theSSMap.point[5].X = 13.5; |
| | | |
| | | theSSMap.point[2].Y = 12; |
| | | theSSMap.point[2].X = 11.5; |
| | | |
| | | theSSMap.point[3].Y = 12; |
| | | theSSMap.point[3].X = 12.5; |
| | | |
| | | theSSMap.point[6].Y = 12; |
| | | theSSMap.point[6].X = 13.5; |
| | | |
| | | theSSMap.point[7].Y = 12; |
| | | theSSMap.point[7].X = 15; |
| | | |
| | | pthread_mutex_init(&add_rtk_history_mutex, NULL); |
| | | |
| | | RTKHistory = (struct rtk_info_ *) malloc(RTK_HISTORY_SIZE * sizeof(struct rtk_info_)); |
| | | rtk_history_num = rtk_history_in = 0; |
| | | |
| | | CarCoord = (struct car_coord_ *) malloc(CAR_COORD_STORE_SIZE * sizeof(struct car_coord_)); |
| | | car_coord_num = car_coord_in = 0; |
| | | |
| | | TestStart = true; |
| | | TestItem = TEST_NONE; |
| | | |
| | | ErrorList.clear(); |
| | | |
| | | TextSpeak("开始测试"); |
| | | } |
| | | |
| | | void UpdateRTKInfo(struct rtk_info *s) |
| | | { |
| | | struct tm test_tm; |
| | | |
| | | struct timeval tv; |
| | | struct timezone tz; |
| | | |
| | | gettimeofday(&tv,&tz); |
| | | |
| | | memset(&test_tm, 0, sizeof(test_tm)); |
| | | |
| | | test_tm.tm_year = 2000 + s->YY - 1900; |
| | | test_tm.tm_mon = s->MM - 1; |
| | | test_tm.tm_mday = s->DD; |
| | | test_tm.tm_hour = s->hh; |
| | | test_tm.tm_min = s->mm; |
| | | test_tm.tm_sec = s->ss; |
| | | |
| | | pthread_mutex_lock(&add_rtk_history_mutex); |
| | | /*if (s->qf == 3)*/ { |
| | | RTKHistory[rtk_history_in].qf = RTK_FIX;//s->qf; |
| | | RTKHistory[rtk_history_in].uptime = mktime(&test_tm) - tz.tz_minuteswest*60; |
| | | RTKHistory[rtk_history_in].azimuth = s->heading; |
| | | RTKHistory[rtk_history_in].coord.X = s->x; |
| | | RTKHistory[rtk_history_in].coord.Y = s->y; |
| | | |
| | | rtk_history_in = (rtk_history_in + 1) % RTK_HISTORY_SIZE; |
| | | if (rtk_history_num < RTK_HISTORY_SIZE) |
| | | rtk_history_num++; |
| | | } |
| | | pthread_mutex_unlock(&add_rtk_history_mutex); |
| | | |
| | | // DEBUG("UpdateRTKInfo qf = %d tm %ld", s->qf, mktime(&test_tm) - tz.tz_minuteswest*60); |
| | | } |
| | | |
| | | void UpdateCarCoord(void) |
| | | { |
| | | double azimuth; |
| | | PointF coord; |
| | | |
| | | // 计算最近的几个,滑动平均 |
| | | int cnt = 0, valid_cnt = 0; |
| | | int s, sm; |
| | | time_t prev_time = 0; |
| | | time_t last_rtk_time = 0; |
| | | |
| | | pthread_mutex_lock(&add_rtk_history_mutex); |
| | | s = rtk_history_in; |
| | | sm = rtk_history_num; |
| | | pthread_mutex_unlock(&add_rtk_history_mutex); |
| | | |
| | | DEBUG("UpdateCarCoord rtk_history_in %d rtk_history_num %d car_coord_num %d", s, sm, car_coord_num); |
| | | |
| | | // 如果出现QF不是固定解、GPS报文丢失的情况,就按上次的行驶状态做直线行驶 |
| | | for (; cnt < sm && valid_cnt < MOV_AVG_SIZE; cnt++) { |
| | | if (s == 0) { |
| | | s = RTK_HISTORY_SIZE - 1; |
| | | } else { |
| | | s--; |
| | | } |
| | | |
| | | if (cnt == 0) { |
| | | last_rtk_time = RTKHistory[s].uptime; |
| | | } |
| | | |
| | | if (RTKHistory[s].uptime - last_rtk_time <= 10) { |
| | | if (RTKHistory[s].qf == RTK_FIX) { |
| | | if (valid_cnt != 0) { |
| | | azimuth += RTKHistory[s].azimuth; |
| | | coord.X += RTKHistory[s].coord.X; |
| | | coord.Y += RTKHistory[s].coord.Y; |
| | | } else { |
| | | azimuth = RTKHistory[s].azimuth; |
| | | coord.X = RTKHistory[s].coord.X; |
| | | coord.Y = RTKHistory[s].coord.Y; |
| | | } |
| | | valid_cnt++; |
| | | } |
| | | } else { |
| | | break; |
| | | } |
| | | prev_time = RTKHistory[s].uptime; |
| | | } |
| | | |
| | | if (valid_cnt >= MOV_AVG_SIZE) { |
| | | azimuth /= MOV_AVG_SIZE; |
| | | coord.X /= MOV_AVG_SIZE; |
| | | coord.Y /= MOV_AVG_SIZE; |
| | | |
| | | CarCoord[car_coord_in].uptime = AppTimer_GetTickCount(); |
| | | |
| | | CarCoord[car_coord_in].azimuth = azimuth; |
| | | CarCoord[car_coord_in].coord = coord; |
| | | car_coord_in = (car_coord_in + 1) % CAR_COORD_STORE_SIZE; |
| | | if (car_coord_num < CAR_COORD_STORE_SIZE) |
| | | car_coord_num++; |
| | | } else if (car_coord_num >= 3) { |
| | | // 按上次运行轨迹推算一步 |
| | | int p1 = ((car_coord_in-1)+CAR_COORD_STORE_SIZE)%CAR_COORD_STORE_SIZE; |
| | | uint32_t tm = AppTimer_GetTickCount() - CarCoord[p1].uptime; |
| | | double distance = currSpeed * tm / 1000; |
| | | |
| | | PointF xy; |
| | | |
| | | xy.X = CarCoord[p1].coord.X + distance * sin(toRadians(CarCoord[p1].azimuth)) * currDirect; |
| | | xy.Y = CarCoord[p1].coord.Y + distance * sin(toRadians(CarCoord[p1].azimuth)) * currDirect; |
| | | |
| | | CarCoord[car_coord_in].uptime = AppTimer_GetTickCount(); |
| | | CarCoord[car_coord_in].azimuth = CarCoord[p1].azimuth; |
| | | CarCoord[car_coord_in].coord = xy; |
| | | car_coord_in = (car_coord_in + 1) % CAR_COORD_STORE_SIZE; |
| | | if (car_coord_num < CAR_COORD_STORE_SIZE) |
| | | car_coord_num++; |
| | | } else { |
| | | return; |
| | | } |
| | | |
| | | // 计算车辆轮廓点、速度、前进后退 |
| | | if (car_coord_num >= 3) { |
| | | int p1 = ((car_coord_in-1)+CAR_COORD_STORE_SIZE)%CAR_COORD_STORE_SIZE; |
| | | int p2 = ((car_coord_in-2)+CAR_COORD_STORE_SIZE)%CAR_COORD_STORE_SIZE; |
| | | int p3 = ((car_coord_in-3)+CAR_COORD_STORE_SIZE)%CAR_COORD_STORE_SIZE; |
| | | |
| | | double speed1 = sqrt(pow(CarCoord[p1].coord.X - CarCoord[p2].coord.X, 2) + pow(CarCoord[p1].coord.Y - CarCoord[p2].coord.Y, 2)) * 1000 / |
| | | (double)(CarCoord[p1].uptime - CarCoord[p2].uptime); |
| | | double speed2 = sqrt(pow(CarCoord[p2].coord.X - CarCoord[p3].coord.X, 2) + pow(CarCoord[p2].coord.Y - CarCoord[p3].coord.Y, 2)) * 1000 / |
| | | (double)(CarCoord[p2].uptime - CarCoord[p3].uptime); |
| | | |
| | | currSpeed = speed1; |
| | | currAzimuth = CarCoord[p1].azimuth; |
| | | currCoord = CarCoord[p1].coord; |
| | | |
| | | DEBUG("方向 spd1 %f spd2 %f", speed1, speed2); |
| | | |
| | | if (speed1 < 0.05 && speed2 < 0.05) { |
| | | // 停车 |
| | | currDirect = 0; |
| | | // TextSpeak("停"); |
| | | } else if (speed1 < 0.05) { |
| | | currDirect = prevDirect; |
| | | } else { |
| | | // 判断前进还是后退 |
| | | double deg = 0.0; |
| | | |
| | | if (fabs(CarCoord[p1].coord.Y-CarCoord[p2].coord.Y) <= GLB_EPSILON) { |
| | | if (CarCoord[p1].coord.X > CarCoord[p2].coord.X) { |
| | | deg = 90; |
| | | } else { |
| | | deg = 270; |
| | | } |
| | | |
| | | DEBUG("方向 deg %f p1x %f p2x %f", deg, CarCoord[p1].coord.X, CarCoord[p2].coord.X); |
| | | } else if (fabs(CarCoord[p1].coord.X - CarCoord[p2].coord.X) <= GLB_EPSILON) { |
| | | if (CarCoord[p1].coord.Y > CarCoord[p2].coord.Y) { |
| | | deg = 0; |
| | | } else { |
| | | deg = 180; |
| | | } |
| | | } else { |
| | | deg = atan(fabs(CarCoord[p1].coord.X - CarCoord[p2].coord.X) / |
| | | fabs(CarCoord[p1].coord.Y - CarCoord[p2].coord.Y)); |
| | | |
| | | deg = toDegree(deg); |
| | | |
| | | if (CarCoord[p1].coord.X > CarCoord[p2].coord.X && |
| | | CarCoord[p1].coord.Y > CarCoord[p2].coord.Y) { |
| | | |
| | | } else if (CarCoord[p1].coord.X < CarCoord[p2].coord.X && |
| | | CarCoord[p1].coord.Y > CarCoord[p2].coord.Y) { |
| | | deg = 360 - deg; |
| | | } else if (CarCoord[p1].coord.X < CarCoord[p2].coord.X && |
| | | CarCoord[p1].coord.Y < CarCoord[p2].coord.Y) { |
| | | deg = 180 + deg; |
| | | } else if (CarCoord[p1].coord.X > CarCoord[p2].coord.X && |
| | | CarCoord[p1].coord.Y < CarCoord[p2].coord.Y) { |
| | | deg = 180 - deg; |
| | | } |
| | | |
| | | DEBUG("方向 deg %f p1x %f p2x %f p1y %f p2y %f", deg, CarCoord[p1].coord.X, |
| | | CarCoord[p2].coord.X, CarCoord[p1].coord.Y, CarCoord[p2].coord.Y); |
| | | } |
| | | |
| | | deg = fabs(CarCoord[p1].azimuth - deg); |
| | | if (deg > 180) { |
| | | deg = 360 - deg; |
| | | } |
| | | if (deg < 90) { |
| | | // 前进 |
| | | currDirect = 1; |
| | | // TextSpeak("进"); |
| | | } else { |
| | | // 后退 |
| | | currDirect = -1; |
| | | // TextSpeak("退"); |
| | | } |
| | | |
| | | prevDirect = currDirect; |
| | | } |
| | | |
| | | DEBUG("speed = %f, azimuth = %f coord.X = %f coord.Y = %f dir = %d", speed1, CarCoord[p1].azimuth, |
| | | CarCoord[p1].coord.X, CarCoord[p1].coord.Y, currDirect); |
| | | |
| | | // UpdateCarBodyCoord(CarCoord[p1].azimuth, CarCoord[p1].coord); |
| | | UpdateCarBodyCoord(CarCoord[p1].azimuth, CarCoord[p1].coord, carModelCache, carModelCacheIn, carModelCacheNum); |
| | | // for (int i = 0; i < theCarModel.num; ++i) { |
| | | // DEBUG("n = %d X = %f Y = %f", i, theCarModel.point[i].X, theCarModel.point[i].Y); |
| | | // } |
| | | |
| | | |
| | | int c1 = ((carModelCacheIn-1)+CAR_MODEL_CACHE_SIZE)%CAR_MODEL_CACHE_SIZE; |
| | | Polygon py; |
| | | |
| | | py.num = carModelCache[c1].point_num; |
| | | py.point = carModelCache[c1].points; |
| | | |
| | | DrawScreen(&theSSMap, &py); |
| | | |
| | | if (!TestStart) return; |
| | | |
| | | if (CarInArea == 0) { |
| | | // if (FrontTireEnterArea(&py, &theParkEdgeMap)) { |
| | | // CarInArea = TEST_PARK_BOTTOM; |
| | | // TestItem = TEST_PARK_BOTTOM; |
| | | // StartParkBottom(); |
| | | // } |
| | | |
| | | CarInArea = TEST_SLOPE; |
| | | TestItem = TEST_SLOPE; |
| | | StartSAS(); |
| | | } |
| | | |
| | | switch (TestItem) { |
| | | case TEST_NONE: { |
| | | break; |
| | | } |
| | | case TEST_PARK_BOTTOM: { |
| | | errs = TestParkBottom(ErrorList, &theParkEdgeMap, GetCarModelCache(0), currSpeed, currDirect); |
| | | |
| | | if (errs != 0) { |
| | | StopParkBottom(); |
| | | TestItem = TEST_NONE; |
| | | } |
| | | break; |
| | | } |
| | | case TEST_PARK_EDGE: { |
| | | errs = TestParkEdge(ErrorList, &theParkEdgeMap, GetCarModelCache(0), currSpeed, currDirect); |
| | | |
| | | if (errs != 0) { |
| | | StopParkEdge(); |
| | | TestItem = TEST_NONE; |
| | | } |
| | | break; |
| | | } |
| | | |
| | | case TEST_TUNE_90: { |
| | | errs = TestTurnA90(ErrorList, &theTurn90Map, GetCarModelCache(0), currSpeed, currDirect, currAzimuth); |
| | | |
| | | if (errs != 0) { |
| | | StopTurnA90(); |
| | | TestItem = TEST_NONE; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | |
| | | case TEST_SLOPE: { |
| | | errs = TestSAS(ErrorList, &theSSMap, GetCarModelCache(0), currSpeed, currDirect); |
| | | |
| | | if (errs != 0) { |
| | | StopSAS(); |
| | | TestItem = TEST_NONE; |
| | | } |
| | | |
| | | break; |
| | | } |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | if (ErrorList.size() > 0) { |
| | | vector<int>::iterator it = ErrorList.end(); |
| | | it--; |
| | | error_list_t list = GetErrorList(*it); |
| | | |
| | | int scr = 0; |
| | | |
| | | for (vector<int>::iterator it1 = ErrorList.begin(); it1 != ErrorList.end(); ++it1) { |
| | | error_list_t list = GetErrorList(*it1); |
| | | |
| | | scr += list.dec_score; |
| | | } |
| | | |
| | | char buff[256]; |
| | | |
| | | sprintf(buff, "%s, 总计扣分 %d", list.text_desc, scr); |
| | | |
| | | TextOsd(1, buff); |
| | | } |
| | | } |
| | | } |
| | | |
| | | car_model_cache_t *GetCarModelCache(int node) |
| | | { |
| | | if (node < carModelCacheNum) { |
| | | node = ((carModelCacheIn-node-1)+CAR_MODEL_CACHE_SIZE)%CAR_MODEL_CACHE_SIZE; |
| | | return &carModelCache[node]; |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | /******************************************************************* |
| | | * @brief 由主天线坐标计算车身点坐标 |
| | | * @param azimuth |
| | | * @param coord |
| | | */ |
| | | static void UpdateCarBodyCoord(double azimuth, PointF coord, car_model_cache_t *carModel, int &in, int &num) |
| | | { |
| | | carModel[in].uptime = AppTimer_GetTickCount(); |
| | | carModel[in].desc = carModelDescFile; |
| | | carModel[in].point_num = 6; |
| | | |
| | | if (carModel[in].points == NULL) { |
| | | carModel[in].points = (PointF *) malloc(sizeof(PointF) * carModel[in].point_num); |
| | | } |
| | | |
| | | for (int i = 0; i < 6; ++i) { |
| | | double tx = coord.X + CarDesc[i].distance*sin(toRadians(azimuth)); |
| | | double ty = coord.Y + CarDesc[i].distance*cos(toRadians(azimuth)); |
| | | |
| | | carModel[in].points[i].X = (tx-coord.X)*cos(toRadians(CarDesc[i].angle)) - |
| | | (ty-coord.Y)*sin(toRadians(CarDesc[i].angle)) + coord.X; |
| | | carModel[in].points[i].Y = (tx-coord.X)*sin(toRadians(CarDesc[i].angle)) + |
| | | (ty-coord.Y)*cos(toRadians(CarDesc[i].angle)) + coord.Y; |
| | | } |
| | | |
| | | in = (in + 1) % CAR_MODEL_CACHE_SIZE; |
| | | if (num < CAR_MODEL_CACHE_SIZE) { |
| | | num++; |
| | | } |
| | | } |
| | | |
| | | static void UpdateCarBodyCoord(double azimuth, PointF coord) |
| | | { |
| | | // static double az = 0; |
| | | // |
| | | // az += 2.0; |
| | | // |
| | | // for (int i = 0; i < theCarModel.num; ++i) { |
| | | // double tx = coord.X + CarDesc[i].distance*sin(toRadians(azimuth)); |
| | | // double ty = coord.Y + CarDesc[i].distance*cos(toRadians(azimuth)); |
| | | // |
| | | // theCarModel.point[i].X = (tx-coord.X)*cos(toRadians(CarDesc[i].angle)) - |
| | | // (ty-coord.Y)*sin(toRadians(CarDesc[i].angle)) + coord.X; |
| | | // theCarModel.point[i].Y = (tx-coord.X)*sin(toRadians(CarDesc[i].angle)) + |
| | | // (ty-coord.Y)*cos(toRadians(CarDesc[i].angle)) + coord.Y; |
| | | // } |
| | | // UpdateParkTest(&theCarModel, &theTireModel, speed); |
| | | // UpdatePark2Test(&theCarModel, &theTireModel, speed); |
| | | // UpdateTuneAngle90Test(&theCarModel, 0); |
| | | //UpdateSlopeTest(&theCarModel, speed, direct); |
| | | } |
| | | |
| | | static bool FrontTireEnterArea(const Polygon *car, const Polygon *map) |
| | | { |
| | | if (IntersectionOf(car->point[0], map) == GM_Containment) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/21. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_DRIVER_TEST_H |
| | | #define RTKDRIVERTEST_DRIVER_TEST_H |
| | | |
| | | #include "Geometry.h" |
| | | |
| | | struct rtk_info { |
| | | int YY; |
| | | int MM; |
| | | int DD; |
| | | int hh; |
| | | int mm; |
| | | int ss; |
| | | int dss; |
| | | int qf; |
| | | double heading; |
| | | double x; |
| | | double y; |
| | | }; |
| | | |
| | | #define TIRE_OUTSIDE 0 |
| | | #define TIRE_INSIDE 1 |
| | | |
| | | // 总数 |
| | | // 中轴线前点,id 0,中轴线后点id |
| | | // 左包围, 右包围 |
| | | // 左前轮,外内 |
| | | typedef struct { |
| | | int body_num; |
| | | int body[64]; |
| | | int front_left_tire[2]; |
| | | int front_right_tire[2]; |
| | | int rear_left_tire[2]; |
| | | int rear_right_tire[2]; |
| | | } carModelDesc_t; |
| | | |
| | | typedef struct { |
| | | uint32_t uptime; |
| | | int point_num; |
| | | PointF *points; |
| | | carModelDesc_t *desc; |
| | | } car_model_cache_t; |
| | | |
| | | void DriverTestInit(void); |
| | | void UpdateRTKInfo(struct rtk_info *s); |
| | | void UpdateCarCoord(void); |
| | | car_model_cache_t *GetCarModelCache(int node); |
| | | |
| | | #endif //RTKDRIVERTEST_DRIVER_TEST_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2017/8/29. |
| | | // |
| | | |
| | | #ifndef JNI_LOG_H |
| | | #define JNI_LOG_H |
| | | |
| | | #include <android/log.h> |
| | | |
| | | #define DTAG "JNI_DEBUG" |
| | | |
| | | #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,DTAG,__VA_ARGS__) // 定义LOGD类型 |
| | | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO,DTAG,__VA_ARGS__) // 定义LOGI类型 |
| | | #define LOGW(...) __android_log_print(ANDROID_LOG_WARN,DTAG,__VA_ARGS__) // 定义LOGW类型 |
| | | #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,DTAG,__VA_ARGS__) // 定义LOGE类型 |
| | | #define LOGF(...) __android_log_print(ANDROID_LOG_FATAL,DTAG,__VA_ARGS__) // 定义LOGF类型 |
| | | |
| | | #define LOGMCUD(...) __android_log_print(ANDROID_LOG_DEBUG,"MCU_DEBUG",__VA_ARGS__) // 定义LOGD类型 |
| | | |
| | | #define ENABLE_DEBUG_PROTOCOL |
| | | |
| | | #ifdef ENABLE_DEBUG_PROTOCOL |
| | | #define DEBUG(...) LOGD(__VA_ARGS__) |
| | | #else |
| | | #define DEBUG(...) |
| | | #endif |
| | | |
| | | #endif //JNI_LOG_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/21. |
| | | // |
| | | |
| | | #include <cstring> |
| | | #include <pthread.h> |
| | | #include "mcu_if.h" |
| | | #include "../common/apptimer.h" |
| | | #include "../utils/crc16.h" |
| | | #include "../defs.h" |
| | | #include "../jni_log.h" |
| | | #include "../common/serial_port.h" |
| | | |
| | | #define MCU_UART UART_1 |
| | | |
| | | enum parse_status_t { |
| | | SYNC_HEAD_ONE, |
| | | SYNC_HEAD_TWO, |
| | | GET_ID_HI, |
| | | GET_ID_LO, |
| | | GET_LENGTH_HI, |
| | | GET_LENGTH_LO, |
| | | GET_PAYLOAD, |
| | | GET_CRC16_HI, |
| | | GET_CRC16_LO |
| | | }; |
| | | |
| | | #define ID_CM_APP_BOOT 0x0001 |
| | | #define ID_MC_MCU_BOOT 0x8001 |
| | | #define ID_CM_INQ_MCU_VER 0x0002 |
| | | #define ID_MC_MCU_VER 0x8002 |
| | | #define ID_CM_RW_INFO 0x0003 |
| | | #define ID_MC_RW_INFO_RSP 0x8003 |
| | | #define ID_CM_MCU_DFU_REQ 0x0004 |
| | | #define ID_MC_MCU_DFU_RSP 0x8004 |
| | | #define ID_CM_MCU_DFU_DATA 0x0005 |
| | | #define ID_CM_MCU_DFU_DATA_CMP 0x0006 |
| | | #define ID_MC_MCU_DFU_DATA_RSP 0x8006 |
| | | #define ID_MC_CAR_INFO 0x8007 |
| | | #define ID_MC_RTK_DATA 0x8008 |
| | | #define ID_CM_RTK_DATA 0x0008 |
| | | #define ID_CM_READ_RFCARD 0x0009 |
| | | #define ID_MC_RFCARD_RSP 0x8009 |
| | | |
| | | static parse_status_t parse_status; |
| | | |
| | | static struct { |
| | | uint16_t id; |
| | | uint16_t length; |
| | | uint16_t rx_len; |
| | | uint8_t buffer[4096 + 4]; |
| | | uint16_t crc16; |
| | | }McuPkt; |
| | | |
| | | static void *UartThread1(void *p); |
| | | static void ParseMcuTimeout(union sigval sig); |
| | | static void McuCommandEntry(uint16_t id, const uint8_t *data, int lenth); |
| | | |
| | | void ParseMcuInit(void) |
| | | { |
| | | parse_status = SYNC_HEAD_ONE; |
| | | AppTimer_delete(ParseMcuTimeout); |
| | | |
| | | SendMcuCommand(ID_CM_APP_BOOT, NULL, 0); |
| | | } |
| | | |
| | | #define PARSE_BUFF_SIZE 4096 |
| | | |
| | | static void *UartThread1(void *p) { |
| | | struct serial_config *cfg = (struct serial_config *) p; |
| | | |
| | | int res = InitSerialPort(MCU_UART, cfg->baud, cfg->data_bit, cfg->verify_bit, cfg->stop_bit, cfg->flow_ctrl); |
| | | DEBUG("Serial %s open %d", cfg->name, res); |
| | | uint8_t RxBuf[PARSE_BUFF_SIZE]; |
| | | int RxBufLen = 0; |
| | | |
| | | if (res == 0) |
| | | ParseMcuInit(); |
| | | |
| | | while (res == 0) { |
| | | int ul = ReadSerialPort(MCU_UART, (uint8_t *)RxBuf + RxBufLen, sizeof(RxBuf) - RxBufLen); |
| | | RxBufLen += ul; |
| | | |
| | | /*{ |
| | | static char buffd[16384]; |
| | | |
| | | buffd[0] = 0; |
| | | int i = 0; |
| | | for (i = 0; i < ul; i++) { |
| | | if ((i % 32) == 0) { |
| | | sprintf(buffd + strlen(buffd), "\n"); |
| | | } |
| | | sprintf(buffd + strlen(buffd), "%02X ", RxBuf[i]); |
| | | if (strlen(buffd) > 800) { |
| | | DEBUG("%s <- %s...", "UART", buffd); |
| | | buffd[0] = 0; |
| | | } |
| | | } |
| | | if (strlen(buffd) > 0) |
| | | DEBUG("%s <- %s", "UART", buffd); |
| | | }*/ |
| | | |
| | | if (RxBufLen > 0) { |
| | | DEBUG("RECV LEN %d", RxBufLen); |
| | | ParseMcu(RxBuf, RxBufLen); |
| | | RxBufLen = 0; |
| | | } |
| | | } |
| | | if (res == 0) { |
| | | UninitSerialPort(MCU_UART); |
| | | } |
| | | pthread_exit(NULL); |
| | | } |
| | | |
| | | void ParseMcu(const uint8_t *data, int length) |
| | | { |
| | | int x = 0; |
| | | while (x < length) { |
| | | uint8_t c = data[x]; |
| | | switch (parse_status) { |
| | | case SYNC_HEAD_ONE: |
| | | if (c == 0x55) { |
| | | parse_status = SYNC_HEAD_TWO; |
| | | AppTimer_delete(ParseMcuTimeout); |
| | | AppTimer_add(ParseMcuTimeout, D_SEC(5)); |
| | | } |
| | | x++; |
| | | break; |
| | | case SYNC_HEAD_TWO: |
| | | if (c == 0xAA) { |
| | | parse_status = GET_ID_HI; |
| | | } else if (c != 0x55) { |
| | | parse_status = SYNC_HEAD_ONE; |
| | | } |
| | | x++; |
| | | break; |
| | | case GET_ID_HI: |
| | | McuPkt.id = c; |
| | | parse_status = GET_ID_LO; |
| | | x++; |
| | | break; |
| | | case GET_ID_LO: |
| | | McuPkt.id <<= 8; |
| | | McuPkt.id += c; |
| | | parse_status = GET_LENGTH_HI; |
| | | x++; |
| | | break; |
| | | case GET_LENGTH_HI: |
| | | McuPkt.rx_len = 0; |
| | | McuPkt.length = c; |
| | | parse_status = GET_LENGTH_LO; |
| | | x++; |
| | | break; |
| | | case GET_LENGTH_LO: |
| | | McuPkt.length <<= 8; |
| | | McuPkt.length += c; |
| | | parse_status = GET_PAYLOAD; |
| | | |
| | | if (McuPkt.length >= 1500) { |
| | | DEBUG("Pkt Too large!"); |
| | | parse_status = SYNC_HEAD_ONE; |
| | | AppTimer_delete(ParseMcuTimeout); |
| | | } |
| | | |
| | | McuPkt.buffer[0] = HI_UINT16(McuPkt.id); |
| | | McuPkt.buffer[1] = LO_UINT16(McuPkt.id); |
| | | McuPkt.buffer[2] = HI_UINT16(McuPkt.length); |
| | | McuPkt.buffer[3] = LO_UINT16(McuPkt.length); |
| | | x++; |
| | | break; |
| | | case GET_PAYLOAD: |
| | | if (length - x >= McuPkt.length - McuPkt.rx_len) { |
| | | memcpy(McuPkt.buffer + 4 + McuPkt.rx_len, data + x, McuPkt.length - McuPkt.rx_len); |
| | | x += McuPkt.length - McuPkt.rx_len; |
| | | McuPkt.rx_len = McuPkt.length; |
| | | parse_status = GET_CRC16_HI; |
| | | } else { |
| | | memcpy(McuPkt.buffer + 4 + McuPkt.rx_len, data + x, length - x); |
| | | McuPkt.rx_len += length - x; |
| | | x = length; |
| | | } |
| | | break; |
| | | case GET_CRC16_HI: |
| | | McuPkt.crc16 = c; |
| | | parse_status = GET_CRC16_LO; |
| | | x++; |
| | | break; |
| | | case GET_CRC16_LO: { |
| | | McuPkt.crc16 <<= 8; |
| | | McuPkt.crc16 += c; |
| | | |
| | | uint16_t crc16 = CRCCCITT(McuPkt.buffer, McuPkt.length + 4, 0, 0); |
| | | |
| | | DEBUG("mcuif crc16 but 0x%04X exp 0x%04X", McuPkt.crc16, crc16); |
| | | |
| | | if (McuPkt.crc16 == crc16) { |
| | | McuCommandEntry(McuPkt.id, McuPkt.buffer + 4, McuPkt.length); |
| | | } |
| | | |
| | | parse_status = SYNC_HEAD_ONE; |
| | | AppTimer_delete(ParseMcuTimeout); |
| | | x++; |
| | | break; |
| | | } |
| | | default: |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void SendMcuCommand(uint16_t id, const uint8_t *data, int length) |
| | | { |
| | | uint8_t buffer[2048]; |
| | | int x = 0; |
| | | |
| | | buffer[x++] = 0x55; |
| | | buffer[x++] = 0xAA; |
| | | buffer[x++] = HI_UINT16(id); |
| | | buffer[x++] = LO_UINT16(id); |
| | | buffer[x++] = HI_UINT16(length); |
| | | buffer[x++] = LO_UINT16(length); |
| | | |
| | | if (data != NULL && length > 0) { |
| | | memcpy(buffer + x, data, length); |
| | | x += length; |
| | | } |
| | | |
| | | uint16_t crc16 = CRCCCITT(buffer + 2, length + 4, 0, 0); |
| | | buffer[x++] = HI_UINT16(crc16); |
| | | buffer[x++] = LO_UINT16(crc16); |
| | | |
| | | WriteSerialPort(MCU_UART, buffer, x); |
| | | } |
| | | |
| | | void ConfigMCU(void) |
| | | { |
| | | // TODO |
| | | static struct serial_config serialConfig; |
| | | |
| | | strcpy(serialConfig.name, "/dev/ttyHSL1"); |
| | | serialConfig.baud = 115200; |
| | | serialConfig.data_bit = 8; |
| | | serialConfig.verify_bit = 'N'; |
| | | serialConfig.stop_bit = 1; |
| | | serialConfig.flow_ctrl = 0; |
| | | |
| | | pthread_t pid; |
| | | pthread_attr_t attr; |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | pthread_create(&pid, &attr, UartThread1, &serialConfig); |
| | | } |
| | | |
| | | void SendRtkToMcu(const uint8_t *data, int length) |
| | | { |
| | | SendMcuCommand(ID_CM_RTK_DATA, data, length); |
| | | } |
| | | |
| | | static void ParseMcuTimeout(union sigval sig) { |
| | | AppTimer_delete(ParseMcuTimeout); |
| | | parse_status = SYNC_HEAD_ONE; |
| | | } |
| | | |
| | | static void sendrtk(union sigval sig) { |
| | | uint8_t data[486]; |
| | | |
| | | memset(data, 0x86, sizeof(data)); |
| | | |
| | | SendMcuCommand(ID_CM_RTK_DATA, data, sizeof(data)); |
| | | |
| | | SendMcuCommand(ID_CM_READ_RFCARD, NULL, 0); |
| | | |
| | | AppTimer_delete(sendrtk); |
| | | AppTimer_add(sendrtk, D_SEC(1)); |
| | | } |
| | | |
| | | static void McuCommandEntry(uint16_t id, const uint8_t *data, int lenth) |
| | | { |
| | | static int ii = 0; |
| | | |
| | | switch (id) { |
| | | case ID_MC_MCU_BOOT: |
| | | DEBUG("MCU BOOT"); |
| | | break; |
| | | case ID_MC_MCU_VER: |
| | | DEBUG("MCU VER"); |
| | | break; |
| | | case ID_MC_RW_INFO_RSP: |
| | | break; |
| | | case ID_MC_MCU_DFU_RSP: |
| | | break; |
| | | case ID_MC_MCU_DFU_DATA_RSP: |
| | | break; |
| | | case ID_MC_CAR_INFO: |
| | | DEBUG("ID_MC_CAR_INFO"); |
| | | break; |
| | | case ID_MC_RTK_DATA: |
| | | DEBUG("ID_MC_RTK_DATA"); |
| | | break; |
| | | case ID_MC_RFCARD_RSP: |
| | | DEBUG("ID_MC_RFCARD_RSP"); |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/21. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_MCU_IF_H |
| | | #define RTKDRIVERTEST_MCU_IF_H |
| | | |
| | | #include <cstdint> |
| | | |
| | | void ConfigMCU(void); |
| | | void SendRtkToMcu(const uint8_t *data, int length); |
| | | void ParseMcuInit(void); |
| | | void ParseMcu(const uint8_t *data, int length); |
| | | void SendMcuCommand(uint16_t id, const uint8_t *data, int length); |
| | | |
| | | #endif //RTKDRIVERTEST_MCU_IF_H |
New file |
| | |
| | | #include <jni.h> |
| | | #include <string> |
| | | #include <pthread.h> |
| | | #include <unistd.h> |
| | | #include "common/serial_port.h" |
| | | #include "jni_log.h" |
| | | #include "common/net.h" |
| | | #include "common/apptimer.h" |
| | | #include "rtk_platform/parse_net.h" |
| | | #include "native-lib.h" |
| | | #include "Geometry.h" |
| | | #include "rtk_platform/platform.h" |
| | | #include "rtk_module/rtk.h" |
| | | #include "mcu/mcu_if.h" |
| | | #include "driver_test.h" |
| | | |
| | | static JavaVM *sg_jvm = NULL; |
| | | static jobject sg_obj = NULL; |
| | | |
| | | const char *RTK_PLATFORM_IP = "47.93.80.84"; |
| | | const int RTK_PLATFORM_PORT = 12125; |
| | | const uint8_t phone[] = {0x20,0x19,0x10,0x15,0x00,0x00,0x00,0x02}; |
| | | |
| | | #define IMEI_LENGTH 15 |
| | | |
| | | char * GetImei(void) |
| | | { |
| | | JNIEnv *env; |
| | | static char imei[IMEI_LENGTH + 1] = {0}; |
| | | |
| | | LOGD("JNI_GetImei"); |
| | | |
| | | if (strlen(imei) == 0) { |
| | | bool ready_in_java_env = false; |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return imei; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "javaGetImei", "()Ljava/lang/String;"); |
| | | |
| | | jstring ret = (jstring) env->CallObjectMethod(sg_obj, fun); |
| | | |
| | | if (ret != NULL) { |
| | | const char *pret = env->GetStringUTFChars(ret, JNI_FALSE); |
| | | strcpy(imei, pret); |
| | | } |
| | | |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | return imei; |
| | | } |
| | | } |
| | | } |
| | | return imei; |
| | | } |
| | | |
| | | int DESEncrypt(const uint8_t *key, int key_length, |
| | | const uint8_t *plaintext, int plaintext_length, |
| | | uint8_t **ciphertext) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | int ciphertext_length = 0; |
| | | *ciphertext = NULL; |
| | | |
| | | LOGD("JNI_DESEncrypt"); |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return 0; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "javaDESEncrypt", "([B[B)[B"); |
| | | |
| | | jbyteArray jni_key = env->NewByteArray(key_length); |
| | | jbyteArray jni_plaintext = env->NewByteArray(plaintext_length); |
| | | |
| | | env->SetByteArrayRegion(jni_key, 0, key_length, (jbyte *) key); |
| | | env->SetByteArrayRegion(jni_plaintext, 0, plaintext_length, (jbyte *) plaintext); |
| | | |
| | | jbyteArray jni_ciphertext = (jbyteArray) env->CallObjectMethod(sg_obj, fun, jni_plaintext, jni_key); |
| | | if (jni_ciphertext != NULL) { |
| | | ciphertext_length = env->GetArrayLength(jni_ciphertext); |
| | | uint8_t *buffer = (uint8_t *)malloc(ciphertext_length); |
| | | env->GetByteArrayRegion(jni_ciphertext, 0, ciphertext_length, (jbyte *) buffer); |
| | | *ciphertext = buffer; |
| | | } |
| | | |
| | | env->DeleteLocalRef(jni_key); |
| | | env->DeleteLocalRef(jni_plaintext); |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | return ciphertext_length; |
| | | } |
| | | |
| | | void SetPlatformKey(const uint8_t *key, int length) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | |
| | | LOGD("JNI_SetPlatformKey"); |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jbyteArray jni_cmd = env->NewByteArray(length); |
| | | env->SetByteArrayRegion(jni_cmd, 0, length, (jbyte *) key); |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "SetPlatformKey", "([B)V"); |
| | | |
| | | env->CallVoidMethod(sg_obj, fun, jni_cmd); |
| | | |
| | | env->DeleteLocalRef(jni_cmd); |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void DelPlatformKey(void) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "DeletePlatformKey", "()V"); |
| | | |
| | | env->CallVoidMethod(sg_obj, fun); |
| | | |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | int GetPlatformKey(uint8_t *pkey) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | uint8_t key[64] = {0}; |
| | | int key_len = 0; |
| | | |
| | | LOGD("JNI_GetPlatformKey"); |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return 0; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "GetPlatformKey", "()[B"); |
| | | |
| | | jbyteArray jni_cmd = (jbyteArray) env->CallObjectMethod(sg_obj, fun); |
| | | |
| | | if (jni_cmd != NULL) { |
| | | key_len = env->GetArrayLength(jni_cmd); |
| | | if (key_len <= sizeof(key)) { |
| | | env->GetByteArrayRegion(jni_cmd, 0, key_len, (jbyte *) key); |
| | | memcpy(pkey, key, key_len); |
| | | } else { |
| | | key_len = 0; |
| | | } |
| | | } |
| | | |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | return key_len; |
| | | } |
| | | |
| | | void SetSharedValue(const char *key, int value) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | |
| | | LOGD("JNI_SetSharedValue"); |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "SetSharedValue", "(Ljava/lang/String;I)V"); |
| | | |
| | | env->CallVoidMethod(sg_obj, fun, env->NewStringUTF(key), value); |
| | | |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | int GetSharedValue(const char *key) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | int value = 0; |
| | | |
| | | LOGD("JNI_GetSharedValue"); |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return value; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "GetSharedValue", "(Ljava/lang/String;)I"); |
| | | |
| | | value = env->CallIntMethod(sg_obj, fun, env->NewStringUTF(key)); |
| | | |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | return value; |
| | | } |
| | | |
| | | void TextSpeak(const char *text) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "TextSpeak", "(Ljava/lang/String;)V"); |
| | | |
| | | std::string cstext = text; |
| | | env->CallVoidMethod(sg_obj, fun, env->NewStringUTF(cstext.c_str())); |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void TextOsd(int type, const char *text) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "TextOsd", "(ILjava/lang/String;)V"); |
| | | |
| | | std::string cstext = text; |
| | | env->CallVoidMethod(sg_obj, fun, type, env->NewStringUTF(cstext.c_str())); |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void DrawScreen(const Polygon *map, const Polygon *car) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "DrawMap", "([[D[[D)V"); |
| | | |
| | | jclass doubleArrCls = env->FindClass("[D"); |
| | | jobjectArray retmap = env->NewObjectArray(map->num, doubleArrCls, NULL); |
| | | jobjectArray retcar = env->NewObjectArray(car->num, doubleArrCls, NULL); |
| | | |
| | | for (int i = 0; i < map->num; ++i) { |
| | | jdoubleArray doubleArr = env->NewDoubleArray(2); |
| | | jdouble tmp[2] = {map->point[i].X, 0 - map->point[i].Y}; |
| | | |
| | | env->SetDoubleArrayRegion(doubleArr, 0, 2, tmp); |
| | | env->SetObjectArrayElement(retmap, i, doubleArr); |
| | | env->DeleteLocalRef(doubleArr); |
| | | } |
| | | |
| | | for (int i = 0; i < car->num; ++i) { |
| | | jdoubleArray doubleArr = env->NewDoubleArray(2); |
| | | jdouble tmp[2] = {car->point[i].X, 0 - car->point[i].Y}; |
| | | |
| | | env->SetDoubleArrayRegion(doubleArr, 0, 2, tmp); |
| | | env->SetObjectArrayElement(retcar, i, doubleArr); |
| | | env->DeleteLocalRef(doubleArr); |
| | | } |
| | | |
| | | env->CallVoidMethod(sg_obj, fun, retmap, retcar); |
| | | env->DeleteLocalRef(retmap); |
| | | env->DeleteLocalRef(retcar); |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void DisplayText(const char *string) |
| | | { |
| | | DEBUG("DisplayText: %s", string); |
| | | } |
| | | |
| | | void CCL(int who) |
| | | { |
| | | JNIEnv *env; |
| | | bool ready_in_java_env = false; |
| | | static int c[2] = {0}; |
| | | |
| | | if (sg_jvm->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) { |
| | | // Attach主线程 |
| | | if (sg_jvm->AttachCurrentThread(&env, NULL) != JNI_OK) { |
| | | LOGE("%s: AttachCurrentThread() failed", __FUNCTION__); |
| | | return; |
| | | } |
| | | } else { |
| | | ready_in_java_env = true; |
| | | } |
| | | |
| | | jclass cls = env->GetObjectClass(sg_obj); |
| | | jmethodID fun = env->GetMethodID(cls, "CCL", "(II)V"); |
| | | |
| | | env->CallVoidMethod(sg_obj, fun, c[who], who); |
| | | |
| | | c[who] = !c[who]; |
| | | |
| | | env->DeleteLocalRef(cls); |
| | | |
| | | if (!ready_in_java_env) { |
| | | //Detach主线程 |
| | | if (sg_jvm->DetachCurrentThread() != JNI_OK) { |
| | | LOGE("%s: DetachCurrentThread() failed", __FUNCTION__); |
| | | } |
| | | } |
| | | } |
| | | |
| | | extern "C" |
| | | JNIEXPORT void JNICALL |
| | | Java_com_anyun_exam_lib_RemoteService_startNative(JNIEnv *env, jobject thiz) { |
| | | // TODO: implement startNative() |
| | | // 保存全局JVM以便在子线程中使用 |
| | | env->GetJavaVM(&sg_jvm); |
| | | // 不能直接赋值(g_obj = ojb) |
| | | sg_obj = env->NewGlobalRef(thiz); |
| | | |
| | | AppTimer_Init(); |
| | | |
| | | ConfigMCU(); |
| | | DriverTestInit(); |
| | | ConfigRTKModule(); |
| | | |
| | | InitPlatform(phone, RTK_PLATFORM_IP, RTK_PLATFORM_PORT); |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/14. |
| | | // |
| | | |
| | | #ifndef RTKBASESTATION_NATIVE_LIB_H |
| | | #define RTKBASESTATION_NATIVE_LIB_H |
| | | |
| | | #include <cstdint> |
| | | #include "Geometry.h" |
| | | |
| | | char * GetImei(void); |
| | | |
| | | int DESEncrypt(const uint8_t *key, int key_length, |
| | | const uint8_t *plaintext, int plaintext_length, |
| | | uint8_t **ciphertext); |
| | | |
| | | void SetPlatformKey(const uint8_t *key, int length); |
| | | void DelPlatformKey(void); |
| | | int GetPlatformKey(uint8_t *pkey); |
| | | void SetSharedValue(const char *key, int value); |
| | | int GetSharedValue(const char *key); |
| | | void TextSpeak(const char *text); |
| | | void TextOsd(int type, const char *text); |
| | | void DrawScreen(const Polygon *map, const Polygon *car); |
| | | void CCL(int who); |
| | | void DisplayText(const char *string); |
| | | |
| | | #endif //RTKBASESTATION_NATIVE_LIB_H |
New file |
| | |
| | | /********************************************************* |
| | | YY add |
| | | Parse u-blox GPS nmea data |
| | | */ |
| | | #include "parse_gps.h" |
| | | #include "../jni_log.h" |
| | | |
| | | #include <ctype.h> |
| | | #include <stdint.h> |
| | | #include <stdlib.h> |
| | | #include <string.h> |
| | | |
| | | typedef const uint8_t *ptr; |
| | | |
| | | static ptr skip1(ptr s, ptr e) |
| | | { |
| | | if(s) |
| | | while(s != e && (*s == ' ' || *s == '\t' || *s == ',' || *s == ';')) |
| | | ++s; |
| | | return s; |
| | | } |
| | | |
| | | static ptr match2(ptr s, ptr e) |
| | | { |
| | | return s && s != e && (*s == '\r' || *s == '\n') ? s+1 : 0; |
| | | } |
| | | |
| | | static ptr matchChar(ptr s, ptr e, uint8_t c) |
| | | { |
| | | return s && s != e && toupper(*s) == (int) c ? s+1 : 0; |
| | | } |
| | | |
| | | static ptr skipQuote(ptr p, ptr e) |
| | | { |
| | | return p && p != e && *p == '"' ? p+1 : p; |
| | | } |
| | | |
| | | static ptr getString(ptr p, ptr e, struct nmea_sequence *res) |
| | | { |
| | | p = skipQuote(p, e); |
| | | if(p) |
| | | { |
| | | ptr s = p; |
| | | while(p != e && (isalnum(*p) || *p==' ' || *p=='+' || *p=='^' || *p=='-' || *p=='_' || *p=='#' || *p=='.' || *p=='/' || *p==':')) ++p; |
| | | if(p != s) |
| | | { |
| | | res->data = s; |
| | | res->length = p - s; |
| | | return skipQuote(p, e); |
| | | } |
| | | } |
| | | res->data = 0; |
| | | res->length = 0; |
| | | |
| | | return (p != 0 && (*p == ',' || *p == '*')) ? p : 0; |
| | | } |
| | | |
| | | static ptr getHexNumber(ptr p, ptr e, ptr start) |
| | | { |
| | | if(p) |
| | | { |
| | | ptr s = p; |
| | | uint16_t r = 0; |
| | | uint8_t check = 0; |
| | | |
| | | while(p != e && isalnum(*p)) { |
| | | if(isdigit(*p)) { |
| | | r = (r << 4) + (*p++ - '0'); |
| | | } |
| | | else { |
| | | r = (r << 4) + (toupper(*p++) - 'A' + 10); |
| | | } |
| | | } |
| | | if(p != s) { |
| | | |
| | | while(start != s-1) { |
| | | check ^= *start++; |
| | | } |
| | | |
| | | if (check != r) DEBUG("crc error exp %02X but %02X", check, r); |
| | | } |
| | | |
| | | return ( p != s && check == r )? p : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static ptr getHexNumber2(ptr p, ptr e, ptr start) |
| | | { |
| | | if(p) |
| | | { |
| | | ptr s = p; |
| | | uint32_t r = 0; |
| | | |
| | | while(p != e && isalnum(*p)) { |
| | | if(isdigit(*p)) { |
| | | r = (r << 4) + (*p++ - '0'); |
| | | } |
| | | else { |
| | | r = (r << 4) + (toupper(*p++) - 'A' + 10); |
| | | } |
| | | } |
| | | if(p != s) { |
| | | |
| | | } |
| | | |
| | | return ( p != s )? p : 0; |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static ptr findEndOfPacket(ptr s, ptr e) |
| | | { |
| | | if(s == e) return 0; |
| | | |
| | | if(*s == '\r' || *s == '\n') |
| | | { |
| | | return s+1; |
| | | } |
| | | else |
| | | { |
| | | /* expecting ... <cr> */ |
| | | ptr p = s; |
| | | while(p != e && (*p == ' ' || *p == '\t')) ++p; |
| | | while(p != e && *p != '\r') ++p; |
| | | return p == e ? 0 : p+1; |
| | | } |
| | | } |
| | | |
| | | static ptr getNMEA(ptr s, ptr e, struct nmea *res) |
| | | { |
| | | res->nmea_num = 0; |
| | | while(s && s != e && *s != '\r' && *s != '\n' && *s != '*') { |
| | | if(s = matchChar(s, e, ',')) { |
| | | struct nmea_sequence dat; |
| | | |
| | | // LOGD("g = %d", res->nmea_num); |
| | | s = getString(s, e, &dat); |
| | | if(res->nmea_num < MAX_NAEA_NUM) { |
| | | res->nmea_value[res->nmea_num] = dat; |
| | | res->nmea_num += 1; |
| | | } |
| | | } |
| | | else { |
| | | s = 0; |
| | | } |
| | | } |
| | | return s; |
| | | } |
| | | |
| | | static ptr getPARAMS(ptr s, ptr e, struct nmea *res) |
| | | { |
| | | res->nmea_num = 0; |
| | | |
| | | while (s && s != e && *s != '\r' && *s != '\n') { |
| | | while(s != e && (*s == ' ' || *s == '\t')) ++s; |
| | | |
| | | struct nmea_sequence dat; |
| | | s = getString(s, e, &dat); |
| | | if(res->nmea_num < MAX_NAEA_NUM) { |
| | | res->nmea_value[res->nmea_num] = dat; |
| | | res->nmea_num += 1; |
| | | } |
| | | |
| | | while (s != e && (*s == ',')) ++s; |
| | | } |
| | | |
| | | return s; |
| | | } |
| | | |
| | | static ptr getNMEA2(ptr s, ptr e, struct nmea *res) |
| | | { |
| | | bool first = true; |
| | | |
| | | res->nmea_num = 0; |
| | | |
| | | while(s && s != e && *s != '\r' && *s != '\n' && *s != '*') { |
| | | if((first && (s=matchChar(s, e, ';'))) || (s=matchChar(s, e, ','))) { |
| | | first = false; |
| | | |
| | | struct nmea_sequence dat; |
| | | // LOGD("g = %d", res->nmea_num); |
| | | s = getString(s, e, &dat); |
| | | |
| | | if(res->nmea_num < MAX_NAEA_NUM) { |
| | | res->nmea_value[res->nmea_num] = dat; |
| | | res->nmea_num += 1; |
| | | } |
| | | } |
| | | else { |
| | | s = 0; |
| | | } |
| | | } |
| | | return s; |
| | | } |
| | | |
| | | static ptr findSemicolon(ptr s, ptr e) |
| | | { |
| | | while (s && s != e && *s != ';') { |
| | | s++; |
| | | } |
| | | return s; |
| | | } |
| | | |
| | | ptr parseGPS(ptr s, ptr e) |
| | | { |
| | | ptr p; |
| | | for(; (p = findEndOfPacket(s, e)) != 0; s = p) |
| | | { |
| | | if(p == s+1) |
| | | { |
| | | /* Silently discard one character; no packets are that short */ |
| | | continue; |
| | | } |
| | | else |
| | | {//GPGGA GPGSA GPGSV GPRMC GPVTG GPGLL GPZDA |
| | | ptr start = s; |
| | | struct nmea nmeas; |
| | | |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'G'), e, 'G'), e, 'A'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPGGA(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'G'), e, 'S'), e, 'A'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPGSA(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'G'), e, 'S'), e, 'V'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPGSV(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'R'), e, 'M'), e, 'C'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPRMC(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'V'), e, 'T'), e, 'G'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPVTG(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'G'), e, 'L'), e, 'L'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPGLL(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'Z'), e, 'D'), e, 'A'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPZDA(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'P'), e, 'T'), e, 'N'), e, 'L'), e, ','), e, 'P'), e, 'J'), e, 'K'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handlePJK(&nmeas); |
| | | continue; |
| | | } |
| | | if(match2(getHexNumber(matchChar(getNMEA(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '$'), e, 'G'), e, 'P'), e, 'T'), e, 'R'), e, 'A'), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleGPTRA(&nmeas); |
| | | continue; |
| | | } |
| | | if (match2(getHexNumber2(matchChar(getNMEA2(findSemicolon(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(start = matchChar(skip1(s, e), e, '#'), e, 'B'), e, 'E'), e, 'S'), e, 'T'), e, 'P'), e, 'O'), e, 'S'), e, 'A'), e), e, &nmeas), e, '*'), e, start), e)) { |
| | | handleBESTPOSA(&nmeas); |
| | | continue; |
| | | } |
| | | if (match2(getPARAMS(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(skip1(s, e), e, 'P'), e, 'J'), e, 'K'), e, ' '), e, 'P'), e, 'A'), e, 'R'), e, 'A'), e, 'M'), e, 'E'), e, 'T'), e, 'E'), e, 'R'), e, ':'), e, &nmeas), e)) { |
| | | handlePJKParam(&nmeas); |
| | | continue; |
| | | } |
| | | if (match2(getPARAMS(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(matchChar(skip1(s, e), e, 'S'), e, 'T'), e, 'A'), e, 'R'), e, 'T'), e, 'T'), e, 'I'), e, 'M'), e, 'E'), e, ':'), e, &nmeas), e)) { |
| | | handleRTKRebootComp(&nmeas); |
| | | continue; |
| | | } |
| | | handleUnrecognisedNMEA(s, p-s); |
| | | } |
| | | } |
| | | |
| | | return s; |
| | | } |
New file |
| | |
| | | #ifndef _PARSE_GPS_H_ |
| | | #define _PARSE_GPS_H_ |
| | | |
| | | #include <stdint.h> |
| | | |
| | | #define MAX_NAEA_NUM 32 |
| | | |
| | | struct nmea_sequence |
| | | { |
| | | const uint8_t *data; |
| | | uint16_t length; |
| | | }; |
| | | |
| | | struct nmea |
| | | { |
| | | uint16_t nmea_num; |
| | | struct nmea_sequence nmea_value[MAX_NAEA_NUM]; |
| | | }; |
| | | |
| | | const uint8_t *parseGPS(const uint8_t *s, const uint8_t *e); |
| | | |
| | | void handleUnrecognisedNMEA(const uint8_t *data, uint16_t length); |
| | | |
| | | void handleGPGGA(const struct nmea *); |
| | | |
| | | void handleGPGSA(const struct nmea *); |
| | | |
| | | void handleGPGSV(const struct nmea *); |
| | | void handleGPRMC(const struct nmea *); |
| | | void handleGPVTG(const struct nmea *); |
| | | void handleGPGLL(const struct nmea *); |
| | | void handleGPZDA(const struct nmea *); |
| | | void handlePJK(const struct nmea *); |
| | | void handleGPTRA(const struct nmea *); |
| | | void handleBESTPOSA(const struct nmea *); |
| | | void handlePJKParam(const struct nmea *s); |
| | | void handleRTKRebootComp(const struct nmea *s); |
| | | |
| | | #endif |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/23. |
| | | // |
| | | |
| | | #include <cstring> |
| | | #include <cstdio> |
| | | #include <pthread.h> |
| | | #include <cmath> |
| | | #include <cstdlib> |
| | | #include <cctype> |
| | | #include "rtk.h" |
| | | #include "parse_gps.h" |
| | | #include "../common/serial_port.h" |
| | | #include "../jni_log.h" |
| | | #include "../driver_test.h" |
| | | #include "../utils/num.h" |
| | | #include "../defs.h" |
| | | #include "../common/apptimer.h" |
| | | #include "../rtk_platform/platform.h" |
| | | #include "../native-lib.h" |
| | | |
| | | #define RTK_MODULE_UART UART_0 |
| | | |
| | | #define PARSE_BUFF_SIZE 4096 |
| | | |
| | | const static char FACTORY[] = "FRESET\r\n"; |
| | | const static char REBOOT[] = "RESET\r\n"; |
| | | const static char INQ_PJK_PARAM[] = "LOG PJKPARA\r\n"; |
| | | const static char AY_PJKPARAM[] = "set pjkpara 6378137 298.257223563 29.51245330924 106.4553361945 0 0\r\n"; |
| | | const static char UNLOGALL[] = "unlogall\r\n"; |
| | | const static char IFCOM2[] = "interfacemode com2 auto auto on\r\n"; |
| | | const static char SAVECONFIG[] = "saveconfig\r\n"; |
| | | const static char *PJKITEMS[] = {"gptra", "ptnlpjk"}; |
| | | const static char *GPSITEMS[] = {"gpgga", "gprmc", "gpvtg"}; |
| | | |
| | | static gpsStatus_t gpsStatus; |
| | | |
| | | static int tra_hh, tra_mm, tra_ss, tra_dss; |
| | | struct rtk_info CurrRTKInfo; |
| | | static time_t recved_gprmc_time = 0, recved_gpgga_time = 0;; |
| | | |
| | | static void CheckPjkParam(void); |
| | | static void CheckPjkParamTimeout(union sigval sig); |
| | | |
| | | static void *UartThread(void *p); |
| | | |
| | | void ConfigRTKModule(void) |
| | | { |
| | | // TODO |
| | | |
| | | memset(&CurrRTKInfo, 0, sizeof(CurrRTKInfo)); |
| | | tra_hh = tra_mm = tra_ss = tra_dss = 0; |
| | | memset(&gpsStatus, 0, sizeof(gpsStatus)); |
| | | |
| | | static struct serial_config serialConfig; |
| | | |
| | | strcpy(serialConfig.name, "/dev/ttyHSL0"); |
| | | serialConfig.baud = 115200; |
| | | serialConfig.data_bit = 8; |
| | | serialConfig.verify_bit = 'N'; |
| | | serialConfig.stop_bit = 1; |
| | | serialConfig.flow_ctrl = 0; |
| | | |
| | | pthread_t pid; |
| | | pthread_attr_t attr; |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | pthread_create(&pid, &attr, UartThread, &serialConfig); |
| | | } |
| | | |
| | | void FactorySettings(void) |
| | | { |
| | | WriteSerialPort(RTK_MODULE_UART, FACTORY, strlen(FACTORY)); |
| | | } |
| | | |
| | | void RebootModule(void) |
| | | { |
| | | WriteSerialPort(RTK_MODULE_UART, REBOOT, strlen(REBOOT)); |
| | | } |
| | | |
| | | void handleRTKRebootComp(const struct nmea *s) |
| | | { |
| | | DEBUG("RTK Reboot complete!!"); |
| | | SetAYFactoryParam(5); |
| | | } |
| | | |
| | | void handlePJKParam(const struct nmea *s) { |
| | | //PJK Parameter: A:6378137.000, 1/F:298.257223563, B0:0.000000deg, L0:120.000000, N0:0.000, E0:500000.000. |
| | | //PJK Parameter: A:6378137.000, 1/F:298.257223563, B0:29.512453deg, L0:106.455336, N0:0.000, E0:0.000. |
| | | bool setparam = true; |
| | | |
| | | const char DP1[] = "A:6378137.000"; |
| | | const char DP2[] = "1/F:298.257223563"; |
| | | const char DP3[] = "B0:29.512453deg"; |
| | | const char DP4[] = "L0:106.455336"; |
| | | const char DP5[] = "N0:0.000"; |
| | | const char DP6[] = "E0:0.000"; |
| | | |
| | | AppTimer_delete(CheckPjkParamTimeout); |
| | | |
| | | for (int i = 0; i < s->nmea_num; ++i) { |
| | | char out[64] = {0}; |
| | | |
| | | memcpy(out, s->nmea_value[i].data, s->nmea_value[i].length); |
| | | |
| | | DEBUG("handlePJKParam = %s", out); |
| | | } |
| | | |
| | | if (s->nmea_num != 6) return; |
| | | |
| | | if (memcmp(s->nmea_value[0].data, DP1, strlen(DP1))) { |
| | | setparam = true; |
| | | } |
| | | if (memcmp(s->nmea_value[1].data, DP2, strlen(DP2))) { |
| | | setparam = true; |
| | | } |
| | | if (memcmp(s->nmea_value[2].data, DP3, strlen(DP3))) { |
| | | setparam = true; |
| | | } |
| | | if (memcmp(s->nmea_value[3].data, DP4, strlen(DP4))) { |
| | | setparam = true; |
| | | } |
| | | if (memcmp(s->nmea_value[4].data, DP5, strlen(DP5))) { |
| | | setparam = true; |
| | | } |
| | | if (memcmp(s->nmea_value[5].data, DP6, strlen(DP6))) { |
| | | setparam = true; |
| | | } |
| | | |
| | | if (setparam) { |
| | | SetAYFactoryParam(5); |
| | | } |
| | | } |
| | | |
| | | void SetAYFactoryParam(int freq) |
| | | { |
| | | DisplayText("配置RTK模块"); |
| | | |
| | | WriteSerialPort(RTK_MODULE_UART, UNLOGALL, strlen(UNLOGALL)); |
| | | WriteSerialPort(RTK_MODULE_UART, IFCOM2, strlen(IFCOM2)); |
| | | |
| | | if (freq == 0) |
| | | freq = 5; |
| | | |
| | | for (int i = 0; i < sizeof(PJKITEMS)/ sizeof(PJKITEMS[0]); ++i) { |
| | | char cmd[64]; |
| | | sprintf(cmd, "log com1 %s ontime %0.1f\r\n", PJKITEMS[i], 1.0/(double)freq); |
| | | WriteSerialPort(RTK_MODULE_UART, cmd, strlen(cmd)); |
| | | } |
| | | |
| | | for (int i = 0; i < sizeof(GPSITEMS)/ sizeof(GPSITEMS[0]); ++i) { |
| | | char cmd[64]; |
| | | sprintf(cmd, "log com1 %s ontime 1\r\n", GPSITEMS[i]); |
| | | WriteSerialPort(RTK_MODULE_UART, cmd, strlen(cmd)); |
| | | } |
| | | |
| | | WriteSerialPort(RTK_MODULE_UART, AY_PJKPARAM, strlen(AY_PJKPARAM)); |
| | | // WriteSerialPort(RTK_MODULE_UART, SAVECONFIG, strlen(SAVECONFIG)); |
| | | } |
| | | |
| | | void GetGpsStatus(gpsStatus_t &data) |
| | | { |
| | | data = gpsStatus; |
| | | } |
| | | |
| | | static void *UartThread(void *p) { |
| | | struct serial_config *cfg = (struct serial_config *) p; |
| | | |
| | | int res = InitSerialPort(RTK_MODULE_UART, cfg->baud, cfg->data_bit, cfg->verify_bit, cfg->stop_bit, cfg->flow_ctrl); |
| | | DEBUG("Serial %s open %d", cfg->name, res); |
| | | uint8_t RxBuf[PARSE_BUFF_SIZE]; |
| | | int RxBufLen = 0; |
| | | |
| | | if (res == 0) { |
| | | CheckPjkParam(); |
| | | } |
| | | |
| | | while (res == 0) { |
| | | int ul = ReadSerialPort(RTK_MODULE_UART, (uint8_t *)RxBuf + RxBufLen, sizeof(RxBuf) - RxBufLen); |
| | | RxBufLen += ul; |
| | | |
| | | { |
| | | static char buffd[16384]; |
| | | |
| | | buffd[0] = 0; |
| | | int i = 0; |
| | | for (i = 0; i < ul; i++) { |
| | | if ((i % 32) == 0) { |
| | | sprintf(buffd + strlen(buffd), "\n"); |
| | | } |
| | | sprintf(buffd + strlen(buffd), "%02X ", RxBuf[i]); |
| | | if (strlen(buffd) > 800) { |
| | | DEBUG("%s <- %s...", "UART", buffd); |
| | | buffd[0] = 0; |
| | | } |
| | | } |
| | | if (strlen(buffd) > 0) |
| | | DEBUG("%s <- %s", "UART", buffd); |
| | | } |
| | | |
| | | if (RxBufLen > 0) { |
| | | const uint8_t *ptr = parseGPS(RxBuf, RxBuf + RxBufLen); |
| | | if(ptr != RxBuf) { |
| | | memcpy(RxBuf, ptr, RxBufLen - (ptr - RxBuf)); |
| | | RxBufLen -= ptr - RxBuf; |
| | | } else if(RxBufLen == PARSE_BUFF_SIZE) { //填满了,且没有一个\r,都抛弃 |
| | | DEBUG("Parse GPS error"); |
| | | RxBufLen = 0; |
| | | } |
| | | } |
| | | } |
| | | if (res == 0) { |
| | | UninitSerialPort(RTK_MODULE_UART); |
| | | } |
| | | pthread_exit(NULL); |
| | | } |
| | | |
| | | |
| | | void handleUnrecognisedNMEA(const uint8_t *data, uint16_t length) { |
| | | // char buff[4096] = {0}; |
| | | // memcpy(buff, data, MIN(length, 3000)); |
| | | // DEBUG("handleUnrecognisedNMEA: %s", buff); |
| | | } |
| | | |
| | | void handleGPGGA(const struct nmea *s) |
| | | { |
| | | DEBUG("handleGPGGA num = %d", s->nmea_num); |
| | | if (s->nmea_num >= 10) { |
| | | double lat1, lat2, lon1, lon2, alt; |
| | | int qf; |
| | | |
| | | qf = str2int(s->nmea_value[5].data, s->nmea_value[5].length); |
| | | |
| | | if (qf > 0) { |
| | | str2float(&lat1, s->nmea_value[1].data, 2); |
| | | str2float(&lat2, s->nmea_value[1].data+2, s->nmea_value[1].length-2); |
| | | |
| | | str2float(&lon1, s->nmea_value[3].data, 3); |
| | | str2float(&lon2, s->nmea_value[3].data+3, s->nmea_value[3].length-3); |
| | | |
| | | lat1 = lat1 + lat2/60.0; |
| | | lon1 = lon1 + lon2/60.0; |
| | | |
| | | str2float(&alt, s->nmea_value[8].data, s->nmea_value[8].length); |
| | | |
| | | gpsStatus.gps_status = 1; |
| | | gpsStatus.latitude = (uint32_t)(lat1 * 1000000); |
| | | gpsStatus.longitude = (uint32_t)(lon1 * 1000000); |
| | | |
| | | // char buff1[32] = {0}; |
| | | // char buff2[32] = {0}; |
| | | // char buff3[32] = {0}; |
| | | // |
| | | // memcpy(buff1, s->nmea_value[1].data, s->nmea_value[1].length); |
| | | // memcpy(buff2, s->nmea_value[3].data, s->nmea_value[3].length); |
| | | // memcpy(buff3, s->nmea_value[8].data, s->nmea_value[8].length); |
| | | // |
| | | // DEBUG("%s %s %s: lat = %ld lon = %ld alt = %f", buff1, buff2, buff3, gpsStatus.latitude, gpsStatus.longitude, alt); |
| | | |
| | | gpsStatus.altitude = (int) fabs(alt); |
| | | |
| | | recved_gpgga_time = AppTimer_GetTickCount(); |
| | | |
| | | if (abs(recved_gpgga_time - recved_gprmc_time) < 500) { |
| | | RequestRtkDownload(gpsStatus.latitude, gpsStatus.longitude, gpsStatus.altitude, |
| | | gpsStatus.bcd_time, 1); |
| | | } |
| | | } else { |
| | | gpsStatus.gps_status = 0; |
| | | } |
| | | } |
| | | } |
| | | |
| | | void handleGPGSA(const struct nmea *s) { |
| | | } |
| | | |
| | | void handleGPGSV(const struct nmea *s) { |
| | | } |
| | | |
| | | void handleGPRMC(const struct nmea *s) |
| | | { |
| | | DEBUG("handleGPRMC num = %d", s->nmea_num); |
| | | if (s->nmea_num >= 9) { |
| | | |
| | | int hh = str2int(s->nmea_value[0].data, 2); |
| | | int mm = str2int(s->nmea_value[0].data + 2, 2); |
| | | int ss = str2int(s->nmea_value[0].data + 4, 2); |
| | | |
| | | int DD = str2int(s->nmea_value[8].data, 2); |
| | | int MM = str2int(s->nmea_value[8].data + 2, 2); |
| | | int YY = str2int(s->nmea_value[8].data + 4, 2); |
| | | |
| | | gpsStatus.bcd_time[0] = ((YY/10)<<4) + (YY%10); |
| | | gpsStatus.bcd_time[1] = ((MM/10)<<4) + (MM%10); |
| | | gpsStatus.bcd_time[2] = ((DD/10)<<4) + (DD%10); |
| | | gpsStatus.bcd_time[3] = ((hh/10)<<4) + (hh%10); |
| | | gpsStatus.bcd_time[4] = ((ss/10)<<4) + (ss%10); |
| | | gpsStatus.bcd_time[5] = ((mm/10)<<4) + (mm%10); |
| | | |
| | | recved_gprmc_time = AppTimer_GetTickCount(); |
| | | |
| | | if (abs(recved_gpgga_time - recved_gprmc_time) < 500) { |
| | | RequestRtkDownload(gpsStatus.latitude, gpsStatus.longitude, gpsStatus.altitude, |
| | | gpsStatus.bcd_time, 1); |
| | | } |
| | | } |
| | | } |
| | | |
| | | const char *GPS_SOL_OK = "SOL_COMPUTED"; |
| | | const char *GPS_SOL_OBS = "INSUFFICIENT_OBS"; |
| | | const char *GPS_SOL_CS = "COLD_START"; |
| | | |
| | | const char *GPS_POS_NONE = "NONE"; |
| | | const char *GPS_POS_FIX = "FIXEDPOS"; |
| | | const char *GPS_POS_SIG = "SINGLE"; |
| | | const char *GPS_POS_PDIFF = "PSRDIFF"; |
| | | const char *GPS_POS_NARF = "NARROW_FLOAT"; |
| | | const char *GPS_POS_WIDI = "WIDE_INT"; |
| | | const char *GPS_POS_NARI = "NARROW_INT"; |
| | | const char *GPS_POS_SWIDL = "SUPER WIDE-LANE"; |
| | | |
| | | void handleBESTPOSA(const struct nmea *s) { |
| | | DEBUG("handleBESTPOSA num = %d", s->nmea_num); |
| | | double lat, lon; |
| | | |
| | | if (memcmp(s->nmea_value[0].data, GPS_SOL_OK, s->nmea_value[0].length)) { |
| | | str2float(&lat, s->nmea_value[2].data, s->nmea_value[2].length); |
| | | str2float(&lon, s->nmea_value[3].data, s->nmea_value[3].length); |
| | | } |
| | | } |
| | | |
| | | void handleGPVTG(const struct nmea *s) { |
| | | } |
| | | |
| | | void handleGPGLL(const struct nmea *s) { |
| | | } |
| | | |
| | | void handleGPZDA(const struct nmea *s) { |
| | | } |
| | | |
| | | void handlePJK(const struct nmea *s) { |
| | | DEBUG("handlePJK num = %d", s->nmea_num); |
| | | |
| | | CurrRTKInfo.hh = str2int(s->nmea_value[0].data, 2); |
| | | CurrRTKInfo.mm = str2int(s->nmea_value[0].data + 2, 2); |
| | | CurrRTKInfo.ss = str2int(s->nmea_value[0].data + 4, 2); |
| | | CurrRTKInfo.dss = str2int(s->nmea_value[0].data + 7, 2); |
| | | |
| | | CurrRTKInfo.MM = str2int(s->nmea_value[1].data, 2); |
| | | CurrRTKInfo.DD = str2int(s->nmea_value[1].data + 2, 2); |
| | | CurrRTKInfo.YY = str2int(s->nmea_value[1].data + 4, 2); |
| | | |
| | | CurrRTKInfo.qf = str2int(s->nmea_value[6].data, s->nmea_value[6].length); |
| | | |
| | | // NOTE: RTK模块是以南北向为X轴,西东向为Y轴,我们交换下,以符合一般逻辑 |
| | | str2float(&CurrRTKInfo.y, s->nmea_value[2].data, s->nmea_value[2].length); |
| | | str2float(&CurrRTKInfo.x, s->nmea_value[4].data, s->nmea_value[4].length); |
| | | |
| | | |
| | | // const double by1 = 28.013; |
| | | // const double bx1 = -11.9669; |
| | | // |
| | | // const double by2 = 29.3232; |
| | | // const double bx2 = -9.5057; |
| | | // |
| | | // static double xx = -10.9669, yy = 28.013; |
| | | // |
| | | // CurrRTKInfo.y = yy; |
| | | // CurrRTKInfo.x = xx; |
| | | // |
| | | // if (forwardx) { |
| | | // xx += 0.02; |
| | | // yy += 0.02 * (by2 - by1) / (bx2 - bx1); |
| | | // } else { |
| | | // xx -= 0.02; |
| | | // yy -= 0.02 * (by2 - by1) / (bx2 - bx1); |
| | | // } |
| | | |
| | | if (CurrRTKInfo.hh == tra_hh && CurrRTKInfo.mm == tra_mm && CurrRTKInfo.ss == tra_ss && CurrRTKInfo.dss == tra_dss) { |
| | | UpdateRTKInfo(&CurrRTKInfo); |
| | | // up_num++; |
| | | /*if ((up_num % 5) == 0)*/ { |
| | | // NewMgrEvent(DRIVER_UPDATE_EVT); |
| | | } |
| | | } |
| | | } |
| | | |
| | | void handleGPTRA(const struct nmea *s) { |
| | | DEBUG("handleGPTRA num = %d", s->nmea_num); |
| | | |
| | | tra_hh = str2int(s->nmea_value[0].data, 2); |
| | | tra_mm = str2int(s->nmea_value[0].data + 2, 2); |
| | | tra_ss = str2int(s->nmea_value[0].data + 4, 2); |
| | | tra_dss = str2int(s->nmea_value[0].data + 7, 2); |
| | | |
| | | str2float(&CurrRTKInfo.heading, s->nmea_value[1].data, s->nmea_value[1].length); |
| | | |
| | | // CurrRTKInfo.heading = 60; |
| | | |
| | | if (CurrRTKInfo.hh == tra_hh && CurrRTKInfo.mm == tra_mm && CurrRTKInfo.ss == tra_ss && CurrRTKInfo.dss == tra_dss) { |
| | | UpdateRTKInfo(&CurrRTKInfo); |
| | | // up_num++; |
| | | /*if ((up_num % 5) == 0)*/ { |
| | | // NewMgrEvent(DRIVER_UPDATE_EVT); |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void CheckPjkParam(void) |
| | | { |
| | | WriteSerialPort(RTK_MODULE_UART, INQ_PJK_PARAM, strlen(INQ_PJK_PARAM)); |
| | | |
| | | AppTimer_delete(CheckPjkParamTimeout); |
| | | AppTimer_add(CheckPjkParamTimeout, D_SEC(3)); |
| | | } |
| | | |
| | | static void CheckPjkParamTimeout(union sigval sig) { |
| | | AppTimer_delete(CheckPjkParamTimeout); |
| | | |
| | | DEBUG("RTK Module failure!!"); |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/23. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_RTK_H |
| | | #define RTKDRIVERTEST_RTK_H |
| | | |
| | | typedef struct { |
| | | uint16_t gps_status; |
| | | uint32_t latitude; |
| | | uint32_t longitude; |
| | | uint16_t altitude; |
| | | uint8_t bcd_time[6]; |
| | | }gpsStatus_t; |
| | | |
| | | void ConfigRTKModule(void); |
| | | void FactorySettings(void); |
| | | void RebootModule(void); |
| | | void SetAYFactoryParam(int freq); |
| | | void GetGpsStatus(gpsStatus_t &data); |
| | | |
| | | #endif //RTKDRIVERTEST_RTK_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/8. |
| | | // |
| | | |
| | | #include <cstdint> |
| | | #include <cstdio> |
| | | #include <cstring> |
| | | #include <malloc.h> |
| | | #include <pthread.h> |
| | | #include <semaphore.h> |
| | | #include "../jni_log.h" |
| | | #include "../defs.h" |
| | | #include "../native-lib.h" |
| | | #include "parse_net.h" |
| | | #include "../common/apptimer.h" |
| | | #include "../common/serial_port.h" |
| | | #include "../common/net.h" |
| | | #include "platform.h" |
| | | #include "../mcu/mcu_if.h" |
| | | |
| | | using namespace std; |
| | | |
| | | #define PKT_HEAD_CHAR 0x7E |
| | | #define MAX_CONTENT_SIZE 1100 |
| | | #define MAX_MESSAGE_DATA 1023 |
| | | #define PKT_SYNC_HEAD 0x1 |
| | | #define PKT_7D 0x02 |
| | | |
| | | #define DEVICE_SERIAL_NUM_SIZE 16 |
| | | #define PHONE_NUM_SIZE 8 |
| | | #define DEFAULT_MAX_RESEND_CNT 3 |
| | | |
| | | #define DEFAULT_SHORT_RESEND_INTERVAL D_SEC(1) |
| | | #define DEFAULT_LONG_RESEND_INTERVAL D_SEC(2) |
| | | |
| | | typedef struct { |
| | | uint16_t length:10; |
| | | uint16_t encrypt:3; |
| | | uint16_t is_multi_msg:1; |
| | | } message_attrib_t; |
| | | |
| | | typedef struct { |
| | | uint8_t version; |
| | | uint16_t id; |
| | | union { |
| | | message_attrib_t a; |
| | | uint16_t b; |
| | | } attrib; |
| | | uint8_t phone_num[PHONE_NUM_SIZE]; |
| | | uint16_t seq; |
| | | uint8_t reserve; |
| | | uint16_t multi_msg_num; |
| | | uint16_t multi_msg_seq; |
| | | |
| | | uint8_t resend; //消息重传次数,如果消息无需远端应答,就设置为0,否则就应为大于0的值 |
| | | uint32_t resend_interval; |
| | | } message_t; |
| | | |
| | | typedef struct { |
| | | uint16_t type : 1; |
| | | uint16_t need_rsp : 1; |
| | | uint16_t reserve : 2; |
| | | uint16_t encrypt : 4; |
| | | }ex_message_attrib_t; |
| | | |
| | | #define EXTERNAL_ENCRYPT_SIZE 256 |
| | | |
| | | typedef struct { |
| | | uint8_t type; |
| | | uint16_t id; |
| | | union { |
| | | ex_message_attrib_t a; |
| | | uint16_t b; |
| | | }attrib; |
| | | uint16_t seq; |
| | | uint8_t sn[16]; |
| | | uint32_t length; |
| | | uint8_t encrypt[EXTERNAL_ENCRYPT_SIZE]; // 单片机和平台的扩展消息都要处理,故按较长的算 |
| | | } ex_message_t; |
| | | |
| | | typedef struct message_tx_table_ { |
| | | uint8_t access; |
| | | uint16_t id; |
| | | uint16_t seq; |
| | | uint8_t curr_cnt; |
| | | uint8_t max_try_cnt; |
| | | uint32_t resend_interval; |
| | | uint32_t time_out; |
| | | uint32_t length; |
| | | struct message_tx_table_ *prev; |
| | | struct message_tx_table_ *next; |
| | | uint8_t data[0]; |
| | | |
| | | } message_tx_table_t; |
| | | |
| | | #define ID_CP_COMMON_RSP 0x0001 |
| | | #define ID_PC_COMMON_RSP 0x8001 |
| | | #define ID_CP_HEARTBEAT 0x0002 |
| | | #define ID_CP_DEVICE_REG 0x0100 |
| | | #define ID_PC_DEVICE_REG_RSP 0x8100 |
| | | #define ID_CP_LOGIN_REQ 0x0101 |
| | | #define ID_CP_RTK_UPLOAD 0x0301 |
| | | #define ID_CP_RTK_START_REQ 0x0401 |
| | | #define ID_PC_RTK_DOWNLOAD 0x8401 |
| | | #define ID_CP_RTK_END_REQ 0x0402 |
| | | |
| | | |
| | | const uint8_t PKT_RESEVER = 0x3C; |
| | | |
| | | static message_tx_table_t * message_tx_table_head[DATA_ACCESS_END]; |
| | | |
| | | static uint8_t packet_parse_status[DATA_ACCESS_END]; |
| | | static uint8_t packet_buffer[DATA_ACCESS_END][MAX_CONTENT_SIZE]; |
| | | static uint16_t packet_buffer_length[DATA_ACCESS_END]; |
| | | |
| | | struct largeMessage_t{ |
| | | uint16_t currSeq; |
| | | uint32_t length; |
| | | uint8_t *data; |
| | | }largeMessage[DATA_ACCESS_END]; |
| | | |
| | | static uint8_t PhoneNumber[PHONE_NUM_SIZE] = {0}; |
| | | static pthread_mutex_t seq_mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | static pthread_mutex_t tx_queue_mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | |
| | | static void ParseTimeout(union sigval sig); |
| | | static uint32_t GetResendTimeout(uint8_t access, uint8_t curr_resend_cnt, uint32_t base_time); |
| | | static uint16_t GetMessageSeq(uint8_t access); |
| | | static void PacketEntry(uint8_t access, const uint8_t *data, uint16_t length); |
| | | static void MessageEntry(uint8_t access, const message_t *msg, const uint8_t *data, uint32_t length); |
| | | static void MakeMessage(message_t *msg, uint8_t version, uint16_t id, uint8_t encrypt, const uint8_t *phone_number, uint8_t reserve, uint8_t resend, uint32_t resend_intval); |
| | | |
| | | static void SendMessage(uint8_t access, const message_t *srcMsg, const uint8_t *data, uint32_t length); |
| | | static void SendPacket(uint8_t access, const message_t *msg, const uint8_t *data, uint16_t id); |
| | | static message_tx_table_t *FindTxQueue(message_tx_table_t **head, uint16_t id, uint16_t seq); |
| | | static message_tx_table_t *FindTxQueue(message_tx_table_t **head, uint32_t tm); |
| | | static message_tx_table_t *FindTxQueue(message_tx_table_t **head, message_tx_table_t *item); |
| | | static void AddTxQueue(message_tx_table_t **head, uint8_t access, uint16_t id, uint16_t seq, const uint8_t *data, uint32_t length, uint8_t resend, uint32_t resend_intval); |
| | | static void RemoveTxQueue(message_tx_table_t **head, uint16_t id, uint16_t seq); |
| | | static void RemoveTxQueue(message_tx_table_t **head, uint16_t id); |
| | | static void RemoveAllTxQueue(message_tx_table_t **head); |
| | | static int SendQueue(message_tx_table_t *item); |
| | | static void ResendItemTimeout(message_tx_table_t **head, uint32_t tm); |
| | | static uint32_t GetResentTimeoutTxQueue(message_tx_table_t **head); |
| | | |
| | | static void *TxQueueMgrThread(void *p); |
| | | static void TriggerResendTxQueue(union sigval sig); |
| | | |
| | | /* |
| | | 7E 80 89 00 40 87 00 00 01 37 20 20 55 68 00 76 00 9A 41 11 00 22 00 77 00 00 00 00 00 00 00 00 |
| | | 00 00 00 00 00 00 00 00 00 00 00 2C 00 00 02 E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |
| | | 00 00 00 00 00 00 00 00 04 38 36 39 30 37 34 30 33 30 39 34 38 37 30 32 F2 0F 4B 93 32 B6 CE 5C |
| | | 55 98 64 20 D1 7A C6 B7 DB E4 93 15 C9 59 5C F4 54 63 11 5C 81 EE F8 35 52 12 64 A5 51 40 B8 E5 |
| | | D7 4D B8 EF 5F C2 2F D4 E5 EA 20 41 E5 C9 F6 BA 64 04 5B 5B 1D F3 9A 09 9D 7E |
| | | */ |
| | | |
| | | void Parse(uint8_t access, const uint8_t *buff, uint16_t length) { |
| | | /*{ |
| | | static char buffd[16384]; |
| | | |
| | | buffd[0] = 0; |
| | | DEBUG("Parse access = %s Length = %d", access ? "TCP" : "UART", length); |
| | | int i = 0; |
| | | for (i = 0; i < length; i++) { |
| | | if ((i % 32) == 0) { |
| | | sprintf(buffd + strlen(buffd), "\n"); |
| | | } |
| | | sprintf(buffd + strlen(buffd), "%02X ", buff[i]); |
| | | if (strlen(buffd) > 800) { |
| | | DEBUG("%s <- %s...", access ? "TCP" : "UART" , buffd); |
| | | buffd[0] = 0; |
| | | } |
| | | } |
| | | if (strlen(buffd) > 0) |
| | | DEBUG("%s <- %s", access ? "TCP" : "UART" , buffd); |
| | | }*/ |
| | | |
| | | for (uint16_t i = 0; i < length; i++) { |
| | | unsigned char dat = buff[i]; |
| | | if (packet_parse_status[access] & PKT_SYNC_HEAD) { |
| | | if (dat == PKT_HEAD_CHAR) { |
| | | packet_parse_status[access] &= ~PKT_SYNC_HEAD; |
| | | packet_parse_status[access] &= ~PKT_7D; |
| | | packet_buffer_length[access] = 0; |
| | | |
| | | AppTimer_add(ParseTimeout, D_SEC(5), access); |
| | | } |
| | | } else { |
| | | if (dat == PKT_HEAD_CHAR) { |
| | | if (packet_buffer_length[access] == 0) { |
| | | /* 出现0长度载荷的情况,往往是单片机过来的数据[7E..]..7E,7E.....7E的括号内丢失了,和后一个7E头结合在一起*/ |
| | | packet_parse_status[access] &= ~PKT_7D; |
| | | |
| | | AppTimer_add(ParseTimeout, D_SEC(5), access); |
| | | } else { |
| | | AppTimer_delete(ParseTimeout); |
| | | packet_parse_status[access] = PKT_SYNC_HEAD; |
| | | PacketEntry(access, packet_buffer[access], packet_buffer_length[access]); |
| | | } |
| | | continue; |
| | | } else if (dat == 0x7D && !(packet_parse_status[access] & PKT_7D)) { |
| | | packet_parse_status[access] |= PKT_7D; |
| | | continue; |
| | | } |
| | | |
| | | if (packet_parse_status[access] & PKT_7D) { |
| | | packet_parse_status[access] &= ~PKT_7D; |
| | | dat = 0x7D + dat - 1; |
| | | } |
| | | |
| | | if (packet_buffer_length[access] < MAX_CONTENT_SIZE) { |
| | | packet_buffer[access][ packet_buffer_length[access] ] = dat; |
| | | packet_buffer_length[access]++; |
| | | } else { // Too much, discard |
| | | DEBUG("Parse error: pkt too large!"); |
| | | AppTimer_delete(ParseTimeout); |
| | | packet_parse_status[access] = PKT_SYNC_HEAD; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void ParseTimeout(union sigval sig) { |
| | | AppTimer_delete(ParseTimeout); |
| | | packet_parse_status[sig.sival_int] = PKT_SYNC_HEAD; |
| | | |
| | | DEBUG("ParseTimeout %d", sig.sival_int); |
| | | } |
| | | |
| | | static uint32_t GetResendTimeout(uint8_t access, uint8_t curr_resend_cnt, uint32_t base_time) |
| | | { |
| | | if (access == DATA_ACCESS_MCU) { |
| | | return base_time; |
| | | } |
| | | |
| | | //T2 = T1 * (n + 1), 首次时间认为是1秒 |
| | | uint32_t t = base_time; |
| | | for (int i = 0; i <= curr_resend_cnt; i++) { |
| | | t = t * (i + 1); |
| | | } |
| | | |
| | | return t; |
| | | } |
| | | |
| | | static uint16_t GetMessageSeq(uint8_t access) |
| | | { |
| | | static uint16_t TxSeq[DATA_ACCESS_END] = {0}; |
| | | uint16_t seq; |
| | | |
| | | pthread_mutex_lock(&seq_mutex); |
| | | seq = TxSeq[access]; |
| | | TxSeq[access]++; |
| | | pthread_mutex_unlock(&seq_mutex); |
| | | |
| | | return seq; |
| | | } |
| | | |
| | | static void PacketEntry(uint8_t access, const uint8_t *data, uint16_t length) { |
| | | uint16_t i, x = 0; |
| | | uint8_t checkByte = 0; |
| | | message_t theMessage; |
| | | |
| | | for (i = 0; i < length; i++) { |
| | | checkByte ^= data[i]; |
| | | } |
| | | |
| | | if (checkByte != 0 || length <= 16) { |
| | | DEBUG("recv pkt error, checkByte: 0x%02X, length: %d", checkByte, length); |
| | | return; |
| | | } |
| | | |
| | | |
| | | length--; // Ignore check byte |
| | | theMessage.version = data[x++]; |
| | | theMessage.id = BUILD_UINT16(data[x + 1], data[x]); |
| | | x += 2; |
| | | theMessage.attrib.b = BUILD_UINT16(data[x + 1], data[x]); |
| | | x += 2; |
| | | memcpy(theMessage.phone_num, data + x, PHONE_NUM_SIZE); |
| | | x += PHONE_NUM_SIZE; |
| | | theMessage.seq = BUILD_UINT16(data[x + 1], data[x]); |
| | | x += 2; |
| | | |
| | | theMessage.reserve = data[x++]; |
| | | theMessage.resend = DEFAULT_MAX_RESEND_CNT; |
| | | |
| | | if (theMessage.attrib.a.is_multi_msg) { |
| | | if (x + 4 <= length) { |
| | | theMessage.multi_msg_num = BUILD_UINT16(data[x + 1], data[x]); |
| | | theMessage.multi_msg_seq = BUILD_UINT16(data[x + 3], data[x + 2]); |
| | | x += 4; |
| | | |
| | | if (theMessage.multi_msg_seq == 1) { |
| | | // First multi-msg |
| | | largeMessage[access].currSeq = 1; |
| | | largeMessage[access].length = 0; |
| | | |
| | | if (largeMessage[access].data != NULL) { |
| | | largeMessage[access].data = (uint8_t *) realloc(largeMessage[access].data, |
| | | theMessage.multi_msg_num * MAX_MESSAGE_DATA); |
| | | } else { |
| | | largeMessage[access].data = (uint8_t *) malloc( |
| | | theMessage.multi_msg_num * MAX_MESSAGE_DATA); |
| | | } |
| | | |
| | | memcpy(largeMessage[access].data, data + x, theMessage.attrib.a.length); |
| | | largeMessage[access].length = theMessage.attrib.a.length; |
| | | CommonRespend(access, theMessage.seq, theMessage.id, COMMON_RESP_SUCCESS); |
| | | } else if (largeMessage[access].data != NULL && |
| | | theMessage.multi_msg_seq != largeMessage[access].currSeq + 1) { |
| | | //请求重传分包? |
| | | CommonRespend(access, theMessage.seq, theMessage.id, COMMON_RESP_FAIL); |
| | | return; |
| | | } else if (largeMessage[access].data != NULL){ |
| | | largeMessage[access].currSeq = theMessage.multi_msg_seq; |
| | | |
| | | memcpy(largeMessage[access].data + largeMessage[access].length, data + x, theMessage.attrib.a.length); |
| | | largeMessage[access].length += theMessage.attrib.a.length; |
| | | |
| | | CommonRespend(access, theMessage.seq, theMessage.id, COMMON_RESP_SUCCESS); |
| | | |
| | | if (theMessage.multi_msg_seq == theMessage.multi_msg_num) { |
| | | DEBUG("多包接收完毕 %d %d\n", theMessage.multi_msg_seq, largeMessage[access].length); |
| | | MessageEntry(access, &theMessage, largeMessage[access].data, largeMessage[access].length); |
| | | free(largeMessage[access].data); |
| | | largeMessage[access].data = NULL; |
| | | } |
| | | } |
| | | } else { |
| | | // Length error |
| | | return; |
| | | } |
| | | } else { |
| | | MessageEntry(access, &theMessage, data + x, theMessage.attrib.a.length); |
| | | } |
| | | } |
| | | |
| | | static void MessageEntry(uint8_t access, const message_t *msg, const uint8_t *data, uint32_t length) |
| | | { |
| | | DEBUG("MessageEntry[%d] id = 0x%04X, seq = %d, length = %d", access, msg->id, msg->seq, length); |
| | | |
| | | switch (msg->id) { |
| | | case ID_PC_COMMON_RSP: |
| | | if (length == 5) { |
| | | uint16_t seq = BUILD_UINT16(data[1], data[0]); |
| | | uint16_t id = BUILD_UINT16(data[3], data[2]); |
| | | uint8_t res = data[4]; |
| | | |
| | | DEBUG("ID_PC_COMMON_RSP seq = %d, id = 0x%04X res = %d", seq, id, res); |
| | | |
| | | RemoveTxQueue(&message_tx_table_head[DATA_ACCESS_PLATFORM], id); |
| | | |
| | | if (id == ID_CP_LOGIN_REQ) { |
| | | DeviceLoginCallback(res); |
| | | } |
| | | } |
| | | break; |
| | | case ID_PC_DEVICE_REG_RSP: { |
| | | DEBUG("ID_PC_DEVICE_REG_RSP"); |
| | | RemoveTxQueue(&message_tx_table_head[DATA_ACCESS_PLATFORM], ID_CP_DEVICE_REG); |
| | | if (length >= 3) { |
| | | if (data[2] == 0 && length == 11) { |
| | | DeviceRegisterCallback(0, data + 3, 8); |
| | | } else { |
| | | DeviceRegisterCallback(data[2], 0, 0); |
| | | } |
| | | } |
| | | break; |
| | | } |
| | | case ID_PC_RTK_DOWNLOAD: |
| | | DEBUG("ID_PC_RTK_DOWNLOAD"); |
| | | // 汇报给单片机 |
| | | if (length > 0) { |
| | | SendRtkToMcu(data, length); |
| | | } |
| | | break; |
| | | default: |
| | | break; |
| | | } |
| | | |
| | | CommonRespend(access, msg->seq, msg->id, COMMON_RESP_FAIL); |
| | | } |
| | | |
| | | static void MakeMessage(message_t *msg, uint8_t version, uint16_t id, uint8_t encrypt, const uint8_t *phone_number, uint8_t reserve, uint8_t resend, uint32_t resend_intval) |
| | | { |
| | | msg->version = version; |
| | | msg->id = id; |
| | | msg->attrib.b = 0; |
| | | msg->attrib.a.encrypt = encrypt; |
| | | memcpy(msg->phone_num, phone_number, PHONE_NUM_SIZE); |
| | | msg->reserve = reserve; |
| | | msg->resend = resend; |
| | | msg->resend_interval = resend_intval; |
| | | } |
| | | |
| | | static void SendMessage(uint8_t access, const message_t *srcMsg, const uint8_t *data, uint32_t length) |
| | | { |
| | | uint16_t total_num = (length + MAX_MESSAGE_DATA - 1) / MAX_MESSAGE_DATA; |
| | | uint32_t x = 0; |
| | | message_t msg = *srcMsg; |
| | | |
| | | if (length == 0) { |
| | | total_num = 1; |
| | | } |
| | | |
| | | msg.attrib.a.is_multi_msg = (total_num > 1 ? 1 : 0); |
| | | |
| | | DEBUG("length = %d, total_num %d\n", length, total_num); |
| | | |
| | | for (uint16_t curr_num = 1; curr_num <= total_num; curr_num++) { |
| | | uint32_t load = 0; |
| | | |
| | | DEBUG("curr_num %d\n", curr_num); |
| | | |
| | | msg.seq = GetMessageSeq(access); |
| | | |
| | | if (msg.attrib.a.is_multi_msg) { |
| | | msg.multi_msg_num = total_num; |
| | | msg.multi_msg_seq = curr_num; |
| | | } |
| | | |
| | | load = (length - x > MAX_MESSAGE_DATA) ? MAX_MESSAGE_DATA : (length - x); |
| | | msg.attrib.a.length = load; |
| | | |
| | | DEBUG("load %d\n", load); |
| | | |
| | | SendPacket(access, &msg, data + x, msg.id); |
| | | x += load; |
| | | } |
| | | } |
| | | |
| | | static void SendPacket(uint8_t access, const message_t *msg, const uint8_t *data, uint16_t id) { |
| | | uint8_t buffer[MAX_CONTENT_SIZE]; |
| | | uint8_t buffer2[MAX_CONTENT_SIZE*2]; |
| | | |
| | | uint16_t x = 0; |
| | | |
| | | DEBUG("SendPacket len = %d", msg->attrib.a.length); |
| | | |
| | | buffer[x++] = msg->version; |
| | | buffer[x++] = HI_UINT16(msg->id); |
| | | buffer[x++] = LO_UINT16(msg->id); |
| | | buffer[x++] = HI_UINT16(msg->attrib.b); |
| | | buffer[x++] = LO_UINT16(msg->attrib.b); |
| | | memcpy(buffer + x, msg->phone_num, PHONE_NUM_SIZE); |
| | | x += PHONE_NUM_SIZE; |
| | | buffer[x++] = HI_UINT16(msg->seq); |
| | | buffer[x++] = LO_UINT16(msg->seq); |
| | | buffer[x++] = msg->reserve; |
| | | if (msg->attrib.a.is_multi_msg) { |
| | | buffer[x++] = HI_UINT16(msg->multi_msg_num); |
| | | buffer[x++] = LO_UINT16(msg->multi_msg_num); |
| | | buffer[x++] = HI_UINT16(msg->multi_msg_seq); |
| | | buffer[x++] = LO_UINT16(msg->multi_msg_seq); |
| | | } |
| | | |
| | | memcpy(buffer + x, data, msg->attrib.a.length); |
| | | x += msg->attrib.a.length; |
| | | |
| | | uint8_t checkByte = 0; |
| | | for (int i = 0; i < x; i++) { |
| | | checkByte ^= buffer[i]; |
| | | } |
| | | buffer[x++] = checkByte; |
| | | |
| | | uint32_t y = 0; |
| | | buffer2[y++] = PKT_HEAD_CHAR; |
| | | for (int i = 0; i < x; i++) { |
| | | if (buffer[i] == 0x7E) { |
| | | buffer2[y++] = 0x7D; |
| | | buffer2[y++] = 0x02; |
| | | } else if (buffer[i] == 0x7D) { |
| | | buffer2[y++] = 0x7D; |
| | | buffer2[y++] = 0x01; |
| | | } else { |
| | | buffer2[y++] = buffer[i]; |
| | | } |
| | | } |
| | | buffer2[y++] = PKT_HEAD_CHAR; |
| | | |
| | | AddTxQueue(&message_tx_table_head[access], access, id, msg->seq, buffer2, y, msg->resend, msg->resend_interval); |
| | | } |
| | | |
| | | |
| | | static message_tx_table_t *FindTxQueue(message_tx_table_t **head, uint16_t id, uint16_t seq) |
| | | { |
| | | if (head == NULL) { |
| | | return NULL; |
| | | } |
| | | for (message_tx_table_t *ptr = *head; ptr != NULL; ptr = ptr->next) { |
| | | if (ptr->id == id && ptr->seq == seq) { |
| | | return ptr; |
| | | } |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | static message_tx_table_t *FindTxQueue(message_tx_table_t **head, uint32_t tm) |
| | | { |
| | | if (head == NULL) { |
| | | return NULL; |
| | | } |
| | | |
| | | for (message_tx_table_t *ptr = *head; ptr != NULL; ptr = ptr->next) { |
| | | if (ptr->time_out <= tm) { |
| | | return ptr; |
| | | } |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | static message_tx_table_t *FindTxQueue(message_tx_table_t **head, message_tx_table_t *item) |
| | | { |
| | | if (head == NULL) { |
| | | return NULL; |
| | | } |
| | | for (message_tx_table_t *ptr = *head; ptr != NULL; ptr = ptr->next) { |
| | | if (ptr == item) { |
| | | return ptr; |
| | | } |
| | | } |
| | | return NULL; |
| | | } |
| | | |
| | | static void AddTxQueue(message_tx_table_t **head, uint8_t access, uint16_t id, uint16_t seq, const uint8_t *data, uint32_t length, uint8_t resend, uint32_t resend_intval) |
| | | { |
| | | message_tx_table_t *new_item; |
| | | |
| | | if (length == 0 || head == NULL) { |
| | | return; |
| | | } |
| | | |
| | | DEBUG("AddTxQueue id = 0x%X, seq = %d, len = %d", id, seq, length); |
| | | |
| | | pthread_mutex_lock(&tx_queue_mutex); |
| | | |
| | | // If the item is exist, skip it |
| | | if (FindTxQueue(head, id, seq) != NULL) { |
| | | DEBUG("已经有了,我们不干了"); |
| | | goto ATQ_END; |
| | | } |
| | | |
| | | if ((new_item = (message_tx_table_t *)malloc(sizeof(message_tx_table_t) + length))== NULL) { // Not enough memory! |
| | | LOGE("Not enough memory!"); |
| | | goto ATQ_END; |
| | | } |
| | | |
| | | new_item->next = NULL; |
| | | new_item->access = access; |
| | | new_item->id = id; |
| | | new_item->seq = seq; |
| | | new_item->length = length; |
| | | new_item->curr_cnt = 0; |
| | | new_item->max_try_cnt = 1 + resend; // Zero means unlimited |
| | | new_item->resend_interval = resend_intval; |
| | | new_item->time_out = resend_intval + AppTimer_GetTickCount(); |
| | | memcpy(new_item->data, data, length); |
| | | |
| | | if (*head == NULL) { |
| | | new_item->prev = NULL; |
| | | *head = new_item; |
| | | |
| | | DEBUG("############### Create head node ##################"); |
| | | |
| | | } else { |
| | | message_tx_table_t *ptr = *head; |
| | | while (ptr->next != NULL) { |
| | | ptr = ptr->next; |
| | | } |
| | | |
| | | ptr->next = new_item; |
| | | new_item->prev = ptr; |
| | | } |
| | | |
| | | SendQueue(new_item); |
| | | |
| | | if (new_item->max_try_cnt > 0 && new_item->curr_cnt >= new_item->max_try_cnt) { |
| | | if (new_item == *head) { |
| | | if (new_item->next == NULL) { |
| | | *head = NULL; |
| | | DEBUG("****************** Delete all ******************"); |
| | | } else { |
| | | *head = new_item->next; |
| | | new_item->next->prev = NULL; |
| | | } |
| | | } else { |
| | | if (new_item->next != NULL) { |
| | | new_item->next->prev = new_item->prev; |
| | | } |
| | | new_item->prev->next = new_item->next; |
| | | } |
| | | free(new_item); |
| | | } |
| | | |
| | | ATQ_END: |
| | | pthread_mutex_unlock(&tx_queue_mutex); |
| | | |
| | | uint32_t tim = GetResentTimeoutTxQueue(&message_tx_table_head[DATA_ACCESS_PLATFORM]); |
| | | |
| | | DEBUG("NEXT ==== %ld", tim); |
| | | |
| | | AppTimer_delete(TriggerResendTxQueue); |
| | | if (tim != uint32_t (-1)) { |
| | | AppTimer_add(TriggerResendTxQueue, tim); |
| | | } |
| | | } |
| | | |
| | | static void RemoveTxQueue(message_tx_table_t **head, uint16_t id, uint16_t seq) |
| | | { |
| | | if (head == NULL) |
| | | return; |
| | | |
| | | message_tx_table_t *ptr = *head; |
| | | |
| | | pthread_mutex_lock(&tx_queue_mutex); |
| | | while ( ptr != NULL ) { |
| | | if (ptr->id == id && ptr->seq == seq) { |
| | | // delete |
| | | message_tx_table_t *temp = ptr; |
| | | |
| | | if (ptr == *head) { |
| | | if (ptr->next == NULL) { |
| | | DEBUG("****************** RemoveTxQueue Delete all ******************"); |
| | | ptr = *head = NULL; |
| | | } else { |
| | | *head = ptr->next; |
| | | ptr->next->prev = NULL; |
| | | ptr = *head; |
| | | } |
| | | } else { |
| | | if (ptr->next != NULL) { |
| | | ptr->next->prev = ptr->prev; |
| | | } |
| | | ptr->prev->next = ptr->next; |
| | | ptr = ptr->next; |
| | | } |
| | | |
| | | free(temp); |
| | | } else { |
| | | ptr = ptr->next; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&tx_queue_mutex); |
| | | } |
| | | |
| | | static void RemoveTxQueue(message_tx_table_t **head, uint16_t id) |
| | | { |
| | | if (head == NULL) |
| | | return; |
| | | |
| | | message_tx_table_t *ptr = *head; |
| | | |
| | | pthread_mutex_lock(&tx_queue_mutex); |
| | | while ( ptr != NULL ) { |
| | | if (ptr->id == id) { |
| | | // delete |
| | | message_tx_table_t *temp = ptr; |
| | | DEBUG("****************** 我们找到了, 弄死它 ******************"); |
| | | |
| | | if (ptr == *head) { |
| | | if (ptr->next == NULL) { |
| | | DEBUG("****************** RemoveTxQueue Delete all ******************"); |
| | | ptr = *head = NULL; |
| | | } else { |
| | | *head = ptr->next; |
| | | ptr->next->prev = NULL; |
| | | ptr = *head; |
| | | } |
| | | } else { |
| | | if (ptr->next != NULL) { |
| | | ptr->next->prev = ptr->prev; |
| | | } |
| | | ptr->prev->next = ptr->next; |
| | | ptr = ptr->next; |
| | | } |
| | | |
| | | free(temp); |
| | | } else { |
| | | ptr = ptr->next; |
| | | } |
| | | } |
| | | pthread_mutex_unlock(&tx_queue_mutex); |
| | | } |
| | | |
| | | static void RemoveAllTxQueue(message_tx_table_t **head) |
| | | { |
| | | if (head == NULL) { |
| | | return; |
| | | } |
| | | |
| | | pthread_mutex_lock(&tx_queue_mutex); |
| | | for (message_tx_table_t *ptr = *head, *next; ptr != NULL; ptr = next) { |
| | | next = ptr->next; |
| | | free(ptr); |
| | | } |
| | | *head = NULL; |
| | | pthread_mutex_unlock(&tx_queue_mutex); |
| | | } |
| | | |
| | | static int SendQueue(message_tx_table_t *item) |
| | | { |
| | | DEBUG("SendQueue id = 0x%04X, seq = %d, length = %d", item->id, item->seq, item->length); |
| | | if (item != NULL) { |
| | | if (item->access == DATA_ACCESS_MCU) { |
| | | if (WriteSerialPort(GetSerialPort(UART_1), item->data, item->length) != item->length) { |
| | | item->time_out = 100 + AppTimer_GetTickCount(); |
| | | LOGE("发往串口出错了"); |
| | | // return -1; |
| | | } |
| | | } else if(item->access == DATA_ACCESS_PLATFORM) { |
| | | if (WritePlatform(item->data, item->length) != item->length) { |
| | | item->time_out = D_SEC(3) + AppTimer_GetTickCount(); |
| | | LOGE("发往网络出错了 seq = %d", item->seq); |
| | | // return -2; |
| | | } |
| | | } else { |
| | | // return 0; |
| | | } |
| | | |
| | | #ifdef ENABLE_DEBUG_PROTOCOL |
| | | /*{ |
| | | static char buff[16384]; |
| | | |
| | | buff[0] = 0; |
| | | |
| | | int i = 0; |
| | | for (i = 0; i < item->length; i++) { |
| | | if ((i % 32) == 0) { |
| | | sprintf(buff + strlen(buff), "\n"); |
| | | } |
| | | sprintf(buff + strlen(buff), "%02X ", item->data[i]); |
| | | |
| | | if (strlen(buff) > 800) { |
| | | DEBUG("%s -> %s...", item->access == DATA_ACCESS_MCU ? "UART" : "TCP" , buff); |
| | | buff[0] = 0; |
| | | } |
| | | } |
| | | |
| | | if (strlen(buff) > 0) { |
| | | DEBUG("%s -> %s", item->access == DATA_ACCESS_MCU ? "UART" : "TCP", buff); |
| | | } |
| | | }*/ |
| | | #endif |
| | | // 系统层确认发送成功 |
| | | item->curr_cnt += 1; |
| | | item->time_out = GetResendTimeout(item->access, item->curr_cnt - 1, item->resend_interval) + AppTimer_GetTickCount(); |
| | | } |
| | | return 0; |
| | | } |
| | | |
| | | static void ResendItemTimeout(message_tx_table_t **head, uint32_t tm) |
| | | { |
| | | if (head == NULL) |
| | | return; |
| | | |
| | | message_tx_table_t *ptr = *head; |
| | | |
| | | while ( ptr != NULL ) { |
| | | if (ptr->time_out <= tm) { |
| | | // send |
| | | LOGE("重发 id 0x%04X seq %d", ptr->id, ptr->seq); |
| | | int ret = SendQueue(ptr); |
| | | if (ret < 0 && ret != -3) { |
| | | break; |
| | | } |
| | | if (ptr->max_try_cnt > 0 && ptr->curr_cnt >= ptr->max_try_cnt) { |
| | | // delete |
| | | DEBUG("Delete item %d", ptr->curr_cnt); |
| | | message_tx_table_t *temp = ptr; |
| | | |
| | | pthread_mutex_lock(&tx_queue_mutex); |
| | | if (ptr == *head) { |
| | | if (ptr->next == NULL) { |
| | | DEBUG("****************** Delete all 2 ******************"); |
| | | ptr = *head = NULL; |
| | | } else { |
| | | *head = ptr->next; |
| | | ptr->next->prev = NULL; |
| | | ptr = *head; |
| | | } |
| | | } else { |
| | | if (ptr->next != NULL) { |
| | | ptr->next->prev = ptr->prev; |
| | | } |
| | | ptr->prev->next = ptr->next; |
| | | ptr = ptr->next; |
| | | } |
| | | pthread_mutex_unlock(&tx_queue_mutex); |
| | | |
| | | free(temp); |
| | | } else { |
| | | ptr = ptr->next; |
| | | } |
| | | } else { |
| | | ptr = ptr->next; |
| | | } |
| | | } |
| | | } |
| | | |
| | | static uint32_t GetResentTimeoutTxQueue(message_tx_table_t **head) |
| | | { |
| | | uint32_t resentTime = uint32_t (-1); |
| | | uint32_t now = AppTimer_GetTickCount(); |
| | | |
| | | if (head == NULL) |
| | | return resentTime; |
| | | |
| | | pthread_mutex_lock(&tx_queue_mutex); |
| | | message_tx_table_t *ptr = *head; |
| | | |
| | | while ( ptr != NULL ) { |
| | | if (ptr->time_out <= now) { |
| | | resentTime = 0; |
| | | break; |
| | | } else if (ptr->time_out - now < resentTime) { |
| | | resentTime = ptr->time_out - now; |
| | | } |
| | | ptr = ptr->next; |
| | | } |
| | | pthread_mutex_unlock(&tx_queue_mutex); |
| | | |
| | | return resentTime; |
| | | } |
| | | |
| | | static sem_t sem_tx_mgr; |
| | | |
| | | static void *TxQueueMgrThread(void *p) { |
| | | while (true) { |
| | | sem_wait(&sem_tx_mgr); |
| | | uint32_t tim = AppTimer_GetTickCount(); |
| | | |
| | | DEBUG("TxQueueMgrThread %ld", tim); |
| | | |
| | | // Check send queue, and resend |
| | | ResendItemTimeout(&message_tx_table_head[DATA_ACCESS_PLATFORM], tim); |
| | | |
| | | tim = GetResentTimeoutTxQueue(&message_tx_table_head[DATA_ACCESS_PLATFORM]); |
| | | |
| | | DEBUG("NEXT ==== %ld", tim); |
| | | AppTimer_delete(TriggerResendTxQueue); |
| | | if (tim != uint32_t (-1)) { |
| | | AppTimer_add(TriggerResendTxQueue, tim); |
| | | } |
| | | } |
| | | pthread_exit(NULL); |
| | | } |
| | | |
| | | static void TriggerResendTxQueue(union sigval sig) { |
| | | AppTimer_delete(TriggerResendTxQueue); |
| | | sem_post(&sem_tx_mgr); |
| | | } |
| | | |
| | | void PlatformTxInit(const uint8_t *phone) |
| | | { |
| | | //2019101500000001 |
| | | memcpy(PhoneNumber, phone, PHONE_NUM_SIZE); |
| | | |
| | | /* PhoneNumber[0] = 0x20; |
| | | PhoneNumber[1] = 0x19; |
| | | PhoneNumber[2] = 0x10; |
| | | PhoneNumber[3] = 0x15; |
| | | PhoneNumber[4] = 0x00; |
| | | PhoneNumber[5] = 0x00; |
| | | PhoneNumber[6] = 0x00; |
| | | PhoneNumber[7] = 0x02;*/ |
| | | |
| | | pthread_mutex_init(&seq_mutex, NULL); |
| | | pthread_mutex_init(&tx_queue_mutex, NULL); |
| | | sem_init(&sem_tx_mgr, 0, 0); |
| | | |
| | | pthread_t pid; |
| | | pthread_attr_t attr; |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | pthread_create(&pid, &attr, TxQueueMgrThread, NULL); |
| | | } |
| | | |
| | | void CommonRespend(uint8_t access, uint16_t seq, uint16_t id, uint8_t value) |
| | | { |
| | | uint8_t data[5]; |
| | | |
| | | data[0] = HI_UINT16(seq); |
| | | data[1] = LO_UINT16(seq); |
| | | data[2] = HI_UINT16(id); |
| | | data[3] = LO_UINT16(id); |
| | | data[4] = value; |
| | | |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_COMMON_RSP, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | |
| | | SendMessage(access, &msg, data, sizeof(data)); |
| | | } |
| | | |
| | | void SendHeartBeat(uint8_t access) |
| | | { |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_HEARTBEAT, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | SendMessage(access, &msg, NULL, 0); |
| | | } |
| | | |
| | | void SendDeviceRegister(uint16_t province, uint16_t city, const uint8_t *device_model, |
| | | int device_model_length, const uint8_t *device_sn, const char *imei) |
| | | { |
| | | uint8_t data[64] = {0}; |
| | | int x = 0; |
| | | |
| | | data[x++] = HI_UINT16(province); |
| | | data[x++] = LO_UINT16(province); |
| | | data[x++] = HI_UINT16(city); |
| | | data[x++] = LO_UINT16(city); |
| | | memcpy(data + x, device_model, device_model_length); |
| | | x += 20; |
| | | memcpy(data + x, device_sn, 16); |
| | | x += 16; |
| | | memcpy(data + x, imei, strlen(imei)); |
| | | x += 15; |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_DEVICE_REG, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | SendMessage(DATA_ACCESS_PLATFORM, &msg, data, x); |
| | | } |
| | | |
| | | void SendDeviceLogin(const uint8_t *data, int length) |
| | | { |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_LOGIN_REQ, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | SendMessage(DATA_ACCESS_PLATFORM, &msg, data, length); |
| | | } |
| | | |
| | | void SendRTKReport(uint8_t gps_status, uint32_t latitude, uint32_t longitude, uint16_t altitude, |
| | | const uint8_t *bcd_time, const uint8_t *rtk, int rtk_length) |
| | | { |
| | | uint8_t data[MAX_CONTENT_SIZE]; |
| | | int x = 0; |
| | | |
| | | data[x++] = gps_status; |
| | | data[x++] = BREAK_UINT32(latitude, 3); |
| | | data[x++] = BREAK_UINT32(latitude, 2); |
| | | data[x++] = BREAK_UINT32(latitude, 1); |
| | | data[x++] = BREAK_UINT32(latitude, 0); |
| | | data[x++] = BREAK_UINT32(longitude, 3); |
| | | data[x++] = BREAK_UINT32(longitude, 2); |
| | | data[x++] = BREAK_UINT32(longitude, 1); |
| | | data[x++] = BREAK_UINT32(longitude, 0); |
| | | data[x++] = HI_UINT16(altitude); |
| | | data[x++] = LO_UINT16(altitude); |
| | | memcpy(data + x, bcd_time, 6); |
| | | x += 6; |
| | | memcpy(data + x, rtk, rtk_length); |
| | | x += rtk_length; |
| | | |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_RTK_UPLOAD, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | SendMessage(DATA_ACCESS_PLATFORM, &msg, data, x); |
| | | } |
| | | |
| | | void SendRTKStart(uint32_t latitude, uint32_t longitude, uint16_t altitude, |
| | | const uint8_t *bcd_time, uint16_t rtk_pkt_interval) |
| | | { |
| | | uint8_t data[18]; |
| | | int x = 0; |
| | | |
| | | data[x++] = BREAK_UINT32(latitude, 3); |
| | | data[x++] = BREAK_UINT32(latitude, 2); |
| | | data[x++] = BREAK_UINT32(latitude, 1); |
| | | data[x++] = BREAK_UINT32(latitude, 0); |
| | | data[x++] = BREAK_UINT32(longitude, 3); |
| | | data[x++] = BREAK_UINT32(longitude, 2); |
| | | data[x++] = BREAK_UINT32(longitude, 1); |
| | | data[x++] = BREAK_UINT32(longitude, 0); |
| | | data[x++] = HI_UINT16(altitude); |
| | | data[x++] = LO_UINT16(altitude); |
| | | memcpy(data + x, bcd_time, 6); |
| | | x += 6; |
| | | data[x++] = HI_UINT16(rtk_pkt_interval); |
| | | data[x++] = LO_UINT16(rtk_pkt_interval); |
| | | |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_RTK_START_REQ, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | SendMessage(DATA_ACCESS_PLATFORM, &msg, data, x); |
| | | } |
| | | |
| | | void SendRTKStop(void) |
| | | { |
| | | message_t msg; |
| | | MakeMessage(&msg, MESSAGE_VERSION_B2016, ID_CP_RTK_END_REQ, PROTOCOL_ENCRYPT_NONE, |
| | | PhoneNumber, PKT_RESEVER, 0, DEFAULT_SHORT_RESEND_INTERVAL); |
| | | SendMessage(DATA_ACCESS_PLATFORM, &msg, NULL, 0); |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/8. |
| | | // |
| | | |
| | | #ifndef RTKBASESTATION_PARSE_NET_H |
| | | #define RTKBASESTATION_PARSE_NET_H |
| | | |
| | | enum |
| | | { |
| | | DATA_ACCESS_MCU = 0, |
| | | DATA_ACCESS_PLATFORM, |
| | | DATA_ACCESS_PLATFORM_2, |
| | | DATA_ACCESS_PLATFORM_LOG, |
| | | DATA_ACCESS_END |
| | | }; |
| | | |
| | | #define MESSAGE_VERSION_JT808 0 |
| | | #define MESSAGE_VERSION_A2013 1 |
| | | #define MESSAGE_VERSION_B2016 128 |
| | | |
| | | #define PROTOCOL_ENCRYPT_NONE 0 |
| | | #define PROTOCOL_ENCRYPT_RSA2048 1 |
| | | |
| | | #define COMMON_RESP_SUCCESS 0 |
| | | #define COMMON_RESP_FAIL 1 |
| | | #define COMMON_RESP_ERROR 2 |
| | | #define COMMON_RESP_NOT_SUPPORT 3 |
| | | |
| | | |
| | | #define EX_MESSAGE_TYPE_INTERNAL 0x9A |
| | | #define EX_MESSAGE_TYPE_EXTERNAL 0x13 |
| | | |
| | | #define EX_MESSAGE_DOWNLOAD 0x8900 |
| | | #define EX_MESSAGE_UPLOAD 0x0900 |
| | | |
| | | #define EX_MESSAGE_ATTRIB_RESEND 1 //是否是重传包 |
| | | #define EX_MESSAGE_ATTRIB_INDICATE 2 //该包是否需要远端应答 |
| | | #define EX_MESSAGE_ATTRIB_SHA1 4 |
| | | #define EX_MESSAGE_ATTRIB_SHA256 8 |
| | | |
| | | void PlatformTxInit(const uint8_t *phone); |
| | | void Parse(uint8_t access, const uint8_t *buff, uint16_t length); |
| | | void CommonRespend(uint8_t access, uint16_t seq, uint16_t id, uint8_t value); |
| | | |
| | | void SendHeartBeat(uint8_t access); |
| | | void SendDeviceRegister(uint16_t province, uint16_t city, const uint8_t *device_model, |
| | | int device_model_length, const uint8_t *device_sn, const char *imei); |
| | | void SendDeviceLogin(const uint8_t *data, int length); |
| | | void SendRTKReport(uint8_t gps_status, uint32_t latitude, uint32_t longitude, uint16_t altitude, |
| | | const uint8_t *bcd_time, const uint8_t *rtk, int rtk_length); |
| | | void SendRTKStart(uint32_t latitude, uint32_t longitude, uint16_t altitude, |
| | | const uint8_t *bcd_time, uint16_t rtk_pkt_interval); |
| | | void SendRTKStop(void); |
| | | |
| | | #endif //RTKBASESTATION_PARSE_NET_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/27. |
| | | // |
| | | |
| | | #include <cstdint> |
| | | #include <cstdlib> |
| | | #include <cstring> |
| | | #include <pthread.h> |
| | | #include <semaphore.h> |
| | | #include "platform.h" |
| | | #include "../jni_log.h" |
| | | #include "../common/net.h" |
| | | #include "../native-lib.h" |
| | | #include "../common/apptimer.h" |
| | | #include "parse_net.h" |
| | | #include "../defs.h" |
| | | #include "../rtk_module/rtk.h" |
| | | |
| | | #define PARSE_BUFF_SIZE 4096 |
| | | |
| | | const char *VK_REG = "platform_register"; |
| | | |
| | | struct platformSocket { |
| | | char domain_name[32]; |
| | | int port; |
| | | }; |
| | | |
| | | static struct deviceInfo_ { |
| | | uint16_t province; |
| | | uint16_t city; |
| | | uint8_t device_model[21]; |
| | | uint8_t device_sn[17]; |
| | | char imei[16]; |
| | | }deviceInfo; |
| | | |
| | | struct platformSocketInfo { |
| | | char domain_name[32]; |
| | | int port; |
| | | }; |
| | | |
| | | static struct platformStatus_ { |
| | | uint8_t platformKey[64]; |
| | | int platformKeyLength; |
| | | uint32_t connected : 1; |
| | | uint32_t registed : 1; |
| | | uint32_t login : 1; |
| | | uint32_t downloadRtk : 1; |
| | | } platformStatus; |
| | | |
| | | struct platformSocket exceptSocket, currSocket; |
| | | static uint32_t eventMask; |
| | | static sem_t sem_status_changed; |
| | | |
| | | static bool requestPlatformSendRtk = false; |
| | | static int platform_tcp_fd = 0; |
| | | |
| | | static pthread_mutex_t platform_tx_mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | static pthread_mutex_t events_mutex = PTHREAD_MUTEX_INITIALIZER; |
| | | |
| | | static void ConnectPlatform(const char *domain_name, int port); |
| | | static void ConnectPlatformLater(union sigval sig); |
| | | |
| | | static void *PlatformDataListenThread(void *p); |
| | | static void *StatusListenThread(void *p); |
| | | |
| | | static void RegisterPlatform(void); |
| | | static void RegisterPlatformTimeout(union sigval sig); |
| | | |
| | | static void LoginPlatform(void); |
| | | static void LoginPlatformTimeout(union sigval sig); |
| | | static void TriggerHeartbeat(union sigval sig); |
| | | |
| | | void InitPlatform(const uint8_t *phone, const char *domain_name, int port) |
| | | { |
| | | pthread_mutex_init(&platform_tx_mutex, NULL); |
| | | pthread_mutex_init(&events_mutex, NULL); |
| | | |
| | | eventMask = 0; |
| | | platform_tcp_fd = -1; |
| | | memset(&currSocket, 0, sizeof(currSocket)); |
| | | strcpy(exceptSocket.domain_name, domain_name); |
| | | exceptSocket.port = port; |
| | | |
| | | sem_init(&sem_status_changed, 0, 0); |
| | | |
| | | strcpy(deviceInfo.imei, GetImei()); |
| | | deviceInfo.province = 53; |
| | | deviceInfo.city = 100; |
| | | strcpy((char *)deviceInfo.device_model, "RTKBaseStation"); |
| | | strcpy((char *)deviceInfo.device_sn, "2019101500000001"); |
| | | |
| | | PlatformTxInit(phone); |
| | | |
| | | pthread_t pid; |
| | | pthread_attr_t attr; |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | pthread_create(&pid, &attr, StatusListenThread, NULL); |
| | | |
| | | strcpy(deviceInfo.imei, GetImei()); |
| | | |
| | | ConnectPlatform(domain_name, port); |
| | | } |
| | | |
| | | void PlatformStatusChanged(uint32_t event) |
| | | { |
| | | pthread_mutex_lock(&events_mutex); |
| | | eventMask |= event; |
| | | pthread_mutex_unlock(&events_mutex); |
| | | sem_post(&sem_status_changed); |
| | | } |
| | | |
| | | static void ConnectPlatform(const char *domain_name, int port) |
| | | { |
| | | DEBUG("ConnectPlatform %s: %d", domain_name, port); |
| | | // TODO |
| | | struct platformSocketInfo *ptr = (struct platformSocketInfo *)malloc(sizeof(struct platformSocketInfo)); |
| | | |
| | | strcpy(ptr->domain_name, domain_name); |
| | | ptr->port = port; |
| | | |
| | | pthread_t platform_pid; |
| | | pthread_attr_t attr; |
| | | pthread_attr_init(&attr); |
| | | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);//detached |
| | | pthread_create(&platform_pid, &attr, PlatformDataListenThread, ptr); |
| | | |
| | | char out[64]; |
| | | sprintf(out, "连接平台 %s:%d...", domain_name, port); |
| | | DisplayText(out); |
| | | } |
| | | |
| | | static void ConnectPlatformLater(union sigval sig) { |
| | | AppTimer_delete(ConnectPlatformLater); |
| | | ConnectPlatform(exceptSocket.domain_name, exceptSocket.port); |
| | | } |
| | | |
| | | static void *StatusListenThread(void *p) { |
| | | while (true) { |
| | | sem_wait(&sem_status_changed); |
| | | |
| | | uint32_t events; |
| | | pthread_mutex_lock(&events_mutex); |
| | | events = eventMask; |
| | | eventMask = 0; |
| | | pthread_mutex_unlock(&events_mutex); |
| | | |
| | | if (events & PLATFORM_CONNECT_EVT) { |
| | | char out[64]; |
| | | sprintf(out, "平台连接成功 %s:%d", currSocket.domain_name, currSocket.port); |
| | | DisplayText(out); |
| | | |
| | | platformStatus.connected = 1; |
| | | if (!platformStatus.registed || platformStatus.platformKeyLength == 0) { |
| | | RegisterPlatform(); |
| | | } else if (!platformStatus.login) { |
| | | LoginPlatform(); |
| | | } |
| | | } |
| | | |
| | | if (events & PLATFORM_DISCONNECT_EVT) { |
| | | char out[64]; |
| | | sprintf(out, "平台断开 %s:%d", currSocket.domain_name, currSocket.port); |
| | | DisplayText(out); |
| | | |
| | | AppTimer_delete(ConnectPlatformLater); |
| | | AppTimer_add(ConnectPlatformLater, D_SEC(2)); |
| | | |
| | | platformStatus.login = 0; |
| | | platformStatus.connected = 0; |
| | | |
| | | AppTimer_delete(TriggerHeartbeat); |
| | | AppTimer_delete(RegisterPlatformTimeout); |
| | | AppTimer_delete(LoginPlatformTimeout); |
| | | } |
| | | if (events & PLATFORM_REGISTER_EVT) { |
| | | DEBUG("PLATFORM_REGISTER_EVT"); |
| | | platformStatus.platformKeyLength = GetPlatformKey(platformStatus.platformKey); |
| | | platformStatus.registed = GetSharedValue(VK_REG); |
| | | platformStatus.login = 0; |
| | | DEBUG("platformStatus.platformKeyLength = %d", platformStatus.platformKeyLength); |
| | | |
| | | if (platformStatus.registed && platformStatus.platformKeyLength > 0) { |
| | | LoginPlatform(); |
| | | } |
| | | } |
| | | if (events & PLATFORM_LOGIN_EVT) { |
| | | DEBUG("PLATFORM_LOGIN_EVT"); |
| | | platformStatus.login = 1; |
| | | requestPlatformSendRtk = true; |
| | | AppTimer_delete(TriggerHeartbeat); |
| | | AppTimer_add(TriggerHeartbeat, D_SEC(30)); |
| | | } |
| | | } |
| | | } |
| | | |
| | | static void *PlatformDataListenThread(void *p) { |
| | | struct platformSocket *ptr = (struct platformSocket *)p; |
| | | |
| | | uint8_t RxBuf[PARSE_BUFF_SIZE]; |
| | | |
| | | int fds_ret; |
| | | struct timeval tv; |
| | | fd_set rdfds; |
| | | fd_set exfds; |
| | | |
| | | int fd = -1; |
| | | int RxBufLen = 0; |
| | | |
| | | fd = ConnectTCP(ptr->domain_name, ptr->port); |
| | | |
| | | pthread_mutex_lock(&platform_tx_mutex); |
| | | platform_tcp_fd = fd; |
| | | |
| | | currSocket = *ptr; |
| | | |
| | | pthread_mutex_unlock(&platform_tx_mutex); |
| | | |
| | | if (fd > 0) { |
| | | PlatformStatusChanged(PLATFORM_CONNECT_EVT); |
| | | } |
| | | |
| | | while (fd > 0) { |
| | | tv.tv_sec = 5; |
| | | tv.tv_usec = 0; |
| | | FD_ZERO(&rdfds); //clean |
| | | FD_SET(fd, &rdfds); //set |
| | | |
| | | fds_ret = select(fd + 1, &rdfds, NULL, NULL, &tv); |
| | | |
| | | if (fds_ret < 0) { |
| | | break; |
| | | } else if(fds_ret == 0) { |
| | | //Occur failure(such as line disconnect) |
| | | } else if(FD_ISSET(fd, &rdfds)) { |
| | | RxBufLen = ReadTCP(fd, RxBuf, sizeof(RxBuf)); |
| | | |
| | | if (RxBufLen < 0) { |
| | | break; |
| | | } else if (RxBufLen > 0) { |
| | | Parse(DATA_ACCESS_PLATFORM, RxBuf, RxBufLen); |
| | | } |
| | | } |
| | | } |
| | | |
| | | pthread_mutex_lock(&platform_tx_mutex); |
| | | if (platform_tcp_fd > 0) { |
| | | DisconnectTCP(platform_tcp_fd); |
| | | platform_tcp_fd = -1; |
| | | } |
| | | pthread_mutex_unlock(&platform_tx_mutex); |
| | | free(ptr); |
| | | |
| | | PlatformStatusChanged(PLATFORM_DISCONNECT_EVT); |
| | | pthread_exit(NULL); |
| | | } |
| | | |
| | | int WritePlatform(const uint8_t * buf, uint32_t len) |
| | | { |
| | | int ret = -1; |
| | | |
| | | pthread_mutex_lock(&platform_tx_mutex); |
| | | if (platform_tcp_fd > 0) { |
| | | ret = WriteTCP(platform_tcp_fd, buf, len); |
| | | } |
| | | pthread_mutex_unlock(&platform_tx_mutex); |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static void RegisterPlatformTimeout(union sigval sig) |
| | | { |
| | | DEBUG("RegisterPlatformTimeout"); |
| | | AppTimer_delete(RegisterPlatformTimeout); |
| | | RegisterPlatform(); |
| | | } |
| | | |
| | | static void RegisterPlatform(void) |
| | | { |
| | | AppTimer_delete(RegisterPlatformTimeout); |
| | | AppTimer_add(RegisterPlatformTimeout, D_SEC(15)); |
| | | SendDeviceRegister(deviceInfo.province, deviceInfo.city, deviceInfo.device_model, |
| | | strlen((char *)deviceInfo.device_model), deviceInfo.device_sn, deviceInfo.imei); |
| | | } |
| | | |
| | | static void TriggerHeartbeat(union sigval sig) { |
| | | AppTimer_delete(TriggerHeartbeat); |
| | | |
| | | if (platformStatus.login && platformStatus.connected) { |
| | | SendHeartBeat(DATA_ACCESS_PLATFORM); |
| | | AppTimer_add(TriggerHeartbeat, D_SEC(30)); |
| | | } |
| | | } |
| | | |
| | | static void LoginPlatformTimeout(union sigval sig) |
| | | { |
| | | AppTimer_delete(LoginPlatformTimeout); |
| | | LoginPlatform(); |
| | | } |
| | | |
| | | static void LoginPlatform(void) |
| | | { |
| | | uint32_t tim = time(NULL); |
| | | uint8_t data[12]; |
| | | uint8_t *ciphertext; |
| | | |
| | | data[0] = BREAK_UINT32(tim, 3); |
| | | data[1] = BREAK_UINT32(tim, 2); |
| | | data[2] = BREAK_UINT32(tim, 1); |
| | | data[3] = BREAK_UINT32(tim, 0); |
| | | |
| | | AppTimer_delete(LoginPlatformTimeout); |
| | | AppTimer_add(LoginPlatformTimeout, D_SEC(15)); |
| | | |
| | | DESEncrypt(platformStatus.platformKey, platformStatus.platformKeyLength, data, 4, &ciphertext); |
| | | |
| | | if (ciphertext != NULL) { |
| | | memcpy(data + 4, ciphertext, 8); |
| | | SendDeviceLogin(data, sizeof(data)); |
| | | } |
| | | } |
| | | |
| | | void DeviceRegisterCallback(uint8_t res, const uint8_t *data, int length) |
| | | { |
| | | AppTimer_delete(RegisterPlatformTimeout); |
| | | if (res != 0) { |
| | | |
| | | } else { |
| | | TextSpeak("终端注册成功"); |
| | | DisplayText("终端注册成功"); |
| | | SetPlatformKey(data, length); |
| | | SetSharedValue(VK_REG, 1); |
| | | PlatformStatusChanged(PLATFORM_REGISTER_EVT); |
| | | } |
| | | } |
| | | |
| | | void DeviceLoginCallback(uint8_t res) |
| | | { |
| | | AppTimer_delete(LoginPlatformTimeout); |
| | | if (res != 0) { |
| | | |
| | | } else { |
| | | TextSpeak("终端登录成功"); |
| | | DisplayText("终端登录成功"); |
| | | PlatformStatusChanged(PLATFORM_LOGIN_EVT); |
| | | } |
| | | } |
| | | |
| | | void RequestRtkDownload(uint32_t latitude, uint32_t longitude, uint16_t altitude, |
| | | const uint8_t *bcd_time, uint16_t rtk_pkt_interval) |
| | | { |
| | | if (requestPlatformSendRtk) { |
| | | requestPlatformSendRtk = false; |
| | | SendRTKStart(latitude, longitude, altitude, bcd_time, rtk_pkt_interval); |
| | | } |
| | | } |
| | | |
| | | void StopRtkDownload(void) |
| | | { |
| | | SendRTKStop(); |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/27. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_PLATFORM_H |
| | | #define RTKDRIVERTEST_PLATFORM_H |
| | | |
| | | #define PLATFORM_CONNECT_EVT 0x0001 |
| | | #define PLATFORM_DISCONNECT_EVT 0x0002 |
| | | #define PLATFORM_REGISTER_EVT 0x0004 |
| | | #define PLATFORM_LOGIN_EVT 0x0008 |
| | | #define RTK_UPDATE_EVT 0x0010 |
| | | #define GPS_UPDATE_EVT 0x0020 |
| | | |
| | | void InitPlatform(const uint8_t *phone, const char *domain_name, int port); |
| | | void PlatformStatusChanged(uint32_t event); |
| | | int WritePlatform(const uint8_t * buf, uint32_t len); |
| | | void DeviceRegisterCallback(uint8_t res, const uint8_t *data, int length); |
| | | void DeviceLoginCallback(uint8_t res); |
| | | |
| | | void RequestRtkDownload(uint32_t latitude, uint32_t longitude, uint16_t altitude, |
| | | const uint8_t *bcd_time, uint16_t rtk_pkt_interval); |
| | | void StopRtkDownload(void); |
| | | |
| | | #endif //RTKDRIVERTEST_PLATFORM_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/11/4. |
| | | // |
| | | |
| | | #include "driving_curve.h" |
| | | #include "../driver_test.h" |
| | | #include "../common/apptimer.h" |
| | | |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | enum { |
| | | DRIVING_ON_CURVE |
| | | }; |
| | | |
| | | const uint32_t STOP_CAR_TIME = D_SEC(2); |
| | | |
| | | static bool carStopEvent = false; |
| | | static bool DCTesting = false; |
| | | static int currTarget; |
| | | static uint32_t stopTimepoint = 0; |
| | | |
| | | static bool CrashRedLine(const Polygon *left, const Polygon *right, const car_model_cache_t *car); |
| | | static bool ExitTestArea(const Polygon *left, const Polygon *right, const car_model_cache_t *car); |
| | | |
| | | void StartDrivingCurve(void) |
| | | { |
| | | DCTesting = true; |
| | | carStopEvent = false; |
| | | currTarget = DRIVING_ON_CURVE; |
| | | } |
| | | |
| | | void StopDrivingCurve(void) |
| | | { |
| | | DCTesting = false; |
| | | } |
| | | |
| | | int TestDrivingCurve(vector<int>&err, const Polygon *map, const Polygon *map2, const car_model_cache_t *car, double speed, int run_status) |
| | | { |
| | | int status = 0; |
| | | |
| | | if (!DCTesting) |
| | | return -2; |
| | | |
| | | if (currTarget == DRIVING_ON_CURVE) { |
| | | if (CrashRedLine(map, map2, car)) { |
| | | // 车轮压线 |
| | | err.push_back(27); |
| | | status = -1; |
| | | } |
| | | |
| | | if (ExitTestArea(map, map2, car)) { |
| | | // 测试完成 |
| | | status = 1; |
| | | } |
| | | |
| | | if (run_status != 0) { |
| | | if (carStopEvent && AppTimer_GetTickCount() - stopTimepoint > D_SEC(2)) { |
| | | // 中途停车 |
| | | err.push_back(28); |
| | | } |
| | | carStopEvent = false; |
| | | } else { |
| | | carStopEvent = true; |
| | | stopTimepoint = AppTimer_GetTickCount(); |
| | | } |
| | | } |
| | | |
| | | if (status != 0) { |
| | | StopDrivingCurve(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | // 车轮是否压边线 |
| | | static bool CrashRedLine(const Polygon *left, const Polygon *right, const car_model_cache_t *car) |
| | | { |
| | | bool ret = false; |
| | | |
| | | car_model_cache_t *prev_car = GetCarModelCache(1); |
| | | if (prev_car == NULL) |
| | | return false; |
| | | |
| | | // 按4个轮子的外侧计算 |
| | | Line front_left_tire_track, front_right_tire_track, rear_left_tire_track, rear_right_tire_track; |
| | | MakeLine(&front_left_tire_track, &car->points[car->desc->front_left_tire[TIRE_OUTSIDE]], &prev_car->points[car->desc->front_left_tire[TIRE_OUTSIDE]]); |
| | | MakeLine(&front_right_tire_track, &car->points[car->desc->front_right_tire[TIRE_OUTSIDE]], &prev_car->points[car->desc->front_right_tire[TIRE_OUTSIDE]]); |
| | | MakeLine(&rear_left_tire_track, &car->points[car->desc->rear_left_tire[TIRE_OUTSIDE]], &prev_car->points[car->desc->rear_left_tire[TIRE_OUTSIDE]]); |
| | | MakeLine(&rear_right_tire_track, &car->points[car->desc->rear_right_tire[TIRE_OUTSIDE]], &prev_car->points[car->desc->rear_right_tire[TIRE_OUTSIDE]]); |
| | | |
| | | Line line; |
| | | |
| | | line.X1 = left->point[0].X; |
| | | line.Y1 = left->point[0].Y; |
| | | for (int i = 1; i < left->num; ++i) { |
| | | line.X2 = left->point[i].X; |
| | | line.Y2 = left->point[i].Y; |
| | | |
| | | if (IntersectionOf(line, front_left_tire_track) == GM_Intersection || |
| | | IntersectionOf(line, front_right_tire_track) == GM_Intersection || |
| | | IntersectionOf(line, rear_left_tire_track) == GM_Intersection || |
| | | IntersectionOf(line, rear_right_tire_track) == GM_Intersection) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | line.X1 = line.X2; |
| | | line.Y1 = line.Y2; |
| | | } |
| | | |
| | | line.X1 = right->point[0].X; |
| | | line.Y1 = right->point[0].Y; |
| | | for (int i = 1; !ret && i < right->num; ++i) { |
| | | line.X2 = right->point[i].X; |
| | | line.Y2 = right->point[i].Y; |
| | | |
| | | if (IntersectionOf(line, front_left_tire_track) == GM_Intersection || |
| | | IntersectionOf(line, front_right_tire_track) == GM_Intersection || |
| | | IntersectionOf(line, rear_left_tire_track) == GM_Intersection || |
| | | IntersectionOf(line, rear_right_tire_track) == GM_Intersection) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | line.X1 = line.X2; |
| | | line.Y1 = line.Y2; |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | // 整个车辆都要驶离该测试区域 |
| | | static bool ExitTestArea(const Polygon *left, const Polygon *right, const car_model_cache_t *car) |
| | | { |
| | | for (int i = 0; i < car->point_num; ++i) { |
| | | if (IntersectionOfLine(left->point[0], right->point[0], car->points[i]) != 1) |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/11/4. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_DRIVING_CURVE_H |
| | | #define RTKDRIVERTEST_DRIVING_CURVE_H |
| | | |
| | | #include "../driver_test.h" |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | void StartDrivingCurve(void); |
| | | void StopDrivingCurve(void); |
| | | int TestDrivingCurve(vector<int>&err, const Polygon *map, const Polygon *map2, const car_model_cache_t *car, double speed, int run_status); |
| | | |
| | | #endif //RTKDRIVERTEST_DRIVING_CURVE_H |
New file |
| | |
| | | #include "error_list.h" |
| | | |
| | | // |
| | | // Created by YY on 2019/10/31. |
| | | // |
| | | const error_list_t errorList[] = { |
| | | { |
| | | .id = 0, |
| | | .text_desc = "", |
| | | .item = 0, |
| | | .dec_score = 0 |
| | | }, |
| | | { |
| | | .id = 1, |
| | | .text_desc = "不按规定使用安全带", |
| | | .item = 1, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 2, |
| | | .text_desc = "不按考试员指令行驶", |
| | | .item = 1, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 3, |
| | | .text_desc = "启动发动机时挡位未置于空档(驻车挡)", |
| | | .item = 1, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 4, |
| | | .text_desc = "发动机启动后,不及时松开启动开关", |
| | | .item = 1, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 5, |
| | | .text_desc = "因操作不当造成发动机熄火一次", |
| | | .item = 1, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 6, |
| | | .text_desc = "不按规定线路、顺序行驶", |
| | | .item = 2, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 7, |
| | | .text_desc = "车身出线", |
| | | .item = 2, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 8, |
| | | .text_desc = "倒库不入", |
| | | .item = 2, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 9, |
| | | .text_desc = "在倒车前,未将两个前轮触地点均驶过控制线", |
| | | .item = 2, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 10, |
| | | .text_desc = "项目完成时间超过210秒", |
| | | .item = 2, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 11, |
| | | .text_desc = "中途停车时间超过2秒", |
| | | .item = 2, |
| | | .dec_score = 5 |
| | | }, |
| | | { |
| | | .id = 12, |
| | | .text_desc = "车辆停止后,前保险杠未定于桩杆线上,且前后超出50cm", |
| | | .item = 3, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 13, |
| | | .text_desc = "行驶中车轮压线", |
| | | .item = 3, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 14, |
| | | .text_desc = "车辆停止后,车身距离路边线超出50cm", |
| | | .item = 3, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 15, |
| | | .text_desc = "起步时间超过30s", |
| | | .item = 3, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 16, |
| | | .text_desc = "起步后溜大于30cm", |
| | | .item = 3, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 17, |
| | | .text_desc = "车辆停止后,前保险杠未定于桩杆线上,且前后不超出50cm", |
| | | .item = 3, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 18, |
| | | .text_desc = "车辆停止后,车身距离路边缘线超出30cm,未超出50cm", |
| | | .item = 3, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 19, |
| | | .text_desc = "停车后,未拉紧驻车制动器", |
| | | .item = 3, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 20, |
| | | .text_desc = "起步时车辆后溜距离10cm~30cm", |
| | | .item = 3, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 21, |
| | | .text_desc = "车辆入库停止后,车身出线", |
| | | .item = 4, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 22, |
| | | .text_desc = "项目完成时间超过90s", |
| | | .item = 4, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 23, |
| | | .text_desc = "行驶中车轮触轧车道边线", |
| | | .item = 4, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 24, |
| | | .text_desc = "行驶中车身触碰车位边线", |
| | | .item = 4, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 25, |
| | | .text_desc = "出库时不使用或错误使用转向灯", |
| | | .item = 4, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 26, |
| | | .text_desc = "中途停车时间超过2秒", |
| | | .item = 4, |
| | | .dec_score = 5 |
| | | }, |
| | | { |
| | | .id = 27, |
| | | .text_desc = "车轮轧道路边缘线", |
| | | .item = 5, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 28, |
| | | .text_desc = "中途停车时间超过2秒", |
| | | .item = 5, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 29, |
| | | .text_desc = "车轮轧道路边缘线", |
| | | .item = 6, |
| | | .dec_score = 100 |
| | | }, |
| | | { |
| | | .id = 30, |
| | | .text_desc = "转弯时不使用或错误使用转向灯,转弯后不关闭转向灯", |
| | | .item = 6, |
| | | .dec_score = 10 |
| | | }, |
| | | { |
| | | .id = 31, |
| | | .text_desc = "中途停车时间超过2秒", |
| | | .item = 6, |
| | | .dec_score = 5 |
| | | } |
| | | }; |
| | | |
| | | error_list_t GetErrorList(int index) |
| | | { |
| | | if (index >= sizeof(errorList) / sizeof(errorList[0])) |
| | | return errorList[0]; |
| | | |
| | | return errorList[index]; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/29. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_ERROR_LIST_H |
| | | #define RTKDRIVERTEST_ERROR_LIST_H |
| | | |
| | | typedef struct { |
| | | int id; |
| | | int item; |
| | | char *text_desc; |
| | | int dec_score; |
| | | }error_list_t; |
| | | |
| | | error_list_t GetErrorList(int index); |
| | | |
| | | #endif //RTKDRIVERTEST_ERROR_LIST_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/23. |
| | | // |
| | | |
| | | #include "park_bottom.h" |
| | | #include "../common/apptimer.h" |
| | | #include "../Geometry.h" |
| | | #include "../native-lib.h" |
| | | #include "../jni_log.h" |
| | | #include "../driver_test.h" |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | enum { |
| | | NONE, |
| | | FIRST_TOUCH_CTRL_LINE, |
| | | FIRST_PARK, |
| | | SECOND_TOUCH_CTRL_LINE, |
| | | SECOND_PARK, |
| | | THIRD_TOUCH_CTRL_LINE |
| | | }; |
| | | |
| | | const int PARK_TIMEOUT = 210; |
| | | |
| | | static bool PBTesting = false; |
| | | static bool trigLeaveTestAreaDetect = false; |
| | | static bool leaveTestArea = false; |
| | | static bool stopCar2S = false; |
| | | |
| | | static int currTarget; |
| | | static bool leftTireCrossLeftLine, leftTireCrossRightLine, rightTireCrossLeftLine, rightTireCrossRightLine; |
| | | static char first_ctrl_line_id; |
| | | static bool carStopEvent; // 中途停车标记 |
| | | static bool carParkSuccess; // 是否停在库位 |
| | | static bool parkTimeout; |
| | | |
| | | static void StopCarTimeout(union sigval sig); |
| | | static void LeaveTestAreaLongtime(union sigval sig); |
| | | static void CrossCtrlLine(const Polygon *map, const car_model_cache_t *car); |
| | | static bool EnterParking(const Polygon *map, const car_model_cache_t *car); |
| | | static void ParkBottomTimeout(union sigval sig); |
| | | static bool CrashRedLine(const Polygon *map, const car_model_cache_t *car); |
| | | |
| | | void StartParkBottom(void) |
| | | { |
| | | stopCar2S = false; |
| | | trigLeaveTestAreaDetect = false; |
| | | leaveTestArea = false; |
| | | PBTesting = true; |
| | | parkTimeout = false; |
| | | first_ctrl_line_id = 0; |
| | | currTarget = FIRST_TOUCH_CTRL_LINE; |
| | | leftTireCrossLeftLine = leftTireCrossRightLine = rightTireCrossLeftLine = rightTireCrossRightLine = false; |
| | | |
| | | TextOsd(0, "ParkBottom"); |
| | | } |
| | | |
| | | void StopParkBottom(void) |
| | | { |
| | | PBTesting = false; |
| | | AppTimer_delete(StopCarTimeout); |
| | | AppTimer_delete(ParkBottomTimeout); |
| | | AppTimer_delete(LeaveTestAreaLongtime); |
| | | currTarget = NONE; |
| | | |
| | | TextOsd(0, "ParkBottom End"); |
| | | } |
| | | |
| | | int TestParkBottom(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status) |
| | | { |
| | | int status = 0; |
| | | |
| | | if (!PBTesting) |
| | | return -2; |
| | | |
| | | DEBUG("TestParkBottom speed %f dir %d", speed, run_status); |
| | | |
| | | |
| | | if (currTarget > FIRST_TOUCH_CTRL_LINE) { |
| | | // 是否超时 |
| | | if (parkTimeout) { |
| | | // 不合格:动作超时 |
| | | err.push_back(10); |
| | | status = -1; |
| | | } |
| | | // 是否压线 |
| | | if (CrashRedLine(map, car)) { |
| | | // 不合格:车身出线 |
| | | err.push_back(7); |
| | | status = -1; |
| | | } |
| | | |
| | | if (trigLeaveTestAreaDetect) { |
| | | if (IntersectionOf(car->points[car->desc->front_left_tire[TIRE_OUTSIDE]], map) == GM_Containment && |
| | | IntersectionOf(car->points[car->desc->front_right_tire[TIRE_OUTSIDE]], map) == GM_Containment) { |
| | | trigLeaveTestAreaDetect = false; |
| | | AppTimer_delete(LeaveTestAreaLongtime); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (currTarget == FIRST_TOUCH_CTRL_LINE || |
| | | currTarget == SECOND_TOUCH_CTRL_LINE || |
| | | currTarget == THIRD_TOUCH_CTRL_LINE) { |
| | | if (run_status > 0) { |
| | | if (stopCar2S && currTarget != FIRST_TOUCH_CTRL_LINE) { |
| | | // 扣5分:中途停车超过2秒 |
| | | err.push_back(11); |
| | | } |
| | | |
| | | if (!((leftTireCrossLeftLine && rightTireCrossLeftLine) || |
| | | (leftTireCrossRightLine && rightTireCrossRightLine))) { |
| | | DEBUG("CrossCtrlLine"); |
| | | CrossCtrlLine(map, car); |
| | | } else if (currTarget == FIRST_TOUCH_CTRL_LINE || currTarget == SECOND_TOUCH_CTRL_LINE) { |
| | | // 跨过控制线后,车辆持续向前行驶,处理这些乱搞情况 |
| | | // 整个车都离开测试区后,如果持续15秒,还没回到测试区,就忽略该测试或者淘汰 |
| | | if (leaveTestArea) { |
| | | if (currTarget == FIRST_TOUCH_CTRL_LINE) { |
| | | status = -2; |
| | | TextOsd(0, "来道场玩的"); |
| | | DEBUG("来道场玩的"); |
| | | } else { |
| | | // 不合格:未按规定线路行驶(直接跑出测试区了) |
| | | err.push_back(6); |
| | | status = -1; |
| | | TextOsd(0, "直接跑出测试区了"); |
| | | DEBUG("直接跑出测试区了"); |
| | | } |
| | | } else if (!trigLeaveTestAreaDetect) { |
| | | Polygon car_body; |
| | | |
| | | car_body.num = car->desc->body_num; |
| | | car_body.point = (PointF *) malloc(sizeof(PointF) * car_body.num); |
| | | for (int i = 0; i < car_body.num; ++i) { |
| | | car_body.point[i] = car->points[car->desc->body[i]]; |
| | | } |
| | | |
| | | if (IntersectionOf(map, &car_body) == GM_None) { |
| | | trigLeaveTestAreaDetect = true; |
| | | AppTimer_delete(LeaveTestAreaLongtime); |
| | | AppTimer_add(LeaveTestAreaLongtime, D_SEC(15)); |
| | | DEBUG("开始离场计时"); |
| | | } |
| | | |
| | | free(car_body.point); |
| | | } |
| | | } |
| | | |
| | | if (currTarget == THIRD_TOUCH_CTRL_LINE) { |
| | | char the_ctrl_line_crossed = 0; |
| | | |
| | | if (leftTireCrossLeftLine && rightTireCrossLeftLine) { |
| | | the_ctrl_line_crossed = 'L'; |
| | | } else if (leftTireCrossRightLine && rightTireCrossRightLine) { |
| | | the_ctrl_line_crossed = 'R'; |
| | | } |
| | | |
| | | if (the_ctrl_line_crossed != 0 && the_ctrl_line_crossed == first_ctrl_line_id) { |
| | | // 项目完成 |
| | | status = 1; |
| | | } else if (the_ctrl_line_crossed != 0) { |
| | | // 不合格:未按规定线路行驶(未回到起始点) |
| | | err.push_back(6); |
| | | status = -1; |
| | | } |
| | | } |
| | | if (carStopEvent) |
| | | AppTimer_delete(StopCarTimeout); |
| | | carStopEvent = false; |
| | | stopCar2S = false; |
| | | } else if (run_status < 0) { |
| | | // 左右倒库大纲并未要求谁先完成,故以先越过的控制线为准,下次得越过另外一条 |
| | | char the_ctrl_line_crossed = 0; |
| | | |
| | | if (leftTireCrossLeftLine && rightTireCrossLeftLine) { |
| | | the_ctrl_line_crossed = 'L'; |
| | | } else if (leftTireCrossRightLine && rightTireCrossRightLine) { |
| | | the_ctrl_line_crossed = 'R'; |
| | | } |
| | | |
| | | if (first_ctrl_line_id > 0 && first_ctrl_line_id == the_ctrl_line_crossed) { |
| | | // 不合格:未按规定线路行驶(试图做2次同方向的倒库) |
| | | err.push_back(6); |
| | | status = -1; |
| | | } else if (the_ctrl_line_crossed > 0 && first_ctrl_line_id == 0) { |
| | | first_ctrl_line_id = the_ctrl_line_crossed; |
| | | // 项目正式开始,210秒内完成 |
| | | AppTimer_delete(ParkBottomTimeout); |
| | | AppTimer_add(ParkBottomTimeout, D_SEC(PARK_TIMEOUT)); |
| | | currTarget = FIRST_PARK; |
| | | carParkSuccess = false; |
| | | parkTimeout = false; |
| | | leftTireCrossLeftLine = leftTireCrossRightLine = rightTireCrossLeftLine = rightTireCrossRightLine = false; |
| | | |
| | | TextOsd(0, "第一次倒库"); |
| | | } else if (the_ctrl_line_crossed > 0) { |
| | | currTarget = SECOND_PARK; |
| | | carParkSuccess = false; |
| | | leftTireCrossLeftLine = leftTireCrossRightLine = rightTireCrossLeftLine = rightTireCrossRightLine = false; |
| | | TextOsd(0, "第二次倒库"); |
| | | } else if (currTarget != THIRD_TOUCH_CTRL_LINE) { |
| | | // 不合格:倒车前,2前轮没驶过控制线 |
| | | err.push_back(9); |
| | | status = -1; |
| | | } |
| | | if (carStopEvent) |
| | | AppTimer_delete(StopCarTimeout); |
| | | carStopEvent = false; |
| | | stopCar2S = false; |
| | | } else { |
| | | if (!carStopEvent) { |
| | | AppTimer_delete(StopCarTimeout); |
| | | AppTimer_add(StopCarTimeout, D_SEC(2)); |
| | | } |
| | | carStopEvent = true; |
| | | } |
| | | } else if (currTarget == FIRST_PARK || currTarget == SECOND_PARK) { |
| | | if (run_status < 0) { |
| | | if (stopCar2S) { |
| | | // 扣5分:中途停车 |
| | | err.push_back(11); |
| | | } |
| | | |
| | | carStopEvent = false; |
| | | stopCar2S = false; |
| | | } else if (run_status == 0) { |
| | | // 立即检查是否停车到位,也许是中途停车,先不管,待发生前进事件后,再断定是否停车到位 |
| | | if (!carStopEvent) { |
| | | carStopEvent = true; |
| | | carParkSuccess = EnterParking(map, car); |
| | | AppTimer_delete(StopCarTimeout); |
| | | AppTimer_add(StopCarTimeout, D_SEC(2)); |
| | | } |
| | | } else { |
| | | if (carStopEvent) { |
| | | if (!carParkSuccess) { |
| | | // 不合格:倒库不入 |
| | | err.push_back(8); |
| | | status = -1; |
| | | } else if (currTarget == FIRST_PARK) { |
| | | currTarget = SECOND_TOUCH_CTRL_LINE; |
| | | TextOsd(0, "过另一根控制线"); |
| | | } else { |
| | | currTarget = THIRD_TOUCH_CTRL_LINE; |
| | | TextOsd(0, "再过第一根控制线"); |
| | | } |
| | | } |
| | | carStopEvent = false; |
| | | stopCar2S = false; |
| | | } |
| | | } |
| | | |
| | | if (status != 0) { |
| | | StopParkBottom(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | static void StopCarTimeout(union sigval sig) { |
| | | AppTimer_delete(StopCarTimeout); |
| | | |
| | | stopCar2S = true; |
| | | } |
| | | |
| | | static void LeaveTestAreaLongtime(union sigval sig) { |
| | | AppTimer_delete(LeaveTestAreaLongtime); |
| | | leaveTestArea = true; |
| | | trigLeaveTestAreaDetect = false; |
| | | } |
| | | |
| | | static void ParkBottomTimeout(union sigval sig) { |
| | | AppTimer_delete(ParkBottomTimeout); |
| | | parkTimeout = true; |
| | | } |
| | | |
| | | // 检测2前轮是否正向越过左右控制线 |
| | | static void CrossCtrlLine(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | Line leftCtrlLine, rightCtrlLine; |
| | | Line track1; |
| | | PointF p1, p2; |
| | | |
| | | car_model_cache_t *prev_car = GetCarModelCache(1); |
| | | if (prev_car == NULL) |
| | | return; |
| | | |
| | | MakeLine(&leftCtrlLine, &map->point[0], &map->point[1]); |
| | | MakeLine(&rightCtrlLine, &map->point[6], &map->point[7]); |
| | | |
| | | // 左前轮,取轮宽的中点 |
| | | p1.X = (car->points[car->desc->front_left_tire[TIRE_OUTSIDE]].X + car->points[car->desc->front_left_tire[TIRE_INSIDE]].X) / 2; |
| | | p1.Y = (car->points[car->desc->front_left_tire[TIRE_OUTSIDE]].Y + car->points[car->desc->front_left_tire[TIRE_INSIDE]].Y) / 2; |
| | | |
| | | p2.X = (prev_car->points[prev_car->desc->front_left_tire[TIRE_OUTSIDE]].X + prev_car->points[prev_car->desc->front_left_tire[TIRE_INSIDE]].X) / 2; |
| | | p2.Y = (prev_car->points[prev_car->desc->front_left_tire[TIRE_OUTSIDE]].Y + prev_car->points[prev_car->desc->front_left_tire[TIRE_INSIDE]].Y) / 2; |
| | | |
| | | MakeLine(&track1, &p1, &p2); |
| | | |
| | | if (IntersectionOf(track1, leftCtrlLine) == GM_Intersection && |
| | | IntersectionOf(p1, map) == GM_None) { |
| | | leftTireCrossLeftLine = true; |
| | | } |
| | | |
| | | if (IntersectionOf(track1, rightCtrlLine) == GM_Intersection && |
| | | IntersectionOf(p1, map) == GM_None) { |
| | | leftTireCrossRightLine = true; |
| | | } |
| | | |
| | | // 右前轮 |
| | | p1.X = (car->points[car->desc->front_right_tire[TIRE_OUTSIDE]].X + car->points[car->desc->front_right_tire[TIRE_INSIDE]].X) / 2; |
| | | p1.Y = (car->points[car->desc->front_right_tire[TIRE_OUTSIDE]].Y + car->points[car->desc->front_right_tire[TIRE_INSIDE]].Y) / 2; |
| | | |
| | | p2.X = (prev_car->points[prev_car->desc->front_right_tire[TIRE_OUTSIDE]].X + prev_car->points[prev_car->desc->front_right_tire[TIRE_INSIDE]].X) / 2; |
| | | p2.Y = (prev_car->points[prev_car->desc->front_right_tire[TIRE_OUTSIDE]].Y + prev_car->points[prev_car->desc->front_right_tire[TIRE_INSIDE]].Y) / 2; |
| | | |
| | | MakeLine(&track1, &p1, &p2); |
| | | |
| | | if (IntersectionOf(track1, leftCtrlLine) == GM_Intersection && |
| | | IntersectionOf(p1, map) == GM_None) { |
| | | rightTireCrossLeftLine = true; |
| | | } |
| | | if (IntersectionOf(track1, rightCtrlLine) == GM_Intersection && |
| | | IntersectionOf(p1, map) == GM_None) { |
| | | rightTireCrossRightLine = true; |
| | | } |
| | | } |
| | | |
| | | static bool EnterParking(const Polygon *map, const car_model_cache_t *car) { |
| | | bool succ = false; |
| | | |
| | | Polygon parking; |
| | | Polygon car_body; |
| | | |
| | | car_body.num = car->desc->body_num; |
| | | car_body.point = (PointF *) malloc(sizeof(PointF) * car_body.num); |
| | | for (int i = 0; i < car_body.num; ++i) { |
| | | car_body.point[i] = car->points[car->desc->body[i]]; |
| | | } |
| | | |
| | | MakePolygon(&parking, {map->point[2], map->point[3], map->point[4], map->point[5]}); |
| | | |
| | | if (IntersectionOf(&car_body, &parking) == GM_Containment) { |
| | | succ = true; |
| | | } |
| | | |
| | | CleanPolygon(&parking); |
| | | free(car_body.point); |
| | | |
| | | return succ; |
| | | } |
| | | |
| | | static bool CrashRedLine(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | bool ret = false; |
| | | |
| | | Line red_line; |
| | | const int red_lines[][2] = {{0, 7}, {1, 2}, {2, 3}, {3, 4}, {4, 5}, {5, 6}}; |
| | | |
| | | Polygon car_body; |
| | | |
| | | car_body.num = car->desc->body_num; |
| | | car_body.point = (PointF *) malloc(sizeof(PointF) * car_body.num); |
| | | for (int i = 0; i < car_body.num; ++i) { |
| | | car_body.point[i] = car->points[car->desc->body[i]]; |
| | | } |
| | | |
| | | for (int i = 0; i < sizeof(red_lines) / sizeof(red_lines[0]); ++i) { |
| | | MakeLine(&red_line, &map->point[red_lines[i][0]], &map->point[red_lines[i][1]]); |
| | | if (IntersectionOf(red_line, &car_body) != GM_None) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | free(car_body.point); |
| | | return ret; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/23. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_PARK_BOTTOM_H |
| | | #define RTKDRIVERTEST_PARK_BOTTOM_H |
| | | |
| | | #include "../Geometry.h" |
| | | #include "../driver_test.h" |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | void StartParkBottom(void); |
| | | void StopParkBottom(void); |
| | | int TestParkBottom(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status); |
| | | |
| | | #endif //RTKDRIVERTEST_PARK_BOTTOM_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/23. |
| | | // |
| | | |
| | | #include "park_edge.h" |
| | | #include "../Geometry.h" |
| | | #include "../driver_test.h" |
| | | #include "../common/apptimer.h" |
| | | #include "../native-lib.h" |
| | | |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | enum { |
| | | ARRIVED_START, |
| | | PARK_CAR, |
| | | START_CAR |
| | | }; |
| | | |
| | | const int PARK_TIMEOUT = 90; |
| | | const uint32_t STOP_CAR_TIME = D_SEC(2); |
| | | |
| | | static int prev_run_status; |
| | | static int runStatusBeforeStop; |
| | | static uint32_t stopTimepoint = 0; |
| | | static bool parkTimeout; |
| | | static bool occurCrashRedLine1, occurCrashRedLine2; |
| | | static bool PETesting = false; |
| | | static int currTarget; |
| | | static bool carStopEvent; // 中途停车标记 |
| | | static bool carParkSuccess; // 是否停在库位 |
| | | static int leaveParkCnt; // 车辆离开库位刚发生的时,检查是否开启转向灯 |
| | | |
| | | static void ParkEdgeTimeout(union sigval sig); |
| | | static bool CrashRedLine1(const Polygon *map, const car_model_cache_t *car); |
| | | static bool CrashRedLine2(const Polygon *map, const car_model_cache_t *car); |
| | | static bool EnterParking(const Polygon *map, const car_model_cache_t *car); |
| | | static bool ExitParkArea(const Polygon *map, const car_model_cache_t *car); |
| | | static bool ExitTestArea(const Polygon *map, const car_model_cache_t *car); |
| | | |
| | | bool EnterParkEdgeArea(const Polygon *car, const Polygon *tire, const Polygon *map) |
| | | { |
| | | if (IntersectionOf(tire->point[0], map) == GM_Containment && |
| | | IntersectionOf(tire->point[1], map) == GM_Containment && |
| | | IntersectionOf(tire->point[4], map) == GM_Containment && |
| | | IntersectionOf(tire->point[5], map) == GM_Containment) { |
| | | return true; |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | void StartParkEdge(void) |
| | | { |
| | | prev_run_status = 0; |
| | | parkTimeout = false; |
| | | occurCrashRedLine1 = occurCrashRedLine2 = false; // 这个科目规定特殊点,发生一次扣10分,而不直接淘汰 |
| | | PETesting = true; |
| | | currTarget = ARRIVED_START; |
| | | } |
| | | |
| | | void StopParkEdge(void) |
| | | { |
| | | AppTimer_delete(ParkEdgeTimeout); |
| | | PETesting = false; |
| | | } |
| | | |
| | | int TestParkEdge(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status) |
| | | { |
| | | int status = 0; |
| | | |
| | | if (!PETesting) |
| | | return 0; |
| | | |
| | | if (currTarget >= PARK_CAR) { |
| | | if (CrashRedLine1(map, car)) { |
| | | if (!occurCrashRedLine1) { |
| | | occurCrashRedLine1 = true; |
| | | // 车轮压边线,每次扣10分 |
| | | err.push_back(23); |
| | | } |
| | | } else { |
| | | occurCrashRedLine1 = false; |
| | | } |
| | | |
| | | if (CrashRedLine2(map, car)) { |
| | | if (!occurCrashRedLine2) { |
| | | occurCrashRedLine2 = true; |
| | | // 车身压库位线,每次扣10分 |
| | | err.push_back(24); |
| | | } |
| | | } else { |
| | | occurCrashRedLine2 = false; |
| | | } |
| | | |
| | | if (parkTimeout) { |
| | | // 超时90秒,不合格 |
| | | err.push_back(22); |
| | | status = -1; |
| | | } |
| | | |
| | | if (prev_run_status != run_status) { |
| | | if (run_status == 0) { |
| | | // 车停了 |
| | | runStatusBeforeStop = prev_run_status; |
| | | stopTimepoint = AppTimer_GetTickCount(); |
| | | } else { |
| | | // 车动了,且和停车前的运行状态一致 |
| | | if (runStatusBeforeStop == run_status && AppTimer_GetTickCount() - stopTimepoint > STOP_CAR_TIME) { |
| | | // 中途停车,扣5分 |
| | | err.push_back(26); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (currTarget == ARRIVED_START) { |
| | | if (ExitTestArea(map, car)) { |
| | | // 直接驶离测试区域 |
| | | status = -2; |
| | | } else |
| | | if (run_status < 0) { |
| | | AppTimer_add(ParkEdgeTimeout, D_SEC(PARK_TIMEOUT)); |
| | | currTarget = PARK_CAR; |
| | | TextOsd(0, "开始倒库"); |
| | | } |
| | | } else if (currTarget == PARK_CAR) { |
| | | if (run_status < 0) { |
| | | carStopEvent = false; |
| | | } else if (run_status == 0) { |
| | | // 立即检查是否停车到位,也许是中途停车,先不管,待发生前进事件后,再断定是否停车到位 |
| | | if (!carStopEvent) { |
| | | carStopEvent = true; |
| | | carParkSuccess = EnterParking(map, car); |
| | | } |
| | | } else { |
| | | if (carStopEvent) { |
| | | if (!carParkSuccess) { |
| | | // 不合格:车身出线 |
| | | err.push_back(21); |
| | | status = -1; |
| | | } |
| | | } |
| | | carStopEvent = false; |
| | | leaveParkCnt = 0; |
| | | currTarget = START_CAR; |
| | | TextOsd(0, "开始出库"); |
| | | } |
| | | } else if (currTarget == START_CAR) { |
| | | if (run_status > 0) { |
| | | leaveParkCnt++; |
| | | |
| | | if (leaveParkCnt == 1) { |
| | | // 未开启转向灯,扣10分 |
| | | err.push_back(25); |
| | | } |
| | | |
| | | if (ExitParkArea(map, car)) { |
| | | // 项目完成 |
| | | status = 1; |
| | | TextOsd(0, "项目完成"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (status != 0) { |
| | | StopParkEdge(); |
| | | } |
| | | |
| | | prev_run_status = run_status; |
| | | return status; |
| | | } |
| | | |
| | | static void ParkEdgeTimeout(union sigval sig) { |
| | | AppTimer_delete(ParkEdgeTimeout); |
| | | parkTimeout = true; |
| | | } |
| | | |
| | | // 车轮是否压道路边线 |
| | | static bool CrashRedLine1(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | bool ret = false; |
| | | |
| | | Line red_line; |
| | | const int red_lines[][2] = {{0, 7}, {1, 2}, {5, 6}}; |
| | | |
| | | Line frontAxle, rearAxle; |
| | | |
| | | MakeLine(&frontAxle, &car->points[car->desc->front_left_tire[TIRE_OUTSIDE]], &car->points[car->desc->front_right_tire[TIRE_OUTSIDE]]); |
| | | MakeLine(&rearAxle, &car->points[car->desc->rear_left_tire[TIRE_OUTSIDE]], &car->points[car->desc->rear_right_tire[TIRE_OUTSIDE]]); |
| | | |
| | | for (int i = 0; i < sizeof(red_lines) / sizeof(red_lines[0]); ++i) { |
| | | MakeLine(&red_line, &map->point[red_lines[i][0]], &map->point[red_lines[i][1]]); |
| | | if (IntersectionOf(red_line, frontAxle) == GM_Intersection || |
| | | IntersectionOf(red_line, rearAxle) == GM_Intersection) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | // 车身是否压库位线 |
| | | static bool CrashRedLine2(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | bool ret = false; |
| | | |
| | | Line red_line; |
| | | const int red_lines[][2] = {{2, 3}, {3, 4}, {4, 5}}; |
| | | |
| | | Polygon car_body; |
| | | |
| | | car_body.num = car->desc->body_num; |
| | | car_body.point = (PointF *) malloc(sizeof(PointF) * car_body.num); |
| | | for (int i = 0; i < car_body.num; ++i) { |
| | | car_body.point[i] = car->points[car->desc->body[i]]; |
| | | } |
| | | |
| | | for (int i = 0; i < sizeof(red_lines) / sizeof(red_lines[0]); ++i) { |
| | | MakeLine(&red_line, &map->point[red_lines[i][0]], &map->point[red_lines[i][1]]); |
| | | if (IntersectionOf(red_line, &car_body) != GM_None) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | free(car_body.point); |
| | | return ret; |
| | | } |
| | | |
| | | static bool EnterParking(const Polygon *map, const car_model_cache_t *car) { |
| | | bool succ = false; |
| | | |
| | | Polygon parking; |
| | | Polygon car_body; |
| | | |
| | | car_body.num = car->desc->body_num; |
| | | car_body.point = (PointF *) malloc(sizeof(PointF) * car_body.num); |
| | | for (int i = 0; i < car_body.num; ++i) { |
| | | car_body.point[i] = car->points[car->desc->body[i]]; |
| | | } |
| | | |
| | | MakePolygon(&parking, {map->point[2], map->point[3], map->point[4], map->point[5]}); |
| | | |
| | | if (IntersectionOf(&car_body, &parking) == GM_Containment) { |
| | | succ = true; |
| | | } |
| | | |
| | | CleanPolygon(&parking); |
| | | free(car_body.point); |
| | | |
| | | return succ; |
| | | } |
| | | |
| | | // 整个车辆都要驶过前库位线 |
| | | static bool ExitParkArea(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | for (int i = 0; i < car->point_num; ++i) { |
| | | if (IntersectionOfLine(map->point[4], map->point[5], car->points[i]) != -1) |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | // 整个车辆都要驶过最前端控制线 |
| | | static bool ExitTestArea(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | for (int i = 0; i < car->point_num; ++i) { |
| | | if (IntersectionOfLine(map->point[6], map->point[7], car->points[i]) != -1) |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/23. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_PARK_EDGE_H |
| | | #define RTKDRIVERTEST_PARK_EDGE_H |
| | | |
| | | #include "../Geometry.h" |
| | | #include "../driver_test.h" |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | bool EnterParkEdgeArea(const Polygon *car, const Polygon *tire, const Polygon *map); |
| | | void StartParkEdge(void); |
| | | void StopParkEdge(void); |
| | | int TestParkEdge(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status); |
| | | |
| | | #endif //RTKDRIVERTEST_PARK_EDGE_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/31. |
| | | // |
| | | |
| | | #include <cstdlib> |
| | | #include <vector> |
| | | #include <cmath> |
| | | |
| | | #include "stop_and_start.h" |
| | | #include "../driver_test.h" |
| | | #include "../jni_log.h" |
| | | #include "../common/apptimer.h" |
| | | |
| | | using namespace std; |
| | | |
| | | enum |
| | | { |
| | | STOP_CAR, |
| | | START_CAR |
| | | }; |
| | | |
| | | const double STOP_DISTANCE_THRESHOLD_RED = 0.5; |
| | | const double EDGE_DISTANCE_THRESHOLD_RED = 0.5; |
| | | const double EDGE_DISTANCE_THRESHOLD_YELLOW = 0.3; |
| | | const double SLIDE_DISTANCE_THRESHOLD_RED = 0.3; |
| | | const double SLIDE_DISTANCE_THRESHOLD_YELLOW = 0.1; |
| | | const int CAR_START_TIMEOUT = 30; |
| | | const double EPSILON = 1e-3; |
| | | |
| | | static bool SASTesting = false; |
| | | |
| | | static double slideDistance; |
| | | static bool startCarTimeout; |
| | | static int currTarget; |
| | | static PointF stopPoint; |
| | | static int startCarConfirm; // 起步时,持续前进一小段才算 |
| | | |
| | | static void StartCarTimeout(union sigval sig); |
| | | static bool CrashRedLine(const Polygon *map, const car_model_cache_t *car); |
| | | static double DistanceOfHead2Stopline(const Polygon *map, const car_model_cache_t *car); |
| | | static double DistanceOfTire2Edge(const Polygon *map, const car_model_cache_t *car); |
| | | static bool ExitTestArea(const Polygon *map, const car_model_cache_t *car); |
| | | |
| | | void StartSAS(void) |
| | | { |
| | | SASTesting = true; |
| | | slideDistance = 0.0; |
| | | startCarTimeout = false; |
| | | currTarget = STOP_CAR; |
| | | } |
| | | |
| | | void StopSAS(void) |
| | | { |
| | | SASTesting = false; |
| | | AppTimer_delete(StartCarTimeout); |
| | | } |
| | | |
| | | int TestSAS(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status) |
| | | { |
| | | int status = 0; |
| | | |
| | | if (!SASTesting) |
| | | return -2; |
| | | |
| | | if (currTarget >= STOP_CAR) { |
| | | if (CrashRedLine(map, car)) { |
| | | // 车轮压线 |
| | | err.push_back(13); |
| | | status = -1; |
| | | } |
| | | } |
| | | |
| | | if (currTarget == STOP_CAR) { |
| | | if (run_status == 0) { |
| | | double dis1 = DistanceOfHead2Stopline(map, car); |
| | | double dis2 = DistanceOfTire2Edge(map, car); |
| | | |
| | | if (dis1 > STOP_DISTANCE_THRESHOLD_RED) { |
| | | // 距离停止线前后超出50厘米 |
| | | err.push_back(12); |
| | | status = -1; |
| | | } else if (fabs(dis1) > EPSILON) { |
| | | // 前保险没有位于停止带内,但没有超出50厘米 |
| | | err.push_back(17); |
| | | } |
| | | |
| | | if (dis2 > EDGE_DISTANCE_THRESHOLD_RED) { |
| | | // 距离边线超出50厘米 |
| | | err.push_back(14); |
| | | status = -1; |
| | | } else if (dis2 > EDGE_DISTANCE_THRESHOLD_YELLOW) { |
| | | // 距离边线超出30厘米 |
| | | err.push_back(18); |
| | | } |
| | | |
| | | // 检查是否拉住手刹 |
| | | |
| | | AppTimer_delete(StartCarTimeout); |
| | | AppTimer_add(StartCarTimeout, D_SEC(CAR_START_TIMEOUT)); |
| | | slideDistance = 0.0; |
| | | stopPoint = car->points[0]; |
| | | startCarConfirm = 0; |
| | | currTarget = START_CAR; |
| | | } else if (run_status > 0) { |
| | | if (ExitTestArea(map, car)) { |
| | | // 车辆直接驶离测试区,直接淘汰 |
| | | err.push_back(12); |
| | | status = -1; |
| | | } |
| | | } |
| | | } else if (currTarget == START_CAR) { |
| | | if (startCarTimeout) { |
| | | startCarTimeout = false; |
| | | //起步时间超过30秒 |
| | | err.push_back(15); |
| | | status = -1; |
| | | } |
| | | |
| | | if (run_status > 0) { |
| | | startCarConfirm++; |
| | | if (startCarConfirm == 2) { |
| | | AppTimer_delete(StartCarTimeout); // 起步完成 |
| | | } |
| | | |
| | | if (slideDistance > SLIDE_DISTANCE_THRESHOLD_YELLOW) { |
| | | // 后滑超过10厘米,但没超过30厘米 |
| | | err.push_back(20); |
| | | } |
| | | } else if (run_status < 0) { |
| | | // 后滑了 |
| | | slideDistance = DistanceOf(stopPoint, car->points[0]); |
| | | if (slideDistance > SLIDE_DISTANCE_THRESHOLD_RED) { |
| | | // 后滑超过30厘米 |
| | | err.push_back(16); |
| | | status = -1; |
| | | } |
| | | } |
| | | |
| | | if (ExitTestArea(map, car)) { |
| | | // 测试完成了 |
| | | status = 1; |
| | | } |
| | | } |
| | | |
| | | if (status != 0) { |
| | | StopSAS(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | static void StartCarTimeout(union sigval sig) { |
| | | AppTimer_delete(StartCarTimeout); |
| | | startCarTimeout = true; |
| | | } |
| | | |
| | | // 车轮是否压边线 |
| | | static bool CrashRedLine(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | bool ret = false; |
| | | |
| | | Line red_line; |
| | | const int red_lines[][2] = {{0, 8}}; |
| | | |
| | | Line frontAxle, rearAxle; |
| | | |
| | | MakeLine(&frontAxle, &car->points[car->desc->front_left_tire[TIRE_OUTSIDE]], &car->points[car->desc->front_right_tire[TIRE_OUTSIDE]]); |
| | | MakeLine(&rearAxle, &car->points[car->desc->rear_left_tire[TIRE_OUTSIDE]], &car->points[car->desc->rear_right_tire[TIRE_OUTSIDE]]); |
| | | |
| | | for (int i = 0; i < sizeof(red_lines) / sizeof(red_lines[0]); ++i) { |
| | | MakeLine(&red_line, &map->point[red_lines[i][0]], &map->point[red_lines[i][1]]); |
| | | if (IntersectionOf(red_line, frontAxle) == GM_Intersection || |
| | | IntersectionOf(red_line, rearAxle) == GM_Intersection) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | static double DistanceOfHead2Stopline(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | double dis = 0.0; |
| | | |
| | | int rel1 = IntersectionOfLine(map->point[4], map->point[3], car->points[0]); |
| | | int rel2 = IntersectionOfLine(map->point[5], map->point[6], car->points[0]); |
| | | |
| | | if (rel1 == 1) { |
| | | Line line1; |
| | | |
| | | MakeLine(&line1, &map->point[4], &map->point[3]); |
| | | |
| | | dis = DistanceOf(car->points[0], line1); |
| | | } else if (rel2 == -1) { |
| | | Line line2; |
| | | |
| | | MakeLine(&line2, &map->point[5], &map->point[6]); |
| | | |
| | | dis = DistanceOf(car->points[0], line2); |
| | | } |
| | | |
| | | return dis; |
| | | } |
| | | |
| | | static double DistanceOfTire2Edge(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | Line edge; |
| | | |
| | | MakeLine(&edge, &map->point[0], &map->point[8]); |
| | | |
| | | double l1 = DistanceOf(car->points[car->desc->front_right_tire[TIRE_OUTSIDE]], edge); |
| | | |
| | | double l2 = DistanceOf(car->points[car->desc->rear_right_tire[TIRE_OUTSIDE]], edge); |
| | | |
| | | return (l1+l2)/2.0; |
| | | } |
| | | |
| | | // 整个车辆都要驶离该测试区域 |
| | | static bool ExitTestArea(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | for (int i = 0; i < car->point_num; ++i) { |
| | | if (IntersectionOfLine(map->point[8], map->point[7], car->points[i]) != -1) |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/10/31. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_STOP_AND_START_H |
| | | #define RTKDRIVERTEST_STOP_AND_START_H |
| | | |
| | | #include "../driver_test.h" |
| | | |
| | | using namespace std; |
| | | |
| | | void StartSAS(void); |
| | | void StopSAS(void); |
| | | int TestSAS(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status); |
| | | |
| | | #endif //RTKDRIVERTEST_STOP_AND_START_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/11/4. |
| | | // |
| | | |
| | | #include "turn_a90.h" |
| | | #include "../Geometry.h" |
| | | #include "../driver_test.h" |
| | | #include "../common/apptimer.h" |
| | | #include "../jni_log.h" |
| | | |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | enum { |
| | | TURN_ANGLE_90, |
| | | TURN_ANGLE_90_CMP |
| | | }; |
| | | |
| | | const uint32_t STOP_CAR_TIME = D_SEC(2); |
| | | |
| | | static bool TA90Testing; |
| | | static bool carStopEvent; |
| | | static bool checked; |
| | | static int currTarget; |
| | | static int azimuth; |
| | | static uint32_t stopTimepoint = 0; |
| | | |
| | | static bool CrashRedLine(const Polygon *map, const car_model_cache_t *car); |
| | | static bool ExitTestArea(const Polygon *map, const car_model_cache_t *car); |
| | | static bool Turned(const Polygon *map, const car_model_cache_t *car); |
| | | |
| | | void StartTurnA90(double heading) |
| | | { |
| | | azimuth = (int) heading; |
| | | checked = false; |
| | | TA90Testing = true; |
| | | carStopEvent = false; |
| | | |
| | | currTarget = TURN_ANGLE_90; |
| | | } |
| | | |
| | | void StopTurnA90(void) |
| | | { |
| | | TA90Testing = false; |
| | | } |
| | | |
| | | int TestTurnA90(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status, double heading) |
| | | { |
| | | int status = 0; |
| | | |
| | | if (!TA90Testing) |
| | | return -2; |
| | | |
| | | DEBUG("TestTurnA90 %d", run_status); |
| | | |
| | | if (CrashRedLine(map, car)) { |
| | | // 压线了 |
| | | err.push_back(29); |
| | | status = -1; |
| | | DEBUG("错误 压线"); |
| | | } |
| | | |
| | | if (run_status != 0) { |
| | | if (carStopEvent) |
| | | DEBUG("TURN_ANGLE_90 停车时间 %ld", AppTimer_GetTickCount() - stopTimepoint); |
| | | |
| | | if (carStopEvent && AppTimer_GetTickCount() - stopTimepoint > STOP_CAR_TIME) { |
| | | // 中途停车 |
| | | err.push_back(31); |
| | | DEBUG("错误 停车1"); |
| | | } |
| | | carStopEvent = false; |
| | | } else if (!carStopEvent){ |
| | | carStopEvent = true; |
| | | stopTimepoint = AppTimer_GetTickCount(); |
| | | } |
| | | |
| | | if (ExitTestArea(map, car)) { |
| | | // 测试结束 |
| | | status = 1; |
| | | } |
| | | |
| | | if (currTarget == TURN_ANGLE_90) { |
| | | // 转向灯开启 |
| | | int az = (int) heading; |
| | | |
| | | if (abs(az - azimuth) > 180) { |
| | | az = 360 - abs(az-azimuth); |
| | | } else { |
| | | az = abs(az - azimuth); |
| | | } |
| | | |
| | | if (az >= 10 && !checked) { |
| | | checked = true; |
| | | // 转向灯未开启 |
| | | err.push_back(30); |
| | | DEBUG("错误 灯没看"); |
| | | } |
| | | |
| | | if (Turned(map, car)) { |
| | | currTarget = TURN_ANGLE_90_CMP; |
| | | checked = false; |
| | | } |
| | | DEBUG("TURN_ANGLE_90 %d %d",run_status, az); |
| | | } else { |
| | | // 关闭转向灯 |
| | | Line line; |
| | | |
| | | MakeLine(&line, &map->point[1], &map->point[2]); |
| | | |
| | | // 大于2.5米后检查车灯 |
| | | if (!checked && DistanceOf(car->points[0], line) >= 2.5) { |
| | | checked = true; |
| | | // 转向灯未关闭 |
| | | err.push_back(30); |
| | | DEBUG("错误 灯没管"); |
| | | } |
| | | DEBUG("TURN_ANGLE_90_CMP"); |
| | | } |
| | | |
| | | if (status != 0) { |
| | | StopTurnA90(); |
| | | } |
| | | |
| | | return status; |
| | | } |
| | | |
| | | // 车轮是否压边线 |
| | | static bool CrashRedLine(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | bool ret = false; |
| | | |
| | | Line red_line; |
| | | const int red_lines[][2] = {{0, 5}, {5, 4}, {1, 2}, {2, 3}}; |
| | | |
| | | Line frontAxle, rearAxle; |
| | | |
| | | // 仅看车轮外侧 |
| | | MakeLine(&frontAxle, &car->points[car->desc->front_left_tire[TIRE_OUTSIDE]], &car->points[car->desc->front_right_tire[TIRE_OUTSIDE]]); |
| | | MakeLine(&rearAxle, &car->points[car->desc->rear_left_tire[TIRE_OUTSIDE]], &car->points[car->desc->rear_right_tire[TIRE_OUTSIDE]]); |
| | | |
| | | for (int i = 0; i < sizeof(red_lines) / sizeof(red_lines[0]); ++i) { |
| | | MakeLine(&red_line, &map->point[red_lines[i][0]], &map->point[red_lines[i][1]]); |
| | | if (IntersectionOf(red_line, frontAxle) == GM_Intersection || |
| | | IntersectionOf(red_line, rearAxle) == GM_Intersection) { |
| | | ret = true; |
| | | break; |
| | | } |
| | | } |
| | | |
| | | return ret; |
| | | } |
| | | |
| | | // 整个车辆都要驶离该测试区域 |
| | | static bool ExitTestArea(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | for (int i = 0; i < car->point_num; ++i) { |
| | | if (IntersectionOfLine(map->point[3], map->point[4], car->points[i]) != 1) |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
| | | |
| | | static bool Turned(const Polygon *map, const car_model_cache_t *car) |
| | | { |
| | | for (int i = 0; i < car->point_num; ++i) { |
| | | if (IntersectionOfLine(map->point[1], map->point[2], car->points[i]) != 1) |
| | | return false; |
| | | } |
| | | return true; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/11/4. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_TURN_A90_H |
| | | #define RTKDRIVERTEST_TURN_A90_H |
| | | |
| | | #include "../driver_test.h" |
| | | #include <vector> |
| | | |
| | | using namespace std; |
| | | |
| | | void StartTurnA90(double heading); |
| | | void StopTurnA90(void); |
| | | int TestTurnA90(vector<int>&err, const Polygon *map, const car_model_cache_t *car, double speed, int run_status, double heading); |
| | | |
| | | #endif //RTKDRIVERTEST_TURN_A90_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/9/10. |
| | | // |
| | | |
| | | #include <cstdio> |
| | | #include "crc16.h" |
| | | |
| | | const static unsigned short crc_table [256] = { |
| | | 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, |
| | | 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, |
| | | 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, 0x1231, 0x0210, |
| | | 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, |
| | | 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, |
| | | 0xf3ff, 0xe3de, 0x2462, 0x3443, 0x0420, 0x1401, |
| | | 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, |
| | | 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, |
| | | 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, |
| | | 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, |
| | | 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, 0x48c4, 0x58e5, |
| | | 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, |
| | | 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, |
| | | 0xa90a, 0xb92b, 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, |
| | | 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, |
| | | 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, |
| | | 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, |
| | | 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, |
| | | 0xad2a, 0xbd0b, 0x8d68, 0x9d49, 0x7e97, 0x6eb6, |
| | | 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, |
| | | 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, |
| | | 0x9f59, 0x8f78, 0x9188, 0x81a9, 0xb1ca, 0xa1eb, |
| | | 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, |
| | | 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, |
| | | 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, |
| | | 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, |
| | | 0x4235, 0x5214, 0x6277, 0x7256, 0xb5ea, 0xa5cb, |
| | | 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, |
| | | 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, |
| | | 0x5424, 0x4405, 0xa7db, 0xb7fa, 0x8799, 0x97b8, |
| | | 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, |
| | | 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, |
| | | 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, |
| | | 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, |
| | | 0x18c0, 0x08e1, 0x3882, 0x28a3, 0xcb7d, 0xdb5c, |
| | | 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, |
| | | 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, |
| | | 0x2ab3, 0x3a92, 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, |
| | | 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, |
| | | 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, |
| | | 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, |
| | | 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, |
| | | 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 |
| | | }; |
| | | |
| | | unsigned short CRCCCITT(unsigned char *data, size_t length, unsigned short seed, unsigned short final) |
| | | { |
| | | size_t count; |
| | | unsigned int crc = seed; |
| | | unsigned int temp; |
| | | |
| | | for (count = 0; count < length; ++count) { |
| | | temp = (*data++ ^ (crc >> 8)) & 0xff; |
| | | crc = crc_table[temp] ^ (crc << 8); |
| | | } |
| | | |
| | | return (unsigned short)(crc ^ final); |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/9/10. |
| | | // |
| | | |
| | | #ifndef ANYUNPROJECT_CRC16_H |
| | | #define ANYUNPROJECT_CRC16_H |
| | | |
| | | #include <cstdio> |
| | | |
| | | unsigned short CRCCCITT(unsigned char *data, size_t length, unsigned short seed, unsigned short final); |
| | | |
| | | #endif //ANYUNPROJECT_CRC16_H |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/23. |
| | | // |
| | | |
| | | #include "num.h" |
| | | |
| | | long str2int(const uint8_t *s, uint16_t length) |
| | | { |
| | | uint16_t i; |
| | | long n = 0; |
| | | bool sign = false; |
| | | |
| | | for(i = 0; i < length; i++) |
| | | { |
| | | |
| | | if(s[i] >= '0' && s[i] <= '9') { |
| | | n = n*10 + s[i] - '0'; |
| | | } else if (i == 0 && s[i]=='-') { |
| | | sign = true; |
| | | } |
| | | } |
| | | |
| | | if (sign) { |
| | | n = 0-n; |
| | | } |
| | | |
| | | return n; |
| | | } |
| | | |
| | | bool str2float(double *f, const uint8_t *s, uint16_t length) |
| | | { |
| | | bool sign = false; |
| | | bool getDecimal = false; |
| | | uint16_t i; |
| | | uint64_t m = 0, n = 1; |
| | | double x; |
| | | |
| | | *f = 0.0; |
| | | |
| | | for(i = 0; i < length; i++) |
| | | { |
| | | if(s[i] == '-' || s[i] == '+') { |
| | | if(i == 0) { |
| | | if (s[i] == '-') { |
| | | sign = true; |
| | | } |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | else if(s[i] == '.') { |
| | | if(getDecimal == true) { |
| | | return false; |
| | | } |
| | | getDecimal = true; |
| | | } |
| | | else if(s[i] >= '0' && s[i] <= '9') { |
| | | m = m*10 + s[i] - '0'; |
| | | if(getDecimal == true) { |
| | | n *= 10; |
| | | } |
| | | } |
| | | else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | x = (double)m / (double)n; |
| | | if(sign) { |
| | | x = 0.0 - x; |
| | | } |
| | | *f = x; |
| | | |
| | | return true; |
| | | } |
New file |
| | |
| | | // |
| | | // Created by YY on 2019/12/23. |
| | | // |
| | | |
| | | #ifndef RTKDRIVERTEST_NUM_H |
| | | #define RTKDRIVERTEST_NUM_H |
| | | |
| | | #include <cstdint> |
| | | |
| | | long str2int(const uint8_t *s, uint16_t length); |
| | | bool str2float(double *f, const uint8_t *s, uint16_t length); |
| | | |
| | | #endif //RTKDRIVERTEST_NUM_H |
| | |
| | | |
| | | import android.app.Service; |
| | | import android.content.Intent; |
| | | import android.content.SharedPreferences; |
| | | import android.os.IBinder; |
| | | import android.os.RemoteCallbackList; |
| | | import android.os.RemoteException; |
| | | import android.util.Base64; |
| | | import android.util.Log; |
| | | |
| | | import com.anyun.exam.lib.util.DESUtil; |
| | | import com.anyun.exam.lib.util.NetUtils; |
| | | |
| | | import androidx.annotation.Nullable; |
| | | |
| | |
| | | * All Rights Saved! Chongqing AnYun Tech co. LTD |
| | | */ |
| | | public class RemoteService extends Service { |
| | | |
| | | private static final String TAG = "RemoteService"; |
| | | private final static String LOAD_KEY = "RTKBaseStation"; |
| | | /**服务是否销毁标志*/ |
| | | private AtomicBoolean mIsServiceDestroyed = new AtomicBoolean(false); |
| | | private RemoteCallbackList<IListenerInterface> mListenerList = new RemoteCallbackList(); |
| | |
| | | public void onCreate() { |
| | | super.onCreate(); |
| | | Log.i(TAG,"onCreate()"); |
| | | startNative(); |
| | | new Thread(new Worker()).start(); |
| | | } |
| | | |
| | |
| | | mListenerList.finishBroadcast(); |
| | | } |
| | | } |
| | | |
| | | public String javaGetImei() { |
| | | return NetUtils.getDeviceId(getApplicationContext()); |
| | | } |
| | | |
| | | public String javaDESEncrypt(String plaintext, String key) { |
| | | try { |
| | | byte []des = DESUtil.encrypt(plaintext.getBytes("utf-8"), key); |
| | | return Base64.encodeToString(des, Base64.DEFAULT); |
| | | } catch (Exception e) { |
| | | |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public byte[] javaDESEncrypt(byte []plaintext, byte []key) { |
| | | try { |
| | | return DESUtil.encrypt(plaintext, key); |
| | | } catch (Exception e) { |
| | | |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | public void SetPlatformKey(byte []key) { |
| | | String params = Base64.encodeToString(key, Base64.DEFAULT); |
| | | |
| | | SharedPreferences sharedPreferences = getSharedPreferences(LOAD_KEY, MODE_PRIVATE); |
| | | SharedPreferences.Editor editor = sharedPreferences.edit(); |
| | | editor.putString("platform_key", params); |
| | | editor.commit(); |
| | | } |
| | | |
| | | public byte[] GetPlatformKey() { |
| | | SharedPreferences sharedPreferences = getSharedPreferences(LOAD_KEY, MODE_PRIVATE); |
| | | String params = sharedPreferences.getString("platform_key", ""); |
| | | if (params.equals("")) { |
| | | return null; |
| | | } |
| | | return Base64.decode(params, Base64.DEFAULT); |
| | | } |
| | | |
| | | public void DeletePlatformKey() { |
| | | SharedPreferences sharedPreferences = getSharedPreferences(LOAD_KEY, MODE_PRIVATE); |
| | | SharedPreferences.Editor editor = sharedPreferences.edit(); |
| | | editor.putString("platform_key", ""); |
| | | editor.commit(); |
| | | } |
| | | |
| | | public void SetSharedValue(String key, int value) { |
| | | SharedPreferences sharedPreferences = getSharedPreferences(LOAD_KEY, MODE_PRIVATE); |
| | | SharedPreferences.Editor editor = sharedPreferences.edit(); |
| | | editor.putInt(key, value); |
| | | editor.commit(); |
| | | } |
| | | |
| | | public int GetSharedValue(String key) { |
| | | SharedPreferences sharedPreferences = getSharedPreferences(LOAD_KEY, MODE_PRIVATE); |
| | | return sharedPreferences.getInt(key, 0); |
| | | } |
| | | |
| | | // Used to load the 'native-lib' library on application startup. |
| | | static { |
| | | System.loadLibrary("native-lib"); |
| | | } |
| | | |
| | | public native void startNative(); |
| | | } |
New file |
| | |
| | | package com.anyun.exam.lib.util; |
| | | |
| | | public class ByteUtil { |
| | | public static String byte2hex(byte [] buffer){ |
| | | StringBuilder h = new StringBuilder(); |
| | | for(int i = 0; i < buffer.length; i++){ |
| | | String temp = Integer.toHexString(buffer[i] & 0xFF).toUpperCase(); |
| | | if(temp.length() == 1){ |
| | | temp = "0" + temp; |
| | | } |
| | | h.append(temp); |
| | | h.append(" "); |
| | | } |
| | | return h.toString(); |
| | | } |
| | | } |
New file |
| | |
| | | package com.anyun.exam.lib.util; |
| | | |
| | | import android.util.Base64; |
| | | |
| | | import java.security.SecureRandom; |
| | | |
| | | import javax.crypto.Cipher; |
| | | import javax.crypto.SecretKey; |
| | | import javax.crypto.SecretKeyFactory; |
| | | import javax.crypto.spec.DESKeySpec; |
| | | import javax.crypto.spec.IvParameterSpec; |
| | | |
| | | public class DESUtil { |
| | | private static String password = "safeluck"; |
| | | |
| | | /** |
| | | * |
| | | * @Method: encrypt |
| | | * @Description: 加密数据 |
| | | * @param data |
| | | * @return |
| | | * @throws Exception |
| | | * @date 2016年7月26日 |
| | | */ |
| | | public static String encrypt(String data, String pwd) { //对string进行BASE64Encoder转换 |
| | | byte[] bt = encryptByKey(data.getBytes(), pwd); |
| | | return Base64.encodeToString(bt, Base64.DEFAULT); |
| | | } |
| | | |
| | | public static byte[] encrypt(byte[] message, String key) throws Exception { |
| | | Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); |
| | | DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8")); |
| | | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
| | | SecretKey secretKey = keyFactory.generateSecret(desKeySpec); |
| | | IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8")); |
| | | cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); |
| | | return cipher.doFinal(message); |
| | | } |
| | | |
| | | public static byte[] encrypt(byte[] message, byte[] key) throws Exception { |
| | | Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); |
| | | DESKeySpec desKeySpec = new DESKeySpec(key); |
| | | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
| | | SecretKey secretKey = keyFactory.generateSecret(desKeySpec); |
| | | IvParameterSpec iv = new IvParameterSpec(key); |
| | | cipher.init(Cipher.ENCRYPT_MODE, secretKey, iv); |
| | | return cipher.doFinal(message); |
| | | } |
| | | |
| | | public static byte[] decrypt2(byte[] message, String key) throws Exception { |
| | | Cipher cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); |
| | | DESKeySpec desKeySpec = new DESKeySpec(key.getBytes("UTF-8")); |
| | | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
| | | SecretKey secretKey = keyFactory.generateSecret(desKeySpec); |
| | | IvParameterSpec iv = new IvParameterSpec(key.getBytes("UTF-8")); |
| | | cipher.init(Cipher.DECRYPT_MODE, secretKey, iv); |
| | | return cipher.doFinal(message); |
| | | } |
| | | |
| | | /** |
| | | * |
| | | * @Method: encrypt |
| | | * @Description: 解密数据 |
| | | * @param data |
| | | * @return |
| | | * @throws Exception |
| | | * @date 2016年7月26日 |
| | | */ |
| | | public static String decryptor(String data, String pwd) throws Exception { //对string进行BASE64Encoder转换 |
| | | byte[] bt = decrypt(Base64.decode(data, Base64.DEFAULT), pwd); |
| | | String strs = new String(bt); |
| | | return strs; |
| | | } |
| | | /** |
| | | * 加密 |
| | | * @param datasource byte[] |
| | | * @param password String |
| | | * @return byte[] |
| | | */ |
| | | private static byte[] encryptByKey(byte[] datasource, String key) { |
| | | try{ |
| | | SecureRandom random = new SecureRandom(); |
| | | |
| | | DESKeySpec desKey = new DESKeySpec(key.getBytes()); |
| | | //创建一个密匙工厂,然后用它把DESKeySpec转换成 |
| | | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
| | | SecretKey securekey = keyFactory.generateSecret(desKey); |
| | | //Cipher对象实际完成加密操作 |
| | | Cipher cipher = Cipher.getInstance("DES"); |
| | | //用密匙初始化Cipher对象 |
| | | cipher.init(Cipher.ENCRYPT_MODE, securekey); |
| | | //现在,获取数据并加密 |
| | | //正式执行加密操作 |
| | | return cipher.doFinal(datasource); |
| | | }catch(Throwable e){ |
| | | e.printStackTrace(); |
| | | } |
| | | return null; |
| | | } |
| | | /** |
| | | * 解密 |
| | | * @param src byte[] |
| | | * @param password String |
| | | * @return byte[] |
| | | * @throws Exception |
| | | */ |
| | | private static byte[] decrypt(byte[] src, String key) throws Exception { |
| | | // DES算法要求有一个可信任的随机数源 |
| | | SecureRandom random = new SecureRandom(); |
| | | // 创建一个DESKeySpec对象 |
| | | DESKeySpec desKey = new DESKeySpec(key.getBytes()); |
| | | // 创建一个密匙工厂 |
| | | SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES"); |
| | | // 将DESKeySpec对象转换成SecretKey对象 |
| | | SecretKey securekey = keyFactory.generateSecret(desKey); |
| | | // Cipher对象实际完成解密操作 |
| | | Cipher cipher = Cipher.getInstance("DES"); |
| | | // 用密匙初始化Cipher对象 |
| | | cipher.init(Cipher.DECRYPT_MODE, securekey, random); |
| | | // 真正开始解密操作 |
| | | return cipher.doFinal(src); |
| | | } |
| | | } |
| | | |
New file |
| | |
| | | package com.anyun.exam.lib.util; |
| | | |
| | | import android.content.Context; |
| | | import android.net.ConnectivityManager; |
| | | import android.net.NetworkInfo; |
| | | import android.net.NetworkInfo.State; |
| | | import android.net.wifi.WifiInfo; |
| | | import android.net.wifi.WifiManager; |
| | | import android.telephony.TelephonyManager; |
| | | |
| | | import java.net.Inet4Address; |
| | | import java.net.InetAddress; |
| | | import java.net.NetworkInterface; |
| | | import java.net.SocketException; |
| | | import java.util.Enumeration; |
| | | |
| | | /** |
| | | * Created by YY on 2017/10/27. |
| | | */ |
| | | public class NetUtils { |
| | | /** |
| | | * 判断网络情况 |
| | | * |
| | | * @param context 上下文 |
| | | * @return false 表示没有网络 true 表示有网络 |
| | | */ |
| | | public static boolean isNetworkAvalible(Context context) { |
| | | // 获得网络状态管理器 |
| | | ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| | | |
| | | if (connectivityManager == null) { |
| | | return false; |
| | | } else { |
| | | // 建立网络数组 |
| | | NetworkInfo[] net_info = connectivityManager.getAllNetworkInfo(); |
| | | |
| | | if (net_info != null) { |
| | | for (int i = 0; i < net_info.length; i++) { |
| | | // 判断获得的网络状态是否是处于连接状态 |
| | | if (net_info[i].getState() == State.CONNECTED) { |
| | | return true; |
| | | } |
| | | } |
| | | } |
| | | } |
| | | return false; |
| | | } |
| | | |
| | | /** |
| | | * 判断网络是否连接 |
| | | **/ |
| | | public static boolean netState(Context context) { |
| | | ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| | | // 获取代表联网状态的NetWorkInfo对象 |
| | | NetworkInfo networkInfo = connManager.getActiveNetworkInfo(); |
| | | // 获取当前的网络连接是否可用 |
| | | boolean available = false; |
| | | try { |
| | | available = networkInfo.isAvailable(); |
| | | } catch (Exception e) { |
| | | // e.printStackTrace(); |
| | | return false; |
| | | } |
| | | if (available) { |
| | | return true; |
| | | } else { |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 在连接到网络基础之上,判断设备是否是SIM网络连接 |
| | | * |
| | | * @param context |
| | | * @return |
| | | */ |
| | | public static boolean IsMobileNetConnect(Context context) { |
| | | try { |
| | | ConnectivityManager connManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| | | State state = connManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState(); |
| | | if (State.CONNECTED == state) |
| | | return true; |
| | | else |
| | | return false; |
| | | } catch (Exception e) { |
| | | e.printStackTrace(); |
| | | return false; |
| | | } |
| | | } |
| | | |
| | | //返回值 -1:没有网络 1:WIFI网络2:wap网络3:net网络 |
| | | public static int GetNetype(Context context) { |
| | | int netType = -1; |
| | | ConnectivityManager connMgr = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); |
| | | NetworkInfo networkInfo = connMgr.getActiveNetworkInfo(); |
| | | if(networkInfo==null) { |
| | | return netType; |
| | | } |
| | | int nType = networkInfo.getType(); |
| | | if(nType== ConnectivityManager.TYPE_MOBILE) { |
| | | if(networkInfo.getExtraInfo().toLowerCase().equals("cmnet")) { |
| | | netType = 3; |
| | | } |
| | | else { |
| | | netType = 2; |
| | | } |
| | | } |
| | | else if(nType== ConnectivityManager.TYPE_WIFI) { |
| | | netType = 1; |
| | | } |
| | | return netType; |
| | | } |
| | | |
| | | public static boolean hasSimCard(Context context) { |
| | | TelephonyManager telMgr = (TelephonyManager) |
| | | context.getSystemService(Context.TELEPHONY_SERVICE); |
| | | boolean result = true; |
| | | switch (telMgr.getSimState()) { |
| | | case TelephonyManager.SIM_STATE_ABSENT: |
| | | result = false; // 没有SIM卡 |
| | | break; |
| | | case TelephonyManager.SIM_STATE_UNKNOWN: |
| | | result = false; |
| | | break; |
| | | } |
| | | return result; |
| | | } |
| | | |
| | | public static TelephonyManager getTelephonyManager(Context context) { |
| | | // 获取telephony系统服务,用于取得SIM卡和网络相关信息 |
| | | TelephonyManager mTelephonyManager = (TelephonyManager) context |
| | | .getSystemService(Context.TELEPHONY_SERVICE); |
| | | return mTelephonyManager; |
| | | } |
| | | |
| | | public static String getIccid(Context context) { |
| | | TelephonyManager mTelephonyManager = (TelephonyManager) context |
| | | .getSystemService(Context.TELEPHONY_SERVICE); |
| | | try { |
| | | return mTelephonyManager.getSimSerialNumber(); |
| | | } catch (SecurityException e) { |
| | | |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 唯一的设备ID: GSM手机的 IMEI 和 CDMA手机的 MEID. Return null if device ID is not |
| | | * 取得手机IMEI |
| | | * available. |
| | | */ |
| | | public static String getDeviceId(Context context) { |
| | | String mDeviceId = getTelephonyManager(context).getImei();// String |
| | | return mDeviceId; |
| | | } |
| | | |
| | | /** |
| | | * 取得IMEI SV |
| | | * 设备的软件版本号: 返回移动终端的软件版本,例如:GSM手机的IMEI/SV码。 例如:the IMEI/SV(software version) |
| | | * for GSM phones. Return null if the software version is not available. |
| | | */ |
| | | public static String getDeviceSoftwareVersion(Context context) { |
| | | String mDeviceSoftwareVersion = getTelephonyManager(context).getDeviceSoftwareVersion();// String |
| | | return mDeviceSoftwareVersion; |
| | | } |
| | | |
| | | /** |
| | | * 取得手机IMSI |
| | | * 返回用户唯一标识,比如GSM网络的IMSI编号 唯一的用户ID: 例如:IMSI(国际移动用户识别码) for a GSM phone. |
| | | * 需要权限:READ_PHONE_STATE |
| | | */ |
| | | public static String getSubscriberId(Context context) { |
| | | String mSubscriberId = getTelephonyManager(context).getSubscriberId();// String |
| | | return mSubscriberId; |
| | | } |
| | | |
| | | public static String getIPAddress(Context context) { |
| | | NetworkInfo info = ((ConnectivityManager) context |
| | | .getSystemService(Context.CONNECTIVITY_SERVICE)).getActiveNetworkInfo(); |
| | | if (info != null && info.isConnected()) { |
| | | if (info.getType() == ConnectivityManager.TYPE_MOBILE) {//当前使用2G/3G/4G网络 |
| | | try { |
| | | //Enumeration<NetworkInterface> en=NetworkInterface.getNetworkInterfaces(); |
| | | for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements(); ) { |
| | | NetworkInterface intf = en.nextElement(); |
| | | for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements(); ) { |
| | | InetAddress inetAddress = enumIpAddr.nextElement(); |
| | | if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) { |
| | | return inetAddress.getHostAddress(); |
| | | } |
| | | } |
| | | } |
| | | } catch (SocketException e) { |
| | | e.printStackTrace(); |
| | | } |
| | | |
| | | } else if (info.getType() == ConnectivityManager.TYPE_WIFI) {//当前使用无线网络 |
| | | WifiManager wifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE); |
| | | WifiInfo wifiInfo = wifiManager.getConnectionInfo(); |
| | | String ipAddress = intIP2StringIP(wifiInfo.getIpAddress());//得到IPV4地址 |
| | | return ipAddress; |
| | | } |
| | | } else { |
| | | //当前无网络连接,请在设置中打开网络 |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * 将得到的int类型的IP转换为String类型 |
| | | * |
| | | * @param ip |
| | | * @return |
| | | */ |
| | | public static String intIP2StringIP(int ip) { |
| | | return (ip & 0xFF) + "." + |
| | | ((ip >> 8) & 0xFF) + "." + |
| | | ((ip >> 16) & 0xFF) + "." + |
| | | (ip >> 24 & 0xFF); |
| | | } |
| | | } |
New file |
| | |
| | | package com.anyun.exam.lib.util; |
| | | |
| | | import android.content.Context; |
| | | import android.speech.tts.TextToSpeech; |
| | | import android.util.Log; |
| | | |
| | | import java.util.Locale; |
| | | |
| | | public class Speaker { |
| | | private Context context; |
| | | private TextToSpeech tts; |
| | | |
| | | final public String TAG = Speaker.class.getCanonicalName(); |
| | | |
| | | public Speaker(final Context context) { |
| | | // TODO Auto-generated constructor stub |
| | | this.context = context; |
| | | tts = new TextToSpeech(context, new TextToSpeech.OnInitListener() { |
| | | @Override |
| | | public void onInit(int status) { |
| | | Log.d(TAG, "onInit TextToSpeech.SUCCESS"); |
| | | |
| | | // TODO Auto-generated method stub |
| | | if (status == TextToSpeech.SUCCESS) |
| | | { |
| | | Log.d(TAG, "TextToSpeech.SUCCESS"); |
| | | int result = tts.setLanguage(Locale.CHINA); |
| | | |
| | | if (result == TextToSpeech.LANG_MISSING_DATA |
| | | || result == TextToSpeech.LANG_NOT_SUPPORTED) |
| | | { |
| | | Log.d(TAG, "TextToSpeech.LANG_NOT_SUPPORTED"); |
| | | } |
| | | } |
| | | } |
| | | }); |
| | | } |
| | | |
| | | public void speak(String text) { |
| | | Log.d(TAG, "SPEAK"); |
| | | // tts.speak(text, TextToSpeech.QUEUE_FLUSH, null); |
| | | tts.speak(text, TextToSpeech.QUEUE_ADD, null, "speech"); |
| | | } |
| | | } |