├── TelePager-bot
├── .gradle
│ ├── 7.1.1
│ │ ├── gc.properties
│ │ ├── fileChanges
│ │ │ └── last-build.bin
│ │ ├── dependencies-accessors
│ │ │ ├── gc.properties
│ │ │ └── dependencies-accessors.lock
│ │ ├── fileHashes
│ │ │ ├── fileHashes.bin
│ │ │ └── fileHashes.lock
│ │ └── executionHistory
│ │ │ ├── executionHistory.bin
│ │ │ └── executionHistory.lock
│ ├── vcs-1
│ │ └── gc.properties
│ ├── buildOutputCleanup
│ │ ├── cache.properties
│ │ ├── outputFiles.bin
│ │ └── buildOutputCleanup.lock
│ └── checksums
│ │ ├── checksums.lock
│ │ ├── md5-checksums.bin
│ │ └── sha1-checksums.bin
├── settings.gradle
├── .idea
│ ├── .gitignore
│ ├── compiler.xml
│ ├── misc.xml
│ ├── gradle.xml
│ ├── jarRepositories.xml
│ └── uiDesigner.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── build.gradle
├── src
│ └── main
│ │ └── java
│ │ ├── Main.java
│ │ ├── PagerBot.java
│ │ └── Serial.java
├── gradlew.bat
└── gradlew
├── NotificationsToPager-android
├── app
│ ├── .gitignore
│ ├── src
│ │ ├── main
│ │ │ ├── res
│ │ │ │ ├── values
│ │ │ │ │ ├── strings.xml
│ │ │ │ │ ├── colors.xml
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── mipmap-hdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-mdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-xxxhdpi
│ │ │ │ │ ├── ic_launcher.webp
│ │ │ │ │ └── ic_launcher_round.webp
│ │ │ │ ├── mipmap-anydpi-v26
│ │ │ │ │ ├── ic_launcher.xml
│ │ │ │ │ └── ic_launcher_round.xml
│ │ │ │ ├── values-night
│ │ │ │ │ └── themes.xml
│ │ │ │ ├── drawable-v24
│ │ │ │ │ └── ic_launcher_foreground.xml
│ │ │ │ ├── layout
│ │ │ │ │ └── activity_main.xml
│ │ │ │ └── drawable
│ │ │ │ │ └── ic_launcher_background.xml
│ │ │ ├── AndroidManifest.xml
│ │ │ └── java
│ │ │ │ └── ru
│ │ │ │ └── example
│ │ │ │ └── notificationstopager
│ │ │ │ ├── NotificationService.kt
│ │ │ │ ├── Translit.java
│ │ │ │ └── MainActivity.kt
│ │ ├── test
│ │ │ └── java
│ │ │ │ └── ru
│ │ │ │ └── example
│ │ │ │ └── notificationstopager
│ │ │ │ └── ExampleUnitTest.java
│ │ └── androidTest
│ │ │ └── java
│ │ │ └── ru
│ │ │ └── example
│ │ │ └── notificationstopager
│ │ │ └── ExampleInstrumentedTest.java
│ ├── proguard-rules.pro
│ └── build.gradle
├── .idea
│ ├── .name
│ ├── .gitignore
│ ├── compiler.xml
│ ├── misc.xml
│ └── gradle.xml
├── gradle
│ └── wrapper
│ │ ├── gradle-wrapper.jar
│ │ └── gradle-wrapper.properties
├── .gitignore
├── settings.gradle
├── build.gradle
├── gradle.properties
├── gradlew.bat
└── gradlew
├── previ.jpg
├── Schematic.jpg
├── Variant by Dmitry Stupak
├── Schematic.jpg
└── UniversalPagerTransmiter.lay6
├── UneversalPagerSender-arduino
├── MemoryFree.h
├── MemoryFree.cpp
├── CmdProc.h
├── Storage.cpp
├── Storage.h
├── Cmd.h
├── Rf7021.h
├── PocsagEncoder.h
├── Cmd.cpp
├── PocsagEncoder.cpp
├── Rf7021.cpp
├── CmdProc.cpp
└── UneversalPagerSender.ino
└── README.md
/TelePager-bot/.gradle/7.1.1/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/vcs-1/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/fileChanges/last-build.bin:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/.idea/.name:
--------------------------------------------------------------------------------
1 | Notifications To Pager
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/dependencies-accessors/gc.properties:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/TelePager-bot/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'TelePager'
2 |
3 |
--------------------------------------------------------------------------------
/TelePager-bot/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/previ.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/previ.jpg
--------------------------------------------------------------------------------
/Schematic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/Schematic.jpg
--------------------------------------------------------------------------------
/NotificationsToPager-android/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/buildOutputCleanup/cache.properties:
--------------------------------------------------------------------------------
1 | #Mon Mar 28 23:03:00 YEKT 2022
2 | gradle.version=7.1.1
3 |
--------------------------------------------------------------------------------
/Variant by Dmitry Stupak/Schematic.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/Variant by Dmitry Stupak/Schematic.jpg
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 | Notifications To Pager
3 |
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/checksums/checksums.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/checksums/checksums.lock
--------------------------------------------------------------------------------
/TelePager-bot/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/checksums/md5-checksums.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/checksums/md5-checksums.bin
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/checksums/sha1-checksums.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/checksums/sha1-checksums.bin
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/fileHashes/fileHashes.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/7.1.1/fileHashes/fileHashes.bin
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/fileHashes/fileHashes.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/7.1.1/fileHashes/fileHashes.lock
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/buildOutputCleanup/outputFiles.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/buildOutputCleanup/outputFiles.bin
--------------------------------------------------------------------------------
/Variant by Dmitry Stupak/UniversalPagerTransmiter.lay6:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/Variant by Dmitry Stupak/UniversalPagerTransmiter.lay6
--------------------------------------------------------------------------------
/NotificationsToPager-android/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/executionHistory/executionHistory.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/7.1.1/executionHistory/executionHistory.bin
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/executionHistory/executionHistory.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/7.1.1/executionHistory/executionHistory.lock
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/buildOutputCleanup/buildOutputCleanup.lock
--------------------------------------------------------------------------------
/TelePager-bot/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-hdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-mdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-xhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp
--------------------------------------------------------------------------------
/TelePager-bot/.gradle/7.1.1/dependencies-accessors/dependencies-accessors.lock:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/TelePager-bot/.gradle/7.1.1/dependencies-accessors/dependencies-accessors.lock
--------------------------------------------------------------------------------
/NotificationsToPager-android/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HotPixelChannel/UniversalPagerTransmiter/HEAD/NotificationsToPager-android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp
--------------------------------------------------------------------------------
/TelePager-bot/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/MemoryFree.h:
--------------------------------------------------------------------------------
1 | // memoryFree header
2 | // From http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213583720/15
3 | // ...written by user "mem".
4 |
5 | #ifndef MEMORY_FREE_H
6 | #define MEMORY_FREE_H
7 |
8 | int freeMemory();
9 |
10 | #endif
11 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Fri Apr 01 17:25:09 YEKT 2022
2 | distributionBase=GRADLE_USER_HOME
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip
4 | distributionPath=wrapper/dists
5 | zipStorePath=wrapper/dists
6 | zipStoreBase=GRADLE_USER_HOME
7 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/caches
5 | /.idea/libraries
6 | /.idea/modules.xml
7 | /.idea/workspace.xml
8 | /.idea/navEditor.xml
9 | /.idea/assetWizardSettings.xml
10 | .DS_Store
11 | /build
12 | /captures
13 | .externalNativeBuild
14 | .cxx
15 | local.properties
16 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/settings.gradle:
--------------------------------------------------------------------------------
1 | dependencyResolutionManagement {
2 | repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
3 | repositories {
4 | google()
5 | mavenCentral()
6 | jcenter() // Warning: this repository is going to shut down soon
7 | }
8 | }
9 | rootProject.name = "Notifications To Pager"
10 | include ':app'
11 |
--------------------------------------------------------------------------------
/TelePager-bot/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | #FFBB86FC
4 | #FF6200EE
5 | #FF3700B3
6 | #FF03DAC5
7 | #FF018786
8 | #FF000000
9 | #FFFFFFFF
10 |
--------------------------------------------------------------------------------
/TelePager-bot/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'java'
3 | }
4 |
5 | group 'org.example'
6 | version '1.0-SNAPSHOT'
7 |
8 | repositories {
9 | mavenCentral()
10 | }
11 |
12 | dependencies {
13 | testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1'
14 | testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1'
15 |
16 | implementation 'org.telegram:telegrambots:5.7.1'
17 | implementation 'com.fazecast:jSerialComm:2.9.1'
18 | }
19 |
20 | test {
21 | useJUnitPlatform()
22 | }
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/test/java/ru/example/notificationstopager/ExampleUnitTest.java:
--------------------------------------------------------------------------------
1 | package ru.example.notificationstopager;
2 |
3 | import org.junit.Test;
4 |
5 | import static org.junit.Assert.*;
6 |
7 | /**
8 | * Example local unit test, which will execute on the development machine (host).
9 | *
10 | * @see Testing documentation
11 | */
12 | public class ExampleUnitTest {
13 | @Test
14 | public void addition_isCorrect() {
15 | assertEquals(4, 2 + 2);
16 | }
17 | }
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/MemoryFree.cpp:
--------------------------------------------------------------------------------
1 | #ifdef __arm__
2 | // should use uinstd.h to define sbrk but Due causes a conflict
3 | extern "C" char* sbrk(int incr);
4 | #else // __ARM__
5 | extern char *__brkval;
6 | #endif // __arm__
7 |
8 | int freeMemory() {
9 | char top;
10 | #ifdef __arm__
11 | return &top - reinterpret_cast(sbrk(0));
12 | #elif defined(CORE_TEENSY) || (ARDUINO > 103 && ARDUINO != 151)
13 | return &top - __brkval;
14 | #else // __arm__
15 | return __brkval ? &top - __brkval : &top - __malloc_heap_start;
16 | #endif // __arm__
17 | }
18 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/CmdProc.h:
--------------------------------------------------------------------------------
1 | #ifndef _CMDPROC_H_
2 | #define _CMDPROC_H_
3 | #include "Storage.h"
4 |
5 |
6 |
7 | void printWelcome(Rf7021 rf);
8 | void processCommand();
9 | void printWelcome();
10 | void printFreeMode();
11 | void printFreeModeAdv();
12 |
13 | void printSending();
14 | void printSent();
15 | void printTrError();
16 | void pstr(String &str);
17 | void reserBuf();
18 |
19 | void printListMode();
20 | void printPager(Pager *pager, bool detailed, bool wHeader); // Print pager info
21 | void printAddDevice(byte stepC, Pager *pager) ;
22 | void printSpecMode();
23 | void printFixAdded(byte *fixed);
24 |
25 | #endif
26 |
--------------------------------------------------------------------------------
/TelePager-bot/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/build.gradle:
--------------------------------------------------------------------------------
1 | // Top-level build file where you can add configuration options common to all sub-projects/modules.
2 | buildscript {
3 | ext.kotlin_version = '1.6.20-RC2'
4 | repositories {
5 | google()
6 | mavenCentral()
7 | }
8 | dependencies {
9 | classpath "com.android.tools.build:gradle:7.0.4"
10 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
11 |
12 | // NOTE: Do not place your application dependencies here; they belong
13 | // in the individual module build.gradle files
14 | }
15 | }
16 |
17 | task clean(type: Delete) {
18 | delete rootProject.buildDir
19 | }
--------------------------------------------------------------------------------
/NotificationsToPager-android/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # UniversalPagerTransmiter
2 | 
3 |
4 | Universal POKSAG message transmitter for one pager or group of pagers. All work with the device is carried out according to the UART protocol and any terminal. Assembled on Arduino Nano and RF7021SE transmitter module
5 |
6 | Youtube: https://youtu.be/_yl8x5P07AI
7 |
8 | Based on: https://github.com/SinuXVR/arduino-pocsag-transcoder
9 |
10 | The ADF7021 (or RF7021SE module) must operate with a 14.7456 MHz TCXO and with at least 2.5 ppm of frequency stability or better. You could use also 12.2880 MHz TCXO. Any other TCXO frequency is not supported.
11 | For working on 145-160MHz needs be added by an external 18 nH inductor between L1 and L2 pins of ADF7021.
12 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/Storage.cpp:
--------------------------------------------------------------------------------
1 | #include "Storage.h"
2 | #include
3 |
4 | void clearEE() {
5 | for (int i = 0; i < EEPROM.length(); i++) EEPROM.update(i, 255);
6 | }
7 | // Add pager to EEPROM (addr 0-20)
8 | bool addPager(Pager *pager, bool toDel) {
9 | Pager lPager = *pager;
10 | if (lPager.addr > STORAGE_COUNT)
11 | return false;
12 |
13 | if (!toDel) {
14 | lPager.crc[0] = CRC[0];
15 | lPager.crc[1] = CRC[1];
16 | }else{
17 | lPager.crc[0] = 0;
18 | lPager.crc[1] = 0;
19 | }
20 | EEPROM.put(lPager.addr * sizeof(Pager), lPager);
21 | return true;
22 | }
23 |
24 | void getPager(byte address, struct Pager *pager) {
25 | EEPROM.get(address*sizeof(Pager), *pager);
26 | }
27 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # You can control the set of applied configuration files using the
3 | # proguardFiles setting in build.gradle.
4 | #
5 | # For more details, see
6 | # http://developer.android.com/guide/developing/tools/proguard.html
7 |
8 | # If your project uses WebView with JS, uncomment the following
9 | # and specify the fully qualified class name to the JavaScript interface
10 | # class:
11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12 | # public *;
13 | #}
14 |
15 | # Uncomment this to preserve the line number information for
16 | # debugging stack traces.
17 | #-keepattributes SourceFile,LineNumberTable
18 |
19 | # If you keep the line number information, uncomment this to
20 | # hide the original source file name.
21 | #-renamesourcefileattribute SourceFile
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/Storage.h:
--------------------------------------------------------------------------------
1 | #ifndef _STORAGE_H
2 | #define _STORAGE_H
3 |
4 | #include
5 | #include "Arduino.h"
6 |
7 | #define PAGER_SIZE 161
8 | #define STORAGE_COUNT 20
9 |
10 | const byte CRC[2] = {0x45, 0x99};
11 |
12 | typedef struct Pager {
13 | byte addr: 8; // Address in EEPROM
14 | char alias[10]; // Readable name
15 | uint32_t cap : 24; // CAP code
16 | uint32_t frequency : 20; // Frequency
17 | byte msgSource: 2; // Message source (0-3)
18 | byte enconding: 2; // Text enconding
19 | byte inversion : 1; // Bit inversion
20 | word rate: 12; // Bautrate (512, 1200, 2400)
21 | byte crc[2]; // Index bytes for detecting
22 | };
23 |
24 |
25 | void clearEE();
26 | bool addPager(Pager *pager, bool toDel);
27 | void getPager(byte address, struct Pager *pager) ;
28 | Pager* getPagers();
29 |
30 | #endif
31 |
--------------------------------------------------------------------------------
/TelePager-bot/.idea/jarRepositories.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/values/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/values-night/themes.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
16 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/androidTest/java/ru/example/notificationstopager/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package ru.example.notificationstopager;
2 |
3 | import android.content.Context;
4 |
5 | import androidx.test.platform.app.InstrumentationRegistry;
6 | import androidx.test.ext.junit.runners.AndroidJUnit4;
7 |
8 | import org.junit.Test;
9 | import org.junit.runner.RunWith;
10 |
11 | import static org.junit.Assert.*;
12 |
13 | /**
14 | * Instrumented test, which will execute on an Android device.
15 | *
16 | * @see Testing documentation
17 | */
18 | @RunWith(AndroidJUnit4.class)
19 | public class ExampleInstrumentedTest {
20 | @Test
21 | public void useAppContext() {
22 | // Context of the app under test.
23 | Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
24 | assertEquals("ru.example.notificationstopager", appContext.getPackageName());
25 | }
26 | }
--------------------------------------------------------------------------------
/NotificationsToPager-android/gradle.properties:
--------------------------------------------------------------------------------
1 | # Project-wide Gradle settings.
2 | # IDE (e.g. Android Studio) users:
3 | # Gradle settings configured through the IDE *will override*
4 | # any settings specified in this file.
5 | # For more details on how to configure your build environment visit
6 | # http://www.gradle.org/docs/current/userguide/build_environment.html
7 | # Specifies the JVM arguments used for the daemon process.
8 | # The setting is particularly useful for tweaking memory settings.
9 | org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
10 | # When configured, Gradle will run in incubating parallel mode.
11 | # This option should only be used with decoupled projects. More details, visit
12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
13 | # org.gradle.parallel=true
14 | # AndroidX package structure to make it clearer which packages are bundled with the
15 | # Android operating system, and which are packaged with your app"s APK
16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn
17 | android.useAndroidX=true
18 | # Automatically convert third-party libraries to use AndroidX
19 | android.enableJetifier=true
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id 'com.android.application'
3 | }
4 | apply plugin: 'kotlin-android'
5 |
6 | android {
7 | compileSdk 31
8 |
9 | defaultConfig {
10 | applicationId "ru.example.notificationstopager"
11 | minSdk 21
12 | targetSdk 31
13 | versionCode 1
14 | versionName "1.0"
15 |
16 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
17 | }
18 |
19 | buildTypes {
20 | release {
21 | minifyEnabled false
22 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
23 | }
24 | }
25 | compileOptions {
26 | sourceCompatibility JavaVersion.VERSION_1_8
27 | targetCompatibility JavaVersion.VERSION_1_8
28 | }
29 |
30 | buildFeatures {
31 | viewBinding = true
32 | }
33 | }
34 |
35 | dependencies {
36 |
37 | implementation 'androidx.appcompat:appcompat:1.4.1'
38 | implementation 'com.google.android.material:material:1.5.0'
39 | implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
40 | testImplementation 'junit:junit:4.+'
41 | androidTestImplementation 'androidx.test.ext:junit:1.1.3'
42 | androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
43 | implementation "androidx.core:core-ktx:+"
44 | implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
45 |
46 | implementation 'me.aflak.libraries:bluetooth:1.3.9'
47 | }
48 |
--------------------------------------------------------------------------------
/TelePager-bot/src/main/java/Main.java:
--------------------------------------------------------------------------------
1 | import org.telegram.telegrambots.meta.TelegramBotsApi;
2 | import org.telegram.telegrambots.meta.api.objects.Update;
3 | import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
4 | import org.telegram.telegrambots.updatesreceivers.DefaultBotSession;
5 |
6 | public class Main {
7 | static String chatId;
8 |
9 |
10 | public static void main(String[] args) {
11 | PagerBot bot = new PagerBot();
12 | Serial serial = new Serial("COM4", 9600);
13 |
14 | bot.setEventListener(new PagerBot.BotReceive() {
15 | @Override
16 | public void onNewEvent(Update update) {
17 | chatId = update.getMessage().getChatId().toString();
18 | if (update.hasMessage() && update.getMessage().hasText()) {
19 | serial.sendMessage(update.getMessage().getText());
20 | }
21 | }
22 | });
23 |
24 | try {
25 | TelegramBotsApi botsApi = new TelegramBotsApi(DefaultBotSession.class);
26 | botsApi.registerBot(bot);
27 | } catch (TelegramApiException e) {
28 | e.printStackTrace();
29 | }
30 |
31 |
32 | serial.setPortListener(new Serial.SerialPortEvent() {
33 | @Override
34 | public void onReceive(String msg) {
35 | if (chatId != null && msg.contains("Message"))
36 | bot.sendMessage(chatId, "Message sent...");
37 | }
38 | });
39 |
40 | if (serial.connect()) {
41 | System.out.println("Port opened");
42 | }
43 | }
44 |
45 |
46 | }
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
18 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
15 |
18 |
21 |
22 |
23 |
24 |
30 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/java/ru/example/notificationstopager/NotificationService.kt:
--------------------------------------------------------------------------------
1 | package ru.example.notificationstopager
2 |
3 | import android.content.Context
4 | import android.content.Intent
5 | import android.service.notification.NotificationListenerService
6 | import android.service.notification.StatusBarNotification
7 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
8 |
9 |
10 | class NotificationService : NotificationListenerService() {
11 | var context: Context? = null
12 | var title: String = ""
13 | var text: String = ""
14 |
15 | override fun onCreate() {
16 | super.onCreate()
17 | context = applicationContext
18 | }
19 |
20 | override fun onListenerConnected() {
21 | super.onListenerConnected()
22 | for (noti in getActiveNotifications()){
23 | onNotificationPosted(noti)
24 | }
25 | }
26 |
27 | override fun onNotificationPosted(sbn: StatusBarNotification) {
28 | title = ""
29 | text = ""
30 | val pack = sbn.packageName
31 | var ticker = ""
32 | if (sbn.notification.tickerText != null) {
33 | ticker = sbn.notification.tickerText.toString()
34 | }
35 |
36 | title = sbn.notification.extras?.getString("android.title") ?: ""
37 | text = sbn.notification.extras?.getString("android.text") ?: ""
38 |
39 | if(title.isEmpty() && text.isEmpty())
40 | return
41 |
42 | val msgrcv = Intent("Msg")
43 | with(msgrcv) {
44 | putExtra("package", pack)
45 | putExtra("ticker", ticker)
46 | putExtra("title", title)
47 | putExtra("text", text)
48 | }
49 |
50 |
51 | LocalBroadcastManager.getInstance(context!!).sendBroadcast(msgrcv)
52 | }
53 |
54 | override fun onNotificationRemoved(sbn: StatusBarNotification) {
55 |
56 | }
57 |
58 | }
--------------------------------------------------------------------------------
/TelePager-bot/src/main/java/PagerBot.java:
--------------------------------------------------------------------------------
1 | import org.telegram.telegrambots.bots.TelegramLongPollingBot;
2 | import org.telegram.telegrambots.meta.api.methods.send.SendMessage;
3 | import org.telegram.telegrambots.meta.api.objects.Update;
4 | import org.telegram.telegrambots.meta.exceptions.TelegramApiException;
5 |
6 | public class PagerBot extends TelegramLongPollingBot {
7 |
8 | public interface BotReceive {
9 | void onNewEvent(Update update);
10 | }
11 |
12 | BotReceive eventListener;
13 |
14 | public void setEventListener(BotReceive eventListener) {
15 | this.eventListener = eventListener;
16 | }
17 |
18 | @Override
19 | public void onUpdateReceived(Update update) {
20 | if (eventListener != null)
21 | eventListener.onNewEvent(update);
22 | // We check if the update has a message and the message has text
23 | if (update.hasMessage() && update.getMessage().hasText()) {
24 | SendMessage message = new SendMessage(); // Create a SendMessage object with mandatory fields
25 | message.setChatId(update.getMessage().getChatId().toString());
26 | message.setText(update.getMessage().getText());
27 |
28 | System.out.println(update.getMessage().getText());
29 | }
30 |
31 |
32 | }
33 |
34 | public void sendMessage(String chatId, String msg){
35 | try {
36 | SendMessage message = new SendMessage(); // Create a SendMessage object with mandatory fields
37 | message.setChatId(chatId);
38 | message.setText(msg);
39 | execute(message);
40 | } catch (TelegramApiException e) {
41 | e.printStackTrace();
42 | }
43 | }
44 |
45 | @Override
46 | public String getBotUsername() {
47 | return "Your Bot Name";
48 | }
49 |
50 | @Override
51 | public String getBotToken() {
52 | return "Paste your token";
53 | }
54 | }
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/Cmd.h:
--------------------------------------------------------------------------------
1 | /*******************************************************************
2 | Copyright (C) 2009 FreakLabs
3 | All rights reserved.
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met:
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | 3. Neither the name of the the copyright holder nor the names of its contributors
13 | may be used to endorse or promote products derived from this software
14 | without specific prior written permission.
15 | THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 | SUCH DAMAGE.
26 | Originally written by Christopher Wang aka Akiba.
27 | Please post support questions to the FreakLabs forum.
28 | *******************************************************************/
29 | /*!
30 | \file
31 | \ingroup
32 | */
33 | /**************************************************************************/
34 | #ifndef CMD_H
35 | #define CMD_H
36 |
37 | #define MAX_MSG_SIZE 120
38 | #include
39 |
40 | // command line structure
41 | typedef struct _cmd_t
42 | {
43 | char *cmd;
44 | void (*func)(int argc, char **argv);
45 | struct _cmd_t *next;
46 | } cmd_t;
47 |
48 | void cmdInit(uint32_t speed);
49 | void cmdPoll();
50 | void clearCmd();
51 | void pauseCmd(byte pause);
52 | void cmdAdd(char *name, void (*func)(int argc, char **argv));
53 | uint32_t cmdStr2Num(char *str, uint8_t base);
54 |
55 | #endif //CMD_H
56 |
--------------------------------------------------------------------------------
/TelePager-bot/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
21 |
22 |
32 |
33 |
41 |
42 |
50 |
51 |
59 |
60 |
68 |
69 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/java/ru/example/notificationstopager/Translit.java:
--------------------------------------------------------------------------------
1 | package ru.example.notificationstopager;
2 |
3 | public class Translit {
4 | public static String cyr2lat(char ch){
5 | switch (ch){
6 | case 'А': return "A";
7 | case 'Б': return "B";
8 | case 'В': return "V";
9 | case 'Г': return "G";
10 | case 'Д': return "D";
11 | case 'Е': return "E";
12 | case 'Ё': return "JE";
13 | case 'Ж': return "ZH";
14 | case 'З': return "Z";
15 | case 'И': return "I";
16 | case 'Й': return "Y";
17 | case 'К': return "K";
18 | case 'Л': return "L";
19 | case 'М': return "M";
20 | case 'Н': return "N";
21 | case 'О': return "O";
22 | case 'П': return "P";
23 | case 'Р': return "R";
24 | case 'С': return "S";
25 | case 'Т': return "T";
26 | case 'У': return "U";
27 | case 'Ф': return "F";
28 | case 'Х': return "KH";
29 | case 'Ц': return "C";
30 | case 'Ч': return "CH";
31 | case 'Ш': return "SH";
32 | case 'Щ': return "JSH";
33 | case 'Ъ': return "HH";
34 | case 'Ы': return "IH";
35 | case 'Ь': return "JH";
36 | case 'Э': return "EH";
37 | case 'Ю': return "JU";
38 | case 'Я': return "JA";
39 |
40 | case 'а': return "a";
41 | case 'б': return "b";
42 | case 'в': return "v";
43 | case 'г': return "g";
44 | case 'д': return "d";
45 | case 'е': return "e";
46 | case 'ё': return "je";
47 | case 'ж': return "zh";
48 | case 'з': return "z";
49 | case 'и': return "i";
50 | case 'й': return "y";
51 | case 'к': return "k";
52 | case 'л': return "l";
53 | case 'м': return "m";
54 | case 'н': return "n";
55 | case 'о': return "o";
56 | case 'п': return "p";
57 | case 'р': return "r";
58 | case 'с': return "s";
59 | case 'т': return "t";
60 | case 'у': return "u";
61 | case 'ф': return "f";
62 | case 'х': return "kh";
63 | case 'ц': return "c";
64 | case 'ч': return "ch";
65 | case 'ш': return "sh";
66 | case 'щ': return "jsh";
67 | case 'ъ': return "hh";
68 | case 'ы': return "ih";
69 | case 'ь': return "jh";
70 | case 'э': return "eh";
71 | case 'ю': return "ju";
72 | case 'я': return "ja";
73 | default: return String.valueOf(ch);
74 | }
75 | }
76 |
77 | public static String cyr2lat(String s){
78 | StringBuilder sb = new StringBuilder(s.length()*2);
79 | for(char ch: s.toCharArray()){
80 | sb.append(cyr2lat(ch));
81 | }
82 | return sb.toString();
83 | }
84 | }
--------------------------------------------------------------------------------
/TelePager-bot/src/main/java/Serial.java:
--------------------------------------------------------------------------------
1 | import com.fazecast.jSerialComm.SerialPort;
2 | import com.fazecast.jSerialComm.SerialPortDataListener;
3 |
4 | import java.io.InputStream;
5 | import java.nio.charset.StandardCharsets;
6 |
7 | import static com.fazecast.jSerialComm.SerialPort.TIMEOUT_READ_BLOCKING;
8 |
9 | public class Serial {
10 | public interface SerialPortEvent {
11 | void onReceive(String msg);
12 | }
13 |
14 | private String port;
15 | private int rate;
16 | private SerialPort serialPort;
17 | private SerialPortEvent portListener;
18 |
19 | public Serial(String port, int rate) {
20 | this.port = port;
21 | this.rate = rate;
22 | }
23 |
24 | public void setPortListener(SerialPortEvent portListener) {
25 | this.portListener = portListener;
26 | }
27 |
28 | public boolean connect() {
29 | if (port.toLowerCase().split("com").length < 2) {
30 | System.out.println(port + " is really correct?");
31 | return false;
32 | }
33 | SerialPort[] avPorts = SerialPort.getCommPorts();
34 | for (SerialPort avPort : avPorts) {
35 | if (avPort.getSystemPortPath().toLowerCase().contains(port.toLowerCase())) {
36 | serialPort = avPort;
37 | serialPort.setComPortTimeouts(TIMEOUT_READ_BLOCKING, 15000, 5000);
38 | break;
39 | }
40 | }
41 | if (serialPort == null) {
42 | System.out.println("Port NULL");
43 | return false;
44 | }
45 | if (serialPort.isOpen()) {
46 | System.out.println("Port is busy");
47 | return false;
48 | }
49 | serialPort.setBaudRate(rate);
50 | serialPort.openPort();
51 | serialPort.addDataListener(new SerialPortDataListener() {
52 | @Override
53 | public int getListeningEvents() {
54 | return 3;
55 | }
56 |
57 | @Override
58 | public void serialEvent(com.fazecast.jSerialComm.SerialPortEvent event) {
59 | switch (event.getEventType()) {
60 | case SerialPort.LISTENING_EVENT_DATA_AVAILABLE: {
61 | StringBuilder msg = new StringBuilder();
62 | InputStream in = serialPort.getInputStream();
63 | try {
64 | for (int j = 0; j < in.available(); ++j)
65 | msg.append((char) in.read());
66 | System.out.print(msg);
67 | if (portListener != null)
68 | portListener.onReceive(msg.toString());
69 | in.close();
70 | } catch (Exception e) {
71 | e.printStackTrace();
72 | }
73 | break;
74 | }
75 |
76 | case SerialPort.LISTENING_EVENT_DATA_WRITTEN: {
77 | break;
78 | }
79 | }
80 | }
81 | });
82 |
83 |
84 | return serialPort.isOpen();
85 | }
86 |
87 | public boolean sendMessage(String msg) {
88 | if (!serialPort.isOpen()) {
89 | System.out.println("Port is closed");
90 | return false;
91 | }
92 | if (msg == null || msg.isEmpty()) {
93 | System.out.println("Empty message");
94 | return false;
95 | }
96 | msg = msg + "\r";
97 | byte[] buf = msg.getBytes(StandardCharsets.UTF_8);
98 | serialPort.writeBytes(msg.getBytes(StandardCharsets.UTF_8), buf.length);
99 | return true;
100 | }
101 |
102 | }
103 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/Rf7021.h:
--------------------------------------------------------------------------------
1 | /*
2 | Simple library for using the RF7021SE (ADF7021) module to transfer binary data
3 |
4 | RF7021SE module pinout:
5 |
6 | | VCC | PAC (not used) |
7 | | CE | SLE |
8 | | SDATA | SREAD |
9 | | NC (not used) | SCLK |
10 | | TxRxData | SWD (not used) |
11 | | MUX (not used) | TxRxCLK |
12 | | GND | GND |
13 |
14 | Copyright (c) 2021, SinuX. All rights reserved.
15 |
16 | This library is distributed "as is" without any warranty.
17 | See MIT License for more details.
18 | */
19 |
20 | #ifndef _RF7021_H_
21 | #define _RF7021_H_
22 |
23 | #include "Arduino.h"
24 |
25 | class Rf7021 {
26 |
27 | public:
28 | Rf7021();
29 |
30 | // Wiring
31 | void setTxRxDataPin(byte txRxDataPin);
32 | void setTxRxCLKPin(byte txRxCLKPin);
33 | void setCEPin(byte cePin);
34 | void setSREADPin(byte sreadPin);
35 | void setSLEPin(byte slePin);
36 | void setSDATAPin(byte sdataPin);
37 | void setSCLKPin(byte sclkPin);
38 |
39 | // Readback
40 | word getSiliconRev();
41 | float getTemp();
42 | float getVoltage();
43 |
44 | // Setup
45 | void setXtalFrequency(uint32_t xtalFrequency);
46 | uint32_t getXtalFrequency();
47 | void setXtalBias(byte xtalBias);
48 | void setCpCurrent(byte cpCurrent);
49 | void setHasExternalInductor(byte hasExternalInductor);
50 | void setmModulationScheme(byte modulationScheme);
51 | void setPowerAmplifierEnabled(byte powerAmplifierEnabled);
52 | void setPowerAmplifierRamping(byte powerAmplifierRamping);
53 | void setPowerAmplifierBias(byte powerAmplifierBias);
54 | void setPowerAmplifierPower(byte powerAmplifierPower);
55 | void setDataInvertType(byte dataInvertType);
56 | void setRCosineAlpha(byte rCosineAlpha);
57 | void setDataRate(word dataRate);
58 | void setFrequency(uint32_t frequency);
59 | uint32_t getFrequency();
60 | void setFrequencyDeviation(word frequencyDev);
61 | void setDataInvertEnabled(byte dataInvertEnabled);
62 |
63 | // Transmission
64 | void txTest(byte testMode, word duration);
65 | bool sendMessage(byte *message, word messageLength);
66 |
67 | private:
68 | typedef union {
69 | uint32_t data;
70 | word dataLower;
71 | word dataUpper;
72 | byte dataBytes[4];
73 | } RfReg;
74 |
75 | typedef struct {
76 | // Wiring
77 | byte txRxDataPin, txRxCLKPin;
78 | byte cePin, sreadPin, slePin, sdataPin, sclkPin;
79 |
80 | // Core settings
81 | uint32_t xtalFrequency;
82 | byte xtalBias;
83 | byte cpCurrent;
84 | byte hasExternalInductor;
85 |
86 | // Transmission settings
87 | byte modulationScheme;
88 | byte powerAmplifierEnabled;
89 | byte powerAmplifierRamping;
90 | byte powerAmplifierBias;
91 | byte powerAmplifierPower;
92 | byte dataInvertType;
93 | byte rCosineAlpha;
94 | word dataRate;
95 | uint32_t frequency;
96 | word frequencyDeviation;
97 | byte dataInvertEnabled;
98 |
99 | union {
100 | RfReg r0;
101 | struct {
102 | byte addressBits : 4;
103 | word fractionalN : 15;
104 | word integerN : 8;
105 | byte rxMode : 1;
106 | byte uartMode : 1;
107 | byte muxOut : 3;
108 | } R0;
109 | };
110 | union {
111 | RfReg r1;
112 | struct {
113 | byte addressBits : 4;
114 | byte rCounter : 3;
115 | byte clockoutDivide : 4;
116 | byte xtalDoubler : 1;
117 | byte xoscEnable : 1;
118 | byte xtalBias : 2;
119 | byte cpCurrent : 2;
120 | byte vcoEnable : 1;
121 | byte rfDivideBy2 : 1;
122 | byte vcoBias : 4;
123 | byte vcoAdjust : 2;
124 | byte vcoInductor : 1;
125 | } R1;
126 | };
127 | union {
128 | RfReg r2;
129 | struct {
130 | byte addressBits : 4;
131 | byte modulationScheme : 3;
132 | byte paEnable : 1;
133 | byte paRamp : 3;
134 | byte paBias : 2;
135 | byte powerAmplifier : 6;
136 | word txFrequencyDeviation : 9;
137 | byte txDataInvert : 2;
138 | byte rcosineAlpha : 1;
139 | } R2;
140 | };
141 | union {
142 | RfReg r3;
143 | struct {
144 | byte addressBits : 4;
145 | byte bbosClkDivide: 2;
146 | byte demClkDivide : 4;
147 | byte cdrClkDivide : 8;
148 | byte seqClkDivide : 8;
149 | byte agcClkDivide : 6;
150 | } R3;
151 | };
152 | union {
153 | RfReg r15;
154 | struct {
155 | byte addressBits : 4;
156 | byte rxTestMode : 4;
157 | byte txTestMode : 3;
158 | byte sdTestMode : 3;
159 | byte cpTestMode : 3;
160 | byte clkMux : 3;
161 | byte pllTestMode : 4;
162 | byte analogTestMode : 4;
163 | byte forceLdHigh : 1;
164 | byte reg1Pd : 1;
165 | byte calOverride : 2;
166 | } R15;
167 | };
168 | } RfConfig;
169 |
170 | RfConfig rfConfig;
171 |
172 | void writeReg(RfReg *reg);
173 | RfReg readReg(word readbackConfig);
174 |
175 | void powerOn();
176 | void powerOff();
177 | };
178 |
179 |
180 | #endif /* _RF7021_H_ */
181 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/res/drawable/ic_launcher_background.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
55 |
60 |
65 |
70 |
75 |
80 |
85 |
90 |
95 |
100 |
105 |
110 |
115 |
120 |
125 |
130 |
135 |
140 |
145 |
150 |
155 |
160 |
165 |
170 |
171 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/app/src/main/java/ru/example/notificationstopager/MainActivity.kt:
--------------------------------------------------------------------------------
1 | package ru.example.notificationstopager
2 |
3 | import android.Manifest
4 | import android.Manifest.permission.BLUETOOTH_CONNECT
5 | import android.app.NotificationChannel
6 | import android.app.NotificationManager
7 | import android.bluetooth.BluetoothDevice
8 | import android.content.*
9 | import android.content.pm.PackageManager
10 | import android.os.Build
11 | import android.os.Bundle
12 | import android.os.Handler
13 | import android.os.Looper
14 | import android.util.Log
15 | import androidx.appcompat.app.AppCompatActivity
16 | import androidx.core.app.ActivityCompat
17 | import androidx.core.app.NotificationCompat
18 | import androidx.core.app.NotificationManagerCompat
19 | import androidx.localbroadcastmanager.content.LocalBroadcastManager
20 | import me.aflak.bluetooth.Bluetooth
21 | import me.aflak.bluetooth.interfaces.DeviceCallback
22 | import ru.example.notificationstopager.databinding.ActivityMainBinding
23 | import java.net.URLEncoder
24 | import java.nio.charset.Charset
25 | import java.nio.charset.StandardCharsets
26 | import java.util.*
27 |
28 | class MainActivity : AppCompatActivity() {
29 | lateinit var binding: ActivityMainBinding;
30 |
31 | var capV: Long = 0
32 | var freqV: Long = 0
33 | var invV: Boolean = false
34 | lateinit var prefs: SharedPreferences
35 |
36 | //val MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB") //для HC-05, на HC-06/04 возможно другой UUID
37 | val bluetooth = Bluetooth(this);
38 |
39 |
40 | override fun onCreate(savedInstanceState: Bundle?) {
41 | super.onCreate(savedInstanceState)
42 | binding = ActivityMainBinding.inflate(layoutInflater)
43 | setContentView(binding.root)
44 | prefs = getSharedPreferences("prefs", MODE_PRIVATE)
45 |
46 | capV = prefs.getLong("cap", 0)
47 | freqV = prefs.getLong("freq", 0)
48 | invV = prefs.getBoolean("inv", false)
49 | with(binding) {
50 |
51 | cap.setText(if (capV > 0) capV.toString() else "")
52 | freq.setText(if (freqV > 0) freqV.toString() else "")
53 | inv.isChecked = invV
54 | }
55 |
56 | binding.save.setOnClickListener {
57 | with(prefs.edit()) {
58 | putLong("cap", binding.cap.text.toString().toLong()).apply()
59 | putLong("freq", binding.freq.text.toString().toLong()).apply()
60 | putBoolean("inv", binding.inv.isChecked).apply()
61 | }
62 | }
63 |
64 | binding.chPerm.setOnClickListener {
65 | reqPermissions()
66 | }
67 |
68 | binding.testNotif.setOnClickListener {
69 | createNotif()
70 | }
71 |
72 | LocalBroadcastManager.getInstance(this).registerReceiver(onNotice, IntentFilter("Msg"));
73 |
74 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
75 | if (checkSelfPermission(Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED) {
76 |
77 | }
78 | }
79 | btInit()
80 | // startService(Intent(this,NotificationService::class.java))
81 | }
82 |
83 | fun btInit() {
84 | bluetooth.onStart();
85 | bluetooth.setDeviceCallback(object : DeviceCallback {
86 | override fun onDeviceConnected(device: BluetoothDevice?) {
87 |
88 | }
89 |
90 | override fun onDeviceDisconnected(device: BluetoothDevice?, message: String?) {
91 |
92 | }
93 |
94 | override fun onMessage(message: ByteArray?) {
95 |
96 | }
97 |
98 | override fun onError(errorCode: Int) {
99 |
100 | }
101 |
102 | override fun onConnectError(device: BluetoothDevice?, message: String?) {
103 |
104 | }
105 | })
106 |
107 | bluetooth.connectToName("BT Super");
108 |
109 | }
110 |
111 | fun sendToBt(msg: String) {
112 |
113 | if (bluetooth.isConnected)
114 | bluetooth.send(msg, StandardCharsets.UTF_8)
115 | }
116 |
117 | fun createNotif() {
118 | var builder = NotificationCompat.Builder(this, "sdfsdf")
119 | .setSmallIcon(R.drawable.ic_launcher_foreground)
120 | .setContentTitle("Важное событие")
121 | .setContentText("Тестируем пейджер...")
122 | .setPriority(NotificationCompat.PRIORITY_HIGH)
123 |
124 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
125 | val name = "Notifi"
126 | val descriptionText = "Some text"
127 | val importance = NotificationManager.IMPORTANCE_DEFAULT
128 | val channel = NotificationChannel("sdfsdf", name, importance).apply {
129 | description = descriptionText
130 | }
131 | // Register the channel with the system
132 | val notificationManager: NotificationManager =
133 | getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
134 | notificationManager.createNotificationChannel(channel)
135 | }
136 |
137 | with(NotificationManagerCompat.from(this)) {
138 | // notificationId is a unique int for each notification that you must define
139 | notify(123, builder.build())
140 | }
141 | }
142 |
143 |
144 | private fun reqPermissions(): Boolean {
145 | startActivity(Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"))
146 |
147 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
148 | ActivityCompat.requestPermissions(
149 | this, listOf(
150 | Manifest.permission.BLUETOOTH_SCAN,
151 | BLUETOOTH_CONNECT
152 | ).toTypedArray(), 100
153 | )
154 | }
155 |
156 |
157 | return false
158 | }
159 |
160 | private val onNotice: BroadcastReceiver = object : BroadcastReceiver() {
161 | override fun onReceive(context: Context, intent: Intent) {
162 |
163 | // val title = Translit.cyr2lat(intent.getStringExtra("title"))
164 | // val text = Translit.cyr2lat(intent.getStringExtra("text"))
165 | val title = intent.getStringExtra("title")
166 | val text = intent.getStringExtra("text")
167 | Log.e("messg", title.plus(", ").plus(text))
168 | sendToBt("send f $freqV c $capV e 1 i ${if (invV) 1 else 0} m $title: $text\r")
169 |
170 |
171 | }
172 | }
173 | }
--------------------------------------------------------------------------------
/TelePager-bot/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MSYS* | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/NotificationsToPager-android/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | #
4 | # Copyright 2015 the original author or authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | ##
21 | ## Gradle start up script for UN*X
22 | ##
23 | ##############################################################################
24 |
25 | # Attempt to set APP_HOME
26 | # Resolve links: $0 may be a link
27 | PRG="$0"
28 | # Need this for relative symlinks.
29 | while [ -h "$PRG" ] ; do
30 | ls=`ls -ld "$PRG"`
31 | link=`expr "$ls" : '.*-> \(.*\)$'`
32 | if expr "$link" : '/.*' > /dev/null; then
33 | PRG="$link"
34 | else
35 | PRG=`dirname "$PRG"`"/$link"
36 | fi
37 | done
38 | SAVED="`pwd`"
39 | cd "`dirname \"$PRG\"`/" >/dev/null
40 | APP_HOME="`pwd -P`"
41 | cd "$SAVED" >/dev/null
42 |
43 | APP_NAME="Gradle"
44 | APP_BASE_NAME=`basename "$0"`
45 |
46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
48 |
49 | # Use the maximum available, or set MAX_FD != -1 to use that value.
50 | MAX_FD="maximum"
51 |
52 | warn () {
53 | echo "$*"
54 | }
55 |
56 | die () {
57 | echo
58 | echo "$*"
59 | echo
60 | exit 1
61 | }
62 |
63 | # OS specific support (must be 'true' or 'false').
64 | cygwin=false
65 | msys=false
66 | darwin=false
67 | nonstop=false
68 | case "`uname`" in
69 | CYGWIN* )
70 | cygwin=true
71 | ;;
72 | Darwin* )
73 | darwin=true
74 | ;;
75 | MINGW* )
76 | msys=true
77 | ;;
78 | NONSTOP* )
79 | nonstop=true
80 | ;;
81 | esac
82 |
83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
84 |
85 |
86 | # Determine the Java command to use to start the JVM.
87 | if [ -n "$JAVA_HOME" ] ; then
88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
89 | # IBM's JDK on AIX uses strange locations for the executables
90 | JAVACMD="$JAVA_HOME/jre/sh/java"
91 | else
92 | JAVACMD="$JAVA_HOME/bin/java"
93 | fi
94 | if [ ! -x "$JAVACMD" ] ; then
95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
96 |
97 | Please set the JAVA_HOME variable in your environment to match the
98 | location of your Java installation."
99 | fi
100 | else
101 | JAVACMD="java"
102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
103 |
104 | Please set the JAVA_HOME variable in your environment to match the
105 | location of your Java installation."
106 | fi
107 |
108 | # Increase the maximum file descriptors if we can.
109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
110 | MAX_FD_LIMIT=`ulimit -H -n`
111 | if [ $? -eq 0 ] ; then
112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
113 | MAX_FD="$MAX_FD_LIMIT"
114 | fi
115 | ulimit -n $MAX_FD
116 | if [ $? -ne 0 ] ; then
117 | warn "Could not set maximum file descriptor limit: $MAX_FD"
118 | fi
119 | else
120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
121 | fi
122 | fi
123 |
124 | # For Darwin, add options to specify how the application appears in the dock
125 | if $darwin; then
126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
127 | fi
128 |
129 | # For Cygwin or MSYS, switch paths to Windows format before running java
130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
133 |
134 | JAVACMD=`cygpath --unix "$JAVACMD"`
135 |
136 | # We build the pattern for arguments to be converted via cygpath
137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
138 | SEP=""
139 | for dir in $ROOTDIRSRAW ; do
140 | ROOTDIRS="$ROOTDIRS$SEP$dir"
141 | SEP="|"
142 | done
143 | OURCYGPATTERN="(^($ROOTDIRS))"
144 | # Add a user-defined pattern to the cygpath arguments
145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
147 | fi
148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
149 | i=0
150 | for arg in "$@" ; do
151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
153 |
154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
156 | else
157 | eval `echo args$i`="\"$arg\""
158 | fi
159 | i=`expr $i + 1`
160 | done
161 | case $i in
162 | 0) set -- ;;
163 | 1) set -- "$args0" ;;
164 | 2) set -- "$args0" "$args1" ;;
165 | 3) set -- "$args0" "$args1" "$args2" ;;
166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
172 | esac
173 | fi
174 |
175 | # Escape application args
176 | save () {
177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
178 | echo " "
179 | }
180 | APP_ARGS=`save "$@"`
181 |
182 | # Collect all arguments for the java command, following the shell quoting and substitution rules
183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
184 |
185 | exec "$JAVACMD" "$@"
186 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/PocsagEncoder.h:
--------------------------------------------------------------------------------
1 | /*
2 | * Simple yet fully functional POCSAG encoder implementation capable
3 | * of generating any kind of message (tone, numeric or alphanumeric)
4 | *
5 | * Alphanumeric messages can be encoded using one of 4 encodings
6 | *
7 | * Copyright (c) 2021, SinuX. All rights reserved.
8 | *
9 | * This library is distributed "as is" without any warranty.
10 | * See MIT License for more details.
11 | */
12 |
13 | #ifndef _POCSAGENCODER_H_
14 | #define _POCSAGENCODER_H_
15 |
16 | #define PCSG_PREAMBLE_LENGTH 80 // Preamble length in bytes (must be >= 72)
17 | #define PCSG_BATCHES_COUNT 5 // Batches count (5 batches can handle 185 to 225 alphanumeric symbols)
18 | #define PCSG_MESSAGE_LENGTH PCSG_PREAMBLE_LENGTH + 68 * PCSG_BATCHES_COUNT // Max message length in bytes including preamble and all batches
19 | #define PCSG_EOT_CHAR 0x04 // Alphanumeric message text termination character code
20 |
21 | #include "Arduino.h"
22 |
23 | class PocsagEncoder {
24 |
25 | public:
26 | PocsagEncoder();
27 |
28 | void setCapCode(uint32_t capCode);
29 | void setSource(byte source);
30 | void setEncodingId(byte encodingId);
31 | void setPrintMessage(byte printMessage);
32 |
33 | typedef union {
34 | struct {
35 | byte parityBits : 1;
36 | word crcBits : 10;
37 | uint32_t payloadBits : 20; // 18 address + 2 source bits or 20 message bits
38 | byte messageType : 1;
39 | };
40 | uint32_t data;
41 | } PocsagCW;
42 |
43 | typedef struct {
44 | PocsagCW codeWords[2];
45 | } PocsagFrame;
46 |
47 | typedef struct {
48 | uint32_t fsc;
49 | PocsagFrame frames[8];
50 | } PocsagBatch;
51 |
52 | typedef struct {
53 | word messageLength;
54 | union {
55 | struct {
56 | byte preamble[PCSG_PREAMBLE_LENGTH];
57 | PocsagBatch batches[PCSG_BATCHES_COUNT];
58 | };
59 | byte dataBytes[PCSG_MESSAGE_LENGTH];
60 | };
61 | } PocsagMessage;
62 |
63 | PocsagMessage encodeNumeric(String messageText);
64 | PocsagMessage encodeAlphanumeric(String messageText);
65 | PocsagMessage encodeTone();
66 |
67 | private:
68 | uint32_t capCode;
69 | byte source;
70 | byte encodingId;
71 | byte printMessage;
72 |
73 | byte getPocsagNumericCharacter(byte asciiChar);
74 | byte getPocsagAlphanumericCharacter(word utf8Char, byte encodingId);
75 |
76 | struct {
77 | word offset;
78 | byte length;
79 | } PCSG_ENCODINGS[4] = {
80 | {48, 63}, // 0 - Latin (Motorola Advisor)
81 | {111, 75}, // 1 - Latin/Cyrillic (Motorola Advisor Linguist, Scriptor LX2 Linguist, NEC Maxima, Optima, Truly Supervisor)
82 | {186, 65}, // 2 - Latin/Cyrillic (Philips PRG2220, PRG2310)
83 | {251, 67} // 3 - Cyrillic (Motorola Advisor, Scriptor LX1)
84 | };
85 | };
86 |
87 | static const byte PCSG_ALPHABET[318][2] PROGMEM = {
88 | // Numeric
89 | {'0', 0x0}, {'1', 0x1}, {'2', 0x2}, {'3', 0x3}, {'4', 0x4}, {'5', 0x5}, {'6', 0x6}, {'7', 0x7}, {'8', 0x8}, {'9', 0x9}, {'*', 0xA}, {'U', 0xB}, {' ', 0xC}, {'-', 0xD}, {')', 0xE}, {'(', 0xF},
90 |
91 | // Alphanumeric common
92 | {' ', 0x20}, {'!', 0x21}, {'"', 0x22}, {'#', 0x23}, {'$', 0x24}, {'%', 0x25}, {'&', 0x26}, {'\'', 0x27}, {'(', 0x28}, {')', 0x29}, {'*', 0x2A}, {'+', 0x2B}, {',', 0x2C}, {'-', 0x2D}, {'.', 0x2E}, {'/', 0x2F},
93 | {'0', 0x30}, {'1', 0x31}, {'2', 0x32}, {'3', 0x33}, {'4', 0x34}, {'5', 0x35}, {'6', 0x36}, {'7', 0x37}, {'8', 0x38}, {'9', 0x39}, {':', 0x3A}, {';', 0x3B}, {'<', 0x3C}, {'=', 0x3D}, {'>', 0x3E}, {'?', 0x3F},
94 |
95 | // 0 - Alphanumeric Latin (Motorola Advisor)
96 | {'@', 0x40}, {'A', 0x41}, {'B', 0x42}, {'C', 0x43}, {'D', 0x44}, {'E', 0x45}, {'F', 0x46}, {'G', 0x47}, {'H', 0x48}, {'I', 0x49}, {'J', 0x4A}, {'K', 0x4B}, {'L', 0x4C}, {'M', 0x4D}, {'N', 0x4E}, {'O', 0x4F},
97 | {'P', 0x50}, {'Q', 0x51}, {'R', 0x52}, {'S', 0x53}, {'T', 0x54}, {'U', 0x55}, {'V', 0x56}, {'W', 0x57}, {'X', 0x58}, {'Y', 0x59}, {'Z', 0x5A}, {'[', 0x5B}, {'\\', 0x5C}, {']', 0x5D}, {'^', 0x5E}, {'_', 0x5F},
98 | {'`', 0x60}, {'a', 0x61}, {'b', 0x62}, {'c', 0x63}, {'d', 0x64}, {'e', 0x65}, {'f', 0x66}, {'g', 0x67}, {'h', 0x68}, {'i', 0x69}, {'j', 0x6A}, {'k', 0x6B}, {'l', 0x6C}, {'m', 0x6D}, {'n', 0x6E}, {'o', 0x6F},
99 | {'p', 0x70}, {'q', 0x71}, {'r', 0x72}, {'s', 0x73}, {'t', 0x74}, {'u', 0x75}, {'v', 0x76}, {'w', 0x77}, {'x', 0x78}, {'y', 0x79}, {'z', 0x7A}, {'{', 0x7B}, {'|', 0x7C}, {'}', 0x7D}, {'~', 0x7E},
100 |
101 | // 1 - Alphanumeric Latin/Cyrillic (Motorola Advisor Linguist, Scriptor LX2 Linguist, NEC Maxima, Optima, Truly Supervisor)
102 | {'@', 0x40}, {'A', 0x41}, {192, 0x41}, {'B', 0x42}, {194, 0x42}, {'C', 0x43}, {209, 0x43}, {'D', 0x44}, {'E', 0x45}, {197, 0x45}, {'F', 0x46}, {'G', 0x47}, {'H', 0x48}, {205, 0x48}, {'I', 0x49}, {'J', 0x4A}, {'K', 0x4B}, {202, 0x4B}, {'L', 0x4C}, {'M', 0x4D}, {204, 0x4D}, {'N', 0x4E}, {'O', 0x4F}, {206, 0x4F},
103 | {'P', 0x50}, {208, 0x50}, {'Q', 0x51}, {'R', 0x52}, {'S', 0x53}, {'T', 0x54}, {210, 0x54}, {'U', 0x55}, {'V', 0x56}, {'W', 0x57}, {'X', 0x58}, {213, 0x58}, {'Y', 0x59}, {'Z', 0x5A}, {'[', 0x5B}, {'\\', 0x5C}, {']', 0x5D}, {'^', 0x5E}, {'_', 0x5F},
104 | {'`', 0x60}, {193, 0x61}, {195, 0x62}, {129, 0x63}, {131, 0x63}, {196, 0x64}, {168, 0x65}, {198, 0x66}, {199, 0x67}, {200, 0x68}, {201, 0x69}, {203, 0x6A}, {207, 0x6B}, {211, 0x6C}, {212, 0x6D}, {214, 0x6E}, {215, 0x6F},
105 | {216, 0x70}, {217, 0x71}, {218, 0x72}, {219, 0x73}, {220, 0x74}, {221, 0x75}, {222, 0x76}, {223, 0x77}, {142, 0x78}, {170, 0x79}, {175, 0x7A}, {'{', 0x7B}, {'|', 0x7C}, {'}', 0x7D}, {'~', 0x7E},
106 |
107 | // 2 - Alphanumeric Latin/Cyrillic (Philips PRG2220, PRG2310)
108 | {'@', 0x40}, {'A', 0x41}, {'B', 0x42}, {'C', 0x43}, {'D', 0x44}, {'E', 0x45}, {'F', 0x46}, {'G', 0x47}, {'H', 0x48}, {'I', 0x49}, {'J', 0x4A}, {'K', 0x4B}, {'L', 0x4C}, {'M', 0x4D}, {'N', 0x4E}, {'O', 0x4F},
109 | {'P', 0x50}, {'Q', 0x51}, {'R', 0x52}, {'S', 0x53}, {'T', 0x54}, {'U', 0x55}, {'V', 0x56}, {'W', 0x57}, {'X', 0x58}, {'Y', 0x59}, {'Z', 0x5A}, {'[', 0x5B}, {'\\', 0x5C}, {']', 0x5D}, {'^', 0x5E}, {'_', 0x5F},
110 | {192, 0x60}, {193, 0x61}, {194, 0x62}, {195, 0x63}, {196, 0x64}, {197, 0x65}, {168, 0x65}, {198, 0x66}, {199, 0x67}, {200, 0x68}, {201, 0x69}, {202, 0x6A}, {203, 0x6B}, {204, 0x6C}, {205, 0x6D}, {206, 0x6E}, {207, 0x6F},
111 | {208, 0x70}, {209, 0x71}, {210, 0x72}, {211, 0x73}, {212, 0x74}, {213, 0x75}, {214, 0x76}, {215, 0x77}, {216, 0x78}, {217, 0x79}, {218, 0x7A}, {219, 0x7B}, {220, 0x7C}, {221, 0x7D}, {222, 0x7E}, {223, 0x7F},
112 |
113 | // 3 - Alphanumeric Cyrillic (Motorola Advisor, Scriptor LX1)
114 | {254, 0x40}, {224, 0x41}, {225, 0x42}, {246, 0x43}, {228, 0x44}, {229, 0x45}, {184, 0x45}, {244, 0x46}, {227, 0x47}, {245, 0x48}, {232, 0x49}, {233, 0x4A}, {234, 0x4B}, {235, 0x4C}, {236, 0x4D}, {237, 0x4E}, {238, 0x4F},
115 | {239, 0x50}, {255, 0x51}, {240, 0x52}, {241, 0x53}, {242, 0x54}, {243, 0x55}, {230, 0x56}, {226, 0x57}, {250, 0x58}, {252, 0x58}, {251, 0x59}, {231, 0x5A}, {248, 0x5B}, {253, 0x5C}, {249, 0x5D}, {247, 0x5E}, {'_', 0x5F},
116 | {222, 0x60}, {192, 0x61}, {193, 0x62}, {214, 0x63}, {196, 0x64}, {197, 0x65}, {168, 0x65}, {212, 0x66}, {195, 0x67}, {213, 0x68}, {200, 0x69}, {201, 0x6A}, {202, 0x6B}, {203, 0x6C}, {204, 0x6D}, {205, 0x6E}, {206, 0x6F},
117 | {207, 0x70}, {223, 0x71}, {208, 0x72}, {209, 0x73}, {210, 0x74}, {211, 0x75}, {198, 0x76}, {194, 0x77}, {218, 0x78}, {220, 0x78}, {219, 0x79}, {199, 0x7A}, {216, 0x7B}, {221, 0x7C}, {217, 0x7D}, {215, 0x7E}
118 | };
119 |
120 | #endif /* _POCSAGENCODER_H_ */
121 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/Cmd.cpp:
--------------------------------------------------------------------------------
1 | /*******************************************************************
2 | Copyright (C) 2009 FreakLabs
3 | All rights reserved.
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions
6 | are met:
7 | 1. Redistributions of source code must retain the above copyright
8 | notice, this list of conditions and the following disclaimer.
9 | 2. Redistributions in binary form must reproduce the above copyright
10 | notice, this list of conditions and the following disclaimer in the
11 | documentation and/or other materials provided with the distribution.
12 | 3. Neither the name of the the copyright holder nor the names of its contributors
13 | may be used to endorse or promote products derived from this software
14 | without specific prior written permission.
15 | THIS SOFTWARE IS PROVIDED BY THE THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 | ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 | SUCH DAMAGE.
26 | Originally written by Christopher Wang aka Akiba.
27 | Please post support questions to the FreakLabs forum.
28 | *******************************************************************/
29 | /*!
30 | \file Cmd.c
31 | This implements a simple command line interface for the Arduino so that
32 | its possible to execute individual functions within the sketch.
33 | */
34 | /**************************************************************************/
35 | #include
36 | #if ARDUINO >= 100
37 | #include
38 | #else
39 | #include
40 | #endif
41 | #include "HardwareSerial.h"
42 | #include "Cmd.h"
43 |
44 | //#define DEBUG
45 |
46 | // command line message buffer and pointer
47 | static uint8_t msg[MAX_MSG_SIZE];
48 | static uint8_t *msg_ptr;
49 |
50 |
51 | // linked list for command table
52 | static cmd_t *cmd_tbl_list, *cmd_tbl;
53 |
54 | // text strings for command prompt (stored in flash)
55 | const char cmd_banner[] PROGMEM = "*************** CMD *******************";
56 | const char cmd_prompt[] PROGMEM = "CMD >> ";
57 | const char cmd_unrecog[] PROGMEM = "What?";
58 |
59 | byte canRun = 1;
60 | uint32_t speedUart;
61 |
62 | /**************************************************************************/
63 | /*!
64 | Generate the main command prompt
65 | */
66 | /**************************************************************************/
67 | void cmd_display()
68 | {
69 | char buf[50];
70 | // strcpy_P(buf, cmd_banner);
71 | //strcpy_P(buf, cmd_prompt);
72 |
73 | #ifdef DEBUG
74 | Serial.print(buf);
75 | Serial.println();
76 | Serial.println(buf);
77 | #endif
78 | }
79 |
80 | /**************************************************************************/
81 | /*!
82 | Parse the command line. This function tokenizes the command input, then
83 | searches for the command table entry associated with the commmand. Once found,
84 | it will jump to the corresponding function.
85 | */
86 | /**************************************************************************/
87 | void cmd_parse(char *cmd)
88 | {
89 | uint8_t argc, i = 0;
90 | char *argv[30];
91 | char buf[50];
92 | cmd_t *cmd_entry;
93 |
94 | fflush(stdout);
95 |
96 | // parse the command line statement and break it up into space-delimited
97 | // strings. the array of strings will be saved in the argv array.
98 | argv[i] = strtok(cmd, " ");
99 | do
100 | {
101 | argv[++i] = strtok(NULL, " ");
102 | } while ((i < 30) && (argv[i] != NULL));
103 |
104 | // save off the number of arguments for the particular command.
105 | argc = i;
106 |
107 | // parse the command table for valid command. used argv[0] which is the
108 | // actual command name typed in at the prompt
109 | for (cmd_entry = cmd_tbl; cmd_entry != NULL; cmd_entry = cmd_entry->next)
110 | {
111 | if (!strcmp(argv[0], cmd_entry->cmd))
112 | {
113 | cmd_entry->func(argc, argv);
114 | cmd_display();
115 | return;
116 | }
117 | }
118 |
119 | // command not recognized. print message and re-generate prompt.
120 | strcpy_P(buf, cmd_unrecog);
121 | #ifdef DEBUG
122 | Serial.println(buf);
123 | #endif
124 |
125 | cmd_display();
126 | }
127 |
128 | /**************************************************************************/
129 | /*!
130 | This function processes the individual characters typed into the command
131 | prompt. It saves them off into the message buffer unless its a "backspace"
132 | or "enter" key.
133 | */
134 | /**************************************************************************/
135 | void cmd_handler()
136 | {
137 | char c = Serial.read();
138 |
139 | switch (c)
140 | {
141 | case '\r':
142 | // terminate the msg and reset the msg ptr. then send
143 | // it to the handler for processing.
144 | *msg_ptr = '\0';
145 | #ifdef DEBUG
146 | Serial.print("\r\n");
147 | #endif
148 | cmd_parse((char *)msg);
149 | msg_ptr = msg;
150 | break;
151 |
152 | case '\b':
153 | // backspace
154 | #ifdef DEBUG
155 | Serial.print(c);
156 | #endif
157 | if (msg_ptr > msg)
158 | {
159 | msg_ptr--;
160 | }
161 | break;
162 |
163 | default:
164 | // normal character entered. add it to the buffer
165 | #ifdef DEBUG
166 | Serial.print(c);
167 | #endif
168 | *msg_ptr++ = c;
169 | break;
170 | }
171 | }
172 |
173 | /**************************************************************************/
174 | /*!
175 | This function should be set inside the main loop. It needs to be called
176 | constantly to check if there is any available input at the command prompt.
177 | */
178 | /**************************************************************************/
179 | void cmdPoll()
180 | {
181 | while ( Serial.available())
182 | {
183 | cmd_handler();
184 | }
185 | }
186 |
187 | void clearCmd() {
188 | cmd_t* p, *next;
189 | for (p = cmd_tbl_list; p != NULL; p = next) {
190 | next = p->next;
191 | free(p->cmd);
192 | free(p);
193 | }
194 | cmd_tbl_list=NULL;
195 | }
196 |
197 | /**************************************************************************/
198 | /*!
199 | Initialize the command line interface. This sets the terminal speed and
200 | and initializes things.
201 | */
202 | /**************************************************************************/
203 | void cmdInit(uint32_t speed)
204 | {
205 | // init the msg ptr
206 | speedUart = speed;
207 | msg_ptr = msg;
208 |
209 | // init the command table
210 | cmd_tbl_list = NULL;
211 |
212 | // set the serial speed
213 | Serial.begin(speed);
214 | }
215 |
216 | /**************************************************************************/
217 | /*!
218 | Add a command to the command table. The commands should be added in
219 | at the setup() portion of the sketch.
220 | */
221 | /**************************************************************************/
222 | void cmdAdd(char *name, void (*func)(int argc, char **argv))
223 | {
224 | // alloc memory for command struct
225 | cmd_tbl = (cmd_t *)malloc(sizeof(cmd_t));
226 |
227 | // alloc memory for command name
228 | char *cmd_name = (char *)malloc(strlen(name) + 1);
229 |
230 | // copy command name
231 | strcpy(cmd_name, name);
232 |
233 | // terminate the command name
234 | cmd_name[strlen(name)] = '\0';
235 |
236 | // fill out structure
237 | cmd_tbl->cmd = cmd_name;
238 | cmd_tbl->func = func;
239 | cmd_tbl->next = cmd_tbl_list;
240 | cmd_tbl_list = cmd_tbl;
241 | }
242 |
243 | void pauseCmd(byte pause) {
244 | canRun = pause;
245 | }
246 |
247 | /**************************************************************************/
248 | /*!
249 | Convert a string to a number. The base must be specified, ie: "32" is a
250 | different value in base 10 (decimal) and base 16 (hexadecimal).
251 | */
252 | /**************************************************************************/
253 | uint32_t cmdStr2Num(char *str, uint8_t base)
254 | {
255 | return strtol(str, NULL, base);
256 | }
257 |
--------------------------------------------------------------------------------
/TelePager-bot/.idea/uiDesigner.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | -
6 |
7 |
8 | -
9 |
10 |
11 | -
12 |
13 |
14 | -
15 |
16 |
17 | -
18 |
19 |
20 |
21 |
22 |
23 | -
24 |
25 |
26 |
27 |
28 |
29 | -
30 |
31 |
32 |
33 |
34 |
35 | -
36 |
37 |
38 |
39 |
40 |
41 | -
42 |
43 |
44 |
45 |
46 | -
47 |
48 |
49 |
50 |
51 | -
52 |
53 |
54 |
55 |
56 | -
57 |
58 |
59 |
60 |
61 | -
62 |
63 |
64 |
65 |
66 | -
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 | -
75 |
76 |
77 |
78 |
79 | -
80 |
81 |
82 |
83 |
84 | -
85 |
86 |
87 |
88 |
89 | -
90 |
91 |
92 |
93 |
94 | -
95 |
96 |
97 |
98 |
99 | -
100 |
101 |
102 | -
103 |
104 |
105 | -
106 |
107 |
108 | -
109 |
110 |
111 | -
112 |
113 |
114 |
115 |
116 | -
117 |
118 |
119 | -
120 |
121 |
122 |
123 |
124 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/PocsagEncoder.cpp:
--------------------------------------------------------------------------------
1 | #include "PocsagEncoder.h"
2 |
3 | PocsagEncoder::PocsagEncoder() {
4 | }
5 |
6 | void PocsagEncoder::setCapCode(uint32_t capCode) {
7 | this->capCode = capCode;
8 | }
9 |
10 | void PocsagEncoder::setSource(byte source) {
11 | this->source = source;
12 | }
13 |
14 | void PocsagEncoder::setEncodingId(byte encodingId) {
15 | this->encodingId = encodingId;
16 | }
17 |
18 | void PocsagEncoder::setPrintMessage(byte printMessage) {
19 | this->printMessage = printMessage;
20 | }
21 |
22 | static word calculateBCH(uint32_t cw) {
23 | uint32_t generator = 0xED200000;
24 | uint32_t mask = 0x80000000;
25 |
26 | for (byte i = 0; i < 21; i++) {
27 | if (cw & mask) {
28 | cw ^= generator;
29 | }
30 | generator >>= 1;
31 | mask >>= 1;
32 | }
33 |
34 | return cw >> 1;
35 | }
36 |
37 | static byte calculateParity(uint32_t cw) {
38 | byte parity = 0;
39 |
40 | for (byte i = 0; i < 32; i++) {
41 | if (cw & 0x80000000) {
42 | parity ^= 1;
43 | }
44 | cw <<= 1;
45 | }
46 |
47 | return parity;
48 | }
49 |
50 | static void flipEndianess(uint32_t *value) {
51 | uint8_t *bytes = (uint8_t*) value;
52 | uint8_t tmp = bytes[0];
53 | bytes[0] = bytes[3];
54 | bytes[3] = tmp;
55 | tmp = bytes[1];
56 | bytes[1] = bytes[2];
57 | bytes[2] = tmp;
58 | }
59 |
60 | static void fillCW(PocsagEncoder::PocsagCW *codeWord, byte messageType, uint32_t payloadBits) {
61 | codeWord->data = 0;
62 | codeWord->messageType = messageType;
63 | codeWord->payloadBits = payloadBits;
64 | codeWord->crcBits = calculateBCH(codeWord->data);
65 | codeWord->parityBits = calculateParity(codeWord->data);
66 | flipEndianess(&codeWord->data);
67 | }
68 |
69 | static void fillAddressCW(PocsagEncoder::PocsagCW *codeWord, uint32_t capCode, byte source) {
70 | fillCW(codeWord, 0, ((capCode >> 3) << 2) | source);
71 | }
72 |
73 | static void fillMessageCW(PocsagEncoder::PocsagCW *codeWord, uint32_t messageBits) {
74 | fillCW(codeWord, 1, messageBits);
75 | }
76 |
77 | // Fill preamble bytes with 0xAA and frames with idle code words, fill address code word and return first frame number
78 | static byte prepareMessage(PocsagEncoder::PocsagMessage *message, uint32_t capCode, byte source) {
79 | // Fill preamble
80 | for (byte i = 0; i < PCSG_PREAMBLE_LENGTH; i++) {
81 | message->preamble[i] = 0xAA;
82 | }
83 | // Fill frames with idle code words
84 | for (byte i = 0; i < PCSG_BATCHES_COUNT; i++) {
85 | message->batches[i].fsc = 0xD814D27C; // 0x7CD214D8
86 | for (byte j = 0; j < 8; j++) {
87 | message->batches[i].frames[j].codeWords[0].data = 0x97C1897A; // 0x7A89C197
88 | message->batches[i].frames[j].codeWords[1].data = 0x97C1897A; // 0x7A89C197
89 | }
90 | }
91 |
92 | // Determine first frame number
93 | byte currentFrame = capCode & 0x7;
94 |
95 | // Fill address code word
96 | fillAddressCW(&message->batches[0].frames[currentFrame].codeWords[0], capCode, source);
97 |
98 | return currentFrame;
99 | }
100 |
101 | // Convert 1-byte ASCII character to 5-bit Pocsag digit
102 | byte PocsagEncoder::getPocsagNumericCharacter(byte asciiChar) {
103 | for (byte i = 0; i < 16; i++) {
104 | if (pgm_read_byte(&PCSG_ALPHABET[i][0]) == asciiChar) {
105 | return pgm_read_byte(&PCSG_ALPHABET[i][1]);
106 | }
107 | }
108 |
109 | return 0xC; // ' ' (space) - unknown digit
110 | }
111 |
112 | // Convert 2-byte Latin or Cyrillic UTF-8 character to 1-byte Windows-1251
113 | static inline byte utf8ToWindows1251(word character, byte flipCase) {
114 | // Latin
115 | if (character <= 0x7E) {
116 | if (flipCase && character >= 0x41 && character <= 0x7A) {
117 | return character ^ (1 << 5);
118 | }
119 | return character;
120 | }
121 |
122 | // Cyrillic
123 | // Special cyrillic characters workaround
124 | switch(character) {
125 | case 0xD081: if (flipCase) return 184; else return 168; // Ё/ё
126 | case 0xD191: if (flipCase) return 168; else return 184; // ё/Ё
127 | case 0xD083: if (flipCase) return 131; else return 129; // Ѓ/ѓ
128 | case 0xD193: if (flipCase) return 129; else return 131; // ѓ/Ѓ
129 | case 0xD084: if (flipCase) return 186; else return 170; // Є/є
130 | case 0xD194: if (flipCase) return 170; else return 186; // є/Є
131 | case 0xD087: if (flipCase) return 191; else return 175; // Ї/ї
132 | case 0xD197: if (flipCase) return 175; else return 191; // ї/Ї
133 | case 0xD08B: if (flipCase) return 158; else return 142; // Ћ/ћ
134 | case 0xD19B: if (flipCase) return 142; else return 158; // ћ/Ћ
135 | default: break;
136 | }
137 |
138 | // Main cyrillic characters
139 | if (character >= 0xD090 && character <= 0xD18F) {
140 | if (character >= 0xD090 && character <= 0xD0BF) {
141 | // 'А' - 'п'
142 | character -= 0xCFD0;
143 | } else if (character >= 0xD180 && character <= 0xD18F) {
144 | // 'р' - 'я'
145 | character -= 0xD090;
146 | }
147 | if (flipCase) {
148 | return character ^ (1 << 5);
149 | }
150 | return character;
151 | }
152 |
153 | return 0x3F; // '?' - unknown symbol;
154 | }
155 |
156 | // Convert 2-byte Latin or Cyrillic UTF-8 character to 7-bit Pocsag character
157 | byte PocsagEncoder::getPocsagAlphanumericCharacter(word utf8Char, byte encodingId) {
158 | byte winChar = utf8ToWindows1251(utf8Char, 0);
159 | if (winChar == 0x3F) {
160 | return 0x3F;
161 | }
162 |
163 | // Search in common section
164 | for (byte i = 16; i < 48; i++) {
165 | if (pgm_read_byte(&PCSG_ALPHABET[i][0]) == winChar) {
166 | return pgm_read_byte(&PCSG_ALPHABET[i][1]);
167 | }
168 | }
169 |
170 | // Search in current case
171 | for (word i = PCSG_ENCODINGS[encodingId].offset; i < PCSG_ENCODINGS[encodingId].offset + PCSG_ENCODINGS[encodingId].length; i++) {
172 | if (pgm_read_byte(&PCSG_ALPHABET[i][0]) == winChar) {
173 | return pgm_read_byte(&PCSG_ALPHABET[i][1]);
174 | }
175 | }
176 |
177 | // Search in flipped case:
178 | winChar = utf8ToWindows1251(utf8Char, 1);
179 | for (word i = PCSG_ENCODINGS[encodingId].offset; i < PCSG_ENCODINGS[encodingId].offset + PCSG_ENCODINGS[encodingId].length; i++) {
180 | if (pgm_read_byte(&PCSG_ALPHABET[i][0]) == winChar) {
181 | return pgm_read_byte(&PCSG_ALPHABET[i][1]);
182 | }
183 | }
184 |
185 | return 0x3F; // '?' - unknown symbol
186 | }
187 |
188 | static void printMsg(PocsagEncoder::PocsagMessage message) {
189 | byte byteCounter = 0;
190 | byte wordCounter = 0;
191 | uint32_t byteAcc = 0;
192 | for (word i = PCSG_PREAMBLE_LENGTH; i < message.messageLength; i++) {
193 | byteAcc <<= 8;
194 | byteAcc |= message.dataBytes[i];
195 | if (++byteCounter >= 4) {
196 | Serial.print(byteAcc, HEX);
197 | if (++wordCounter % 8 == 1) {
198 | Serial.println();
199 | } else {
200 | Serial.print(" ");
201 | if (wordCounter >= 18) {
202 | wordCounter = 1;
203 | Serial.println();
204 | }
205 | }
206 | byteCounter = 0;
207 | byteAcc = 0;
208 | }
209 | }
210 | }
211 |
212 | static void incrementCounters(byte *currentBatch, byte *currentFrame, byte *currentCodeWord) {
213 | (*currentCodeWord)++;
214 | if (*currentCodeWord >= 2) {
215 | *currentCodeWord = 0;
216 | (*currentFrame)++;
217 | if (*currentFrame >= 8) {
218 | *currentFrame = 0;
219 | (*currentBatch)++;
220 | }
221 | }
222 | }
223 |
224 | static void pushPocsagChar(byte pocsagChar, byte charSize, uint32_t *messageBits, byte *messageBitsLength,
225 | PocsagEncoder::PocsagMessage *message, byte *currentBatch, byte *currentFrame, byte *currentCodeWord) {
226 | for (byte b = 0; b < charSize; b++) {
227 | *messageBits |= pocsagChar & 1;
228 | (*messageBitsLength)++;
229 |
230 | // Push message bits to code word
231 | if (*messageBitsLength >= 20) {
232 | *messageBitsLength = 0;
233 | fillMessageCW(&message->batches[*currentBatch].frames[*currentFrame].codeWords[*currentCodeWord], *messageBits);
234 | incrementCounters(currentBatch, currentFrame, currentCodeWord);
235 | }
236 |
237 | *messageBits <<= 1;
238 | pocsagChar >>= 1;
239 | }
240 | }
241 |
242 | PocsagEncoder::PocsagMessage PocsagEncoder::encodeNumeric(String messageText) {
243 | PocsagMessage message;
244 |
245 | // Prepare message and fill address CW
246 | byte currentFrame = prepareMessage(&message, capCode, source);
247 | byte currentBatch = 0;
248 | byte currentCodeWord = 1;
249 | uint32_t messageBits = 0;
250 | byte messageBitsLength = 0;
251 |
252 | // Convert and push all characters to message code words
253 | for (word i = 0; i < messageText.length(); i++) {
254 | byte nextChar = messageText.charAt(i);
255 |
256 | // Skip leading space and non-printable symbols
257 | if ((i == 0 && nextChar == 0x20) || nextChar < 0x20) {
258 | continue;
259 | }
260 |
261 | // Translate to pocsag digit
262 | byte pocsagChar = getPocsagNumericCharacter(nextChar);
263 |
264 | // Push next digit to message bits
265 | pushPocsagChar(pocsagChar, 4, &messageBits, &messageBitsLength, &message, ¤tBatch, ¤tFrame, ¤tCodeWord);
266 | }
267 |
268 | // Fill empty space of last message codeword with 0xC character
269 | if (messageBitsLength > 0 && messageBitsLength < 20) {
270 | byte freeSpace = 20 - messageBitsLength;
271 | for (byte i = 0; i < freeSpace / 4; i++) {
272 | pushPocsagChar(0xC, 4, &messageBits, &messageBitsLength, &message, ¤tBatch, ¤tFrame, ¤tCodeWord);
273 | }
274 | }
275 |
276 | message.messageLength = PCSG_PREAMBLE_LENGTH + 68 * (currentBatch + 1);
277 |
278 | if (printMessage) {
279 | printMsg(message);
280 | }
281 |
282 | return message;
283 | }
284 |
285 | PocsagEncoder::PocsagMessage PocsagEncoder::encodeAlphanumeric(String messageText) {
286 | PocsagMessage message;
287 |
288 | // Prepare message and fill address CW
289 | byte currentFrame = prepareMessage(&message, capCode, source);
290 | byte currentBatch = 0;
291 | byte currentCodeWord = 1;
292 | uint32_t messageBits = 0;
293 | byte messageBitsLength = 0;
294 |
295 | // Convert and push all characters to message code words
296 | for (word i = 0; i < messageText.length(); i++) {
297 | word nextChar = messageText.charAt(i);
298 |
299 | // Skip leading space and non-printable symbols
300 | if ((i == 0 && nextChar == 0x20) || nextChar < 0x20) {
301 | continue;
302 | }
303 |
304 | // 2-byte UTF-8 symbol - read second byte (workaround for Cyrillic characters)
305 | if (nextChar & 0x80) {
306 | i++;
307 | nextChar <<= 8;
308 | nextChar |= (byte) messageText.charAt(i);
309 | }
310 |
311 | // Translate to pocsag alphabet using current encoding
312 | byte pocsagChar = getPocsagAlphanumericCharacter(nextChar, encodingId);
313 |
314 | // Check if there is enough space to put next char in the last code word of the last batch
315 | // We must preserve at least 7 bits to put EOT/ETX character at the end of the message
316 | if (currentBatch == PCSG_BATCHES_COUNT - 1 && currentFrame == 7 && currentCodeWord == 1) {
317 | // Skip all remaining chars because they won't fit
318 | if (messageBitsLength >= 7) {
319 | break;
320 | }
321 | }
322 |
323 | // Push next character to message bits
324 | pushPocsagChar(pocsagChar, 7, &messageBits, &messageBitsLength, &message, ¤tBatch, ¤tFrame, ¤tCodeWord);
325 | }
326 |
327 | // Push EOT symbol to the end of the message
328 | byte eotChar = PCSG_EOT_CHAR;
329 | pushPocsagChar(eotChar, 7, &messageBits, &messageBitsLength, &message, ¤tBatch, ¤tFrame, ¤tCodeWord);
330 |
331 | // Fill last message code word
332 | if (messageBitsLength > 0 && messageBitsLength < 20) {
333 | // Try to push additional EOTs
334 | byte freeSpace = 20 - messageBitsLength;
335 | for (byte i = 0; i < freeSpace / 7; i++) {
336 | pushPocsagChar(eotChar, 7, &messageBits, &messageBitsLength, &message, ¤tBatch, ¤tFrame, ¤tCodeWord);
337 | }
338 | // Trying to fill left empty space with EOT bits partially
339 | for (byte b = 0; b < 19 - messageBitsLength; b++) {
340 | messageBits |= eotChar & 1;
341 | messageBits <<= 1;
342 | eotChar >>= 1;
343 | }
344 | fillMessageCW(&message.batches[currentBatch].frames[currentFrame].codeWords[currentCodeWord], messageBits);
345 | }
346 |
347 | message.messageLength = PCSG_PREAMBLE_LENGTH + 68 * (currentBatch + 1);
348 |
349 | if (printMessage) {
350 | printMsg(message);
351 | }
352 |
353 | return message;
354 | }
355 |
356 | PocsagEncoder::PocsagMessage PocsagEncoder::encodeTone() {
357 | PocsagMessage message;
358 |
359 | // Fill address CW only
360 | prepareMessage(&message, capCode, source);
361 | message.messageLength = PCSG_PREAMBLE_LENGTH + 68;
362 |
363 | if (printMessage) {
364 | printMsg(message);
365 | }
366 |
367 | return message;
368 | }
369 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/Rf7021.cpp:
--------------------------------------------------------------------------------
1 | #include "rf7021.h"
2 |
3 | Rf7021::Rf7021() {
4 | // Default settings
5 | rfConfig.xtalFrequency = 19680000UL; // Default 19.68 MHz TCXO
6 | rfConfig.hasExternalInductor = 1; // RF7021SE has no external inductor on L1-L2 pins by default
7 | rfConfig.xtalBias = 3; // 0 - 20uA, 1 - 25uA, 2 - 30uA, 3 - 35uA
8 | rfConfig.cpCurrent = 3; // 0 - 0.3mA, 1 - 0.9mA, 2 - 1.5mA, 3 - 2.1mA
9 | rfConfig.modulationScheme = 0; // 0 - FSK, 1 - GFSK, 2 - 3FSK, 3 - 4FSK, 4 - OFSK, 5 - RCFSK, 6 - RC3FSK, 7 - RC4FSK
10 | rfConfig.powerAmplifierEnabled = 1; // 0 - OFF, 1 - ON
11 | rfConfig.powerAmplifierRamping = 1; // 0 - OFF, 1 - LOWEST, ..., 7 - HIGHEST
12 | rfConfig.powerAmplifierBias = 3; // 0 - 5uA, 1 - 7uA, 2 - 9uA, 3 - 11 uA
13 | rfConfig.powerAmplifierPower = 63; // 0 - OFF, 1 - LOWEST, ..., 63 - HIGHEST
14 | rfConfig.dataInvertType = 2; // 0 - NONE, 1 - Invert CLK, 2 - Invert DATA, 3 - Invert CLK and DATA
15 | rfConfig.dataInvertEnabled = 0; // 0 - OFF, 1 - ON
16 | rfConfig.rCosineAlpha = 1; // 0 - 0.5, 1 - 0.7
17 | }
18 |
19 | void Rf7021::setTxRxDataPin(byte txRxDataPin) {
20 | rfConfig.txRxDataPin = txRxDataPin;
21 | pinMode(txRxDataPin, OUTPUT);
22 | }
23 |
24 | void Rf7021::setTxRxCLKPin(byte txRxCLKPin) {
25 | rfConfig.txRxCLKPin = txRxCLKPin;
26 | pinMode(txRxCLKPin, INPUT);
27 | }
28 |
29 | void Rf7021::setCEPin(byte cePin) {
30 | rfConfig.cePin = cePin;
31 | pinMode(cePin, OUTPUT);
32 | }
33 |
34 | void Rf7021::setSREADPin(byte sreadPin) {
35 | rfConfig.sreadPin = sreadPin;
36 | pinMode(sreadPin, INPUT);
37 | }
38 |
39 | void Rf7021::setSLEPin(byte slePin) {
40 | rfConfig.slePin = slePin;
41 | pinMode(slePin, OUTPUT);
42 | }
43 |
44 | void Rf7021::setSDATAPin(byte sdataPin) {
45 | rfConfig.sdataPin = sdataPin;
46 | pinMode(sdataPin, OUTPUT);
47 | }
48 |
49 | void Rf7021::setSCLKPin(byte sclkPin) {
50 | rfConfig.sclkPin = sclkPin;
51 | pinMode(sclkPin, OUTPUT);
52 | }
53 |
54 | void Rf7021::setXtalFrequency(uint32_t xtalFrequency) {
55 | rfConfig.xtalFrequency = xtalFrequency;
56 | }
57 |
58 | uint32_t Rf7021::getXtalFrequency() {
59 | return rfConfig.xtalFrequency;
60 | }
61 |
62 | void Rf7021::setXtalBias(byte xtalBias) {
63 | rfConfig.xtalBias = xtalBias;
64 | }
65 |
66 | void Rf7021::setCpCurrent(byte cpCurrent) {
67 | rfConfig.cpCurrent = cpCurrent;
68 | }
69 |
70 | void Rf7021::setHasExternalInductor(byte hasExternalInductor) {
71 | rfConfig.hasExternalInductor = hasExternalInductor;
72 | }
73 |
74 | void Rf7021::setmModulationScheme(byte modulationScheme) {
75 | rfConfig.modulationScheme = modulationScheme;
76 | }
77 |
78 | void Rf7021::setPowerAmplifierEnabled(byte powerAmplifierEnabled) {
79 | rfConfig.powerAmplifierEnabled = powerAmplifierEnabled;
80 | }
81 |
82 | void Rf7021::setPowerAmplifierRamping(byte powerAmplifierRamping) {
83 | rfConfig.powerAmplifierRamping = powerAmplifierRamping;
84 | }
85 |
86 | void Rf7021::setPowerAmplifierBias(byte powerAmplifierBias) {
87 | rfConfig.powerAmplifierBias = powerAmplifierBias;
88 | }
89 |
90 | void Rf7021::setPowerAmplifierPower(byte powerAmplifierPower) {
91 | rfConfig.powerAmplifierPower = powerAmplifierPower;
92 | }
93 |
94 | void Rf7021::setDataInvertType(byte dataInvertType) {
95 | rfConfig.dataInvertType = dataInvertType;
96 | }
97 |
98 | void Rf7021::setRCosineAlpha(byte rCosineAlpha) {
99 | rfConfig.rCosineAlpha = rCosineAlpha;
100 | }
101 |
102 | void Rf7021::setDataRate(word dataRate) {
103 | rfConfig.dataRate = dataRate;
104 | }
105 |
106 | void Rf7021::setFrequency(uint32_t frequency) {
107 | rfConfig.frequency = frequency;
108 | }
109 |
110 | uint32_t Rf7021::getFrequency() {
111 | return rfConfig.frequency ;
112 | }
113 |
114 | void Rf7021::setFrequencyDeviation(word frequencyDeviation) {
115 | rfConfig.frequencyDeviation = frequencyDeviation;
116 | }
117 |
118 | void Rf7021::setDataInvertEnabled(byte dataInvertEnabled) {
119 | rfConfig.dataInvertEnabled = dataInvertEnabled;
120 | }
121 |
122 | void Rf7021::writeReg(RfReg *reg) {
123 | digitalWrite(rfConfig.slePin, LOW);
124 | digitalWrite(rfConfig.sclkPin, LOW);
125 |
126 | for (byte i = 4; i > 0; i--) {
127 | byte buf = reg->dataBytes[i - 1];
128 | for (byte j = 8; j > 0; j--) {
129 | digitalWrite(rfConfig.sclkPin, LOW);
130 | digitalWrite(rfConfig.sdataPin, (buf & 0x80) ? HIGH : LOW);
131 | digitalWrite(rfConfig.sclkPin, HIGH);
132 | buf <<= 1;
133 | }
134 | digitalWrite(rfConfig.sclkPin, LOW);
135 | }
136 |
137 | digitalWrite(rfConfig.slePin, HIGH);
138 | delay(1);
139 | digitalWrite(rfConfig.sdataPin, LOW);
140 | digitalWrite(rfConfig.slePin, LOW);
141 | }
142 |
143 | Rf7021::RfReg Rf7021::readReg(word readbackConfig) {
144 | RfReg reg;
145 | reg.data = ((readbackConfig & 0x1F) << 4);
146 |
147 | reg.data |= 7;
148 | writeReg(®);
149 | reg.data = 0;
150 |
151 | digitalWrite(rfConfig.sdataPin, LOW);
152 | digitalWrite(rfConfig.sclkPin, LOW);
153 | digitalWrite(rfConfig.slePin, HIGH);
154 |
155 | // Skip first DB16 byte
156 | digitalWrite(rfConfig.sclkPin, HIGH);
157 | digitalWrite(rfConfig.sclkPin, LOW);
158 |
159 | byte buf = 0;
160 | for (byte i = 2; i > 0; i--) {
161 | for (byte j = 8; j > 0; j--) {
162 | digitalWrite(rfConfig.sclkPin, HIGH);
163 | buf <<= 1;
164 | if (digitalRead(rfConfig.sreadPin)) {
165 | buf |= 1;
166 | }
167 | digitalWrite(rfConfig.sclkPin, LOW);
168 | }
169 | reg.dataBytes[i - 1] = buf;
170 | }
171 |
172 | digitalWrite(rfConfig.sclkPin, HIGH);
173 | digitalWrite(rfConfig.slePin, LOW);
174 | digitalWrite(rfConfig.sclkPin, LOW);
175 |
176 | return reg;
177 | }
178 |
179 | word Rf7021::getSiliconRev() {
180 | powerOn();
181 | word value = readReg(0x1C).dataLower;
182 | powerOff();
183 | return value;
184 | }
185 |
186 | float Rf7021::getTemp() {
187 | powerOn();
188 | RfReg reg;
189 | reg.data = 8;
190 | reg.data |= 1 << 8;
191 | writeReg(®);
192 | reg = readReg(0x16);
193 | powerOff();
194 | return 469.5 - (7.2 * (reg.dataBytes[0] & 0x7F));
195 | }
196 |
197 | float Rf7021::getVoltage() {
198 | powerOn();
199 | RfReg reg;
200 | reg.data = 8;
201 | reg.data |= 1 << 8;
202 | writeReg(®);
203 | reg = readReg(0x15);
204 | powerOff();
205 | return (reg.dataBytes[0] & 0x7F) / 21.1;
206 | }
207 |
208 | void Rf7021::powerOn() {
209 | digitalWrite(rfConfig.cePin, HIGH);
210 | delay(1);
211 |
212 | // Prepare and push Register 1
213 | rfConfig.R1.addressBits = 1;
214 | rfConfig.R1.rCounter = 1;
215 | rfConfig.R1.clockoutDivide = 0;
216 | rfConfig.R1.xtalDoubler = 0;
217 | rfConfig.R1.xoscEnable = 1;
218 | rfConfig.R1.xtalBias = rfConfig.xtalBias;
219 | rfConfig.R1.cpCurrent = rfConfig.cpCurrent;
220 | rfConfig.R1.vcoEnable = 1;
221 | if (rfConfig.frequency >= 900000000UL && rfConfig.frequency <= 950000000UL) {
222 | // 900 - 950 MHz internal VCO
223 | rfConfig.R1.rfDivideBy2 = 0;
224 | rfConfig.R1.vcoBias = 8;
225 | rfConfig.R1.vcoAdjust = 3;
226 | rfConfig.R1.vcoInductor = 0;
227 | } else if (rfConfig.frequency >= 800000000UL && rfConfig.frequency < 900000000UL) {
228 | // 862 - 900 MHz internal VCO
229 | rfConfig.R1.rfDivideBy2 = 0;
230 | rfConfig.R1.vcoBias = 8;
231 | rfConfig.R1.vcoAdjust = 0;
232 | rfConfig.R1.vcoInductor = 0;
233 | } else if (rfConfig.frequency >= 450000000UL && rfConfig.frequency < 500000000UL) {
234 | // 450 - 500 MHz internal VCO
235 | rfConfig.R1.rfDivideBy2 = 1;
236 | rfConfig.R1.vcoBias = 8;
237 | rfConfig.R1.vcoAdjust = 3;
238 | rfConfig.R1.vcoInductor = 0;
239 | } else if (rfConfig.frequency >= 400000000UL && rfConfig.frequency < 450000000UL) {
240 | // 400 - 450 MHz internal VCO
241 | rfConfig.R1.rfDivideBy2 = 1;
242 | rfConfig.R1.vcoBias = 8;
243 | rfConfig.R1.vcoAdjust = 0;
244 | rfConfig.R1.vcoInductor = 0;
245 | } else if (rfConfig.hasExternalInductor && rfConfig.frequency >= 500000000UL && rfConfig.frequency <= 650000000UL) {
246 | // 500 - 650 MHz external VCO
247 | rfConfig.R1.rfDivideBy2 = 0;
248 | rfConfig.R1.vcoBias = 4;
249 | rfConfig.R1.vcoInductor = 1;
250 | } else if (rfConfig.hasExternalInductor && rfConfig.frequency >= 200000000UL && rfConfig.frequency < 400000000UL) {
251 | // 200 - 400 MHz external VCO
252 | rfConfig.R1.rfDivideBy2 = 0;
253 | rfConfig.R1.vcoBias = 3;
254 | rfConfig.R1.vcoInductor = 1;
255 | } else if (rfConfig.hasExternalInductor && rfConfig.frequency >= 80000000UL && rfConfig.frequency < 200000000UL) {
256 | // 80 - 200 MHz external VCO
257 | rfConfig.R1.rfDivideBy2 = 1;
258 | rfConfig.R1.vcoBias = 2;
259 | rfConfig.R1.vcoInductor = 1;
260 | }
261 | writeReg(&rfConfig.r1);
262 |
263 | // Prepare and push Register 15 (CLK_MUX = 0x0 to enable default mode)
264 | rfConfig.R15.addressBits = 15;
265 | rfConfig.R15.rxTestMode = 0;
266 | rfConfig.R15.txTestMode = 0;
267 | rfConfig.R15.sdTestMode = 0;
268 | rfConfig.R15.cpTestMode = 0;
269 | rfConfig.R15.clkMux = 0;
270 | rfConfig.R15.pllTestMode = 0;
271 | rfConfig.R15.analogTestMode = 0;
272 | rfConfig.R15.forceLdHigh = 0;
273 | rfConfig.R15.reg1Pd = 0;
274 | rfConfig.R15.calOverride = 0;
275 | writeReg(&rfConfig.r15);
276 |
277 | // Prepare and push Register 3
278 | rfConfig.R3.addressBits = 3;
279 | // Find best BBOS divider
280 | for (byte bbosDiv = 0; bbosDiv < 4; bbosDiv++) {
281 | uint32_t bbosClk = round(rfConfig.xtalFrequency / (2 << (bbosDiv + 1)));
282 | if (bbosClk >= 1000000UL && bbosClk <= 2000000UL) {
283 | rfConfig.R3.bbosClkDivide = bbosDiv;
284 | }
285 | }
286 | // Find best DEMOD and CDR dividers to achieve required data rate
287 | double rateDeltaMin = rfConfig.dataRate;
288 | for (byte dem = 1; dem < 15; dem++) {
289 | byte cdr = round(rfConfig.xtalFrequency / (dem * rfConfig.dataRate * 32.0));
290 | if (cdr == 0) continue;
291 | word realRate = round(rfConfig.xtalFrequency / (dem * cdr * 32.0));
292 | double delta = abs(realRate - rfConfig.dataRate);
293 | if (delta < rateDeltaMin) {
294 | rfConfig.R3.demClkDivide = dem;
295 | rfConfig.R3.cdrClkDivide = cdr;
296 | rateDeltaMin = delta;
297 | }
298 | }
299 | rfConfig.R3.seqClkDivide = round(rfConfig.xtalFrequency / 100000.0);
300 | rfConfig.R3.agcClkDivide = round((rfConfig.R3.seqClkDivide * rfConfig.xtalFrequency) / 10000.0);
301 | writeReg(&rfConfig.r3);
302 |
303 | // Prepare and push Register 0
304 | rfConfig.R0.addressBits = 0;
305 | double n = (rfConfig.frequency * rfConfig.R1.rCounter / (rfConfig.xtalFrequency * (rfConfig.R1.rfDivideBy2 ? 0.5 : 1.0)));
306 | uint32_t nInt = floor(n);
307 | uint32_t nFrac = round((n - floor(n)) * 32768);
308 | rfConfig.R0.fractionalN = nFrac;
309 | rfConfig.R0.integerN = nInt;
310 | rfConfig.R0.rxMode = 0;
311 | rfConfig.R0.uartMode = 0;
312 | rfConfig.R0.muxOut = 0;
313 | writeReg(&rfConfig.r0);
314 |
315 | // Prepare and push Register 2
316 | rfConfig.R2.addressBits = 2;
317 | rfConfig.R2.modulationScheme = rfConfig.modulationScheme;
318 | rfConfig.R2.paEnable = rfConfig.powerAmplifierEnabled;
319 | rfConfig.R2.paRamp = rfConfig.powerAmplifierRamping;
320 | rfConfig.R2.paBias = rfConfig.powerAmplifierBias;
321 | rfConfig.R2.powerAmplifier = rfConfig.powerAmplifierPower;
322 | rfConfig.R2.txFrequencyDeviation = round(rfConfig.frequencyDeviation * 65536.0 * (rfConfig.R1.rfDivideBy2 ? 2.0 : 1.0) / ((double) rfConfig.xtalFrequency / rfConfig.R1.rCounter));
323 | rfConfig.R2.txDataInvert = rfConfig.dataInvertEnabled ? rfConfig.dataInvertType : 0;
324 | rfConfig.R2.rcosineAlpha = rfConfig.rCosineAlpha;
325 | writeReg(&rfConfig.r2);
326 | }
327 |
328 | void Rf7021::powerOff() {
329 | digitalWrite(rfConfig.cePin, LOW);
330 | delay(1);
331 | }
332 |
333 | void Rf7021::txTest(byte testMode, word duration) {
334 | powerOn();
335 |
336 | rfConfig.R15.txTestMode = testMode;
337 | writeReg(&rfConfig.r15);
338 |
339 | delay(duration);
340 |
341 | powerOff();
342 | }
343 |
344 | bool Rf7021::sendMessage(byte *message, word messageLength) {
345 | powerOn();
346 |
347 | byte bitCounter = 0;
348 | word byteCounter = 0;
349 | byte currentByte = message[0];
350 | long startTime = millis();
351 |
352 | while (byteCounter < messageLength) {
353 | // Wait LOW on TxRxCLK
354 | while (digitalRead(rfConfig.txRxCLKPin));
355 |
356 | // Push bit
357 | if (currentByte & 0x80) {
358 | digitalWrite(rfConfig.txRxDataPin, HIGH);
359 | } else {
360 | digitalWrite(rfConfig.txRxDataPin, LOW);
361 | }
362 |
363 | // Switch to next bit
364 | bitCounter++;
365 | if (bitCounter >= 8) {
366 | bitCounter = 0;
367 | byteCounter++;
368 | currentByte = message[byteCounter];
369 | } else {
370 | currentByte <<= 1;
371 | }
372 |
373 | // Wait HIGH on TxRxCLK
374 | while (!digitalRead(rfConfig.txRxCLKPin)) {
375 | if (millis() - startTime > 3000) {
376 | powerOff();
377 | return false;
378 | }
379 | };
380 | }
381 |
382 | powerOff();
383 | return true;
384 | }
385 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/CmdProc.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include "Rf7021.h"
3 | #include "Storage.h"
4 | #include "Cmd.h"
5 | #include
6 |
7 | Rf7021 rfD;
8 |
9 | String alignStr(char* strI, int len) {
10 | String ret = String();
11 | String str = String(strI);
12 | int dif = len - str.length();
13 | if (dif > 0) {
14 | int pre;
15 |
16 | if (dif % 2 == 0)
17 | pre = dif / 2;
18 | else
19 | pre = dif / 2 - 1 + dif % 2;
20 |
21 | for (int i = 0; i < dif; i++) {
22 | if (i == pre)
23 | ret += str;
24 | ret += (F(" "));
25 | }
26 |
27 | } else {
28 | ret = str.substring(0, len);
29 | }
30 | return ret;
31 | }
32 |
33 | void pstr(String &str) {
34 | Serial.println(str);
35 | }
36 |
37 | void reserBuf() {
38 | while (Serial.available() > 0) {
39 | Serial.read();
40 | }
41 | }
42 |
43 | String getCurStr() {
44 | return String(F(" / cur. "));
45 | }
46 | void printSet(String val) {
47 | Serial.println(String(F("Set: ")) + val);
48 | }
49 | void printDiv() {
50 | Serial.println(F("\r--------------------------"));
51 | }
52 |
53 |
54 |
55 |
56 | void printWelcome(Rf7021 rf) {
57 | rfD = rf;
58 | Serial.println("\r\r\r\r\r");
59 | Serial.println(F("-----===[ Welcome to Universal POCSAG Transmitter ]===-----"));
60 | Serial.print(F("Sysinfo: FW ver: 1.0, HW rev. "));
61 | Serial.print(rf.getSiliconRev(), HEX);
62 | Serial.print(F(", temp.: "));
63 | Serial.print(rf.getTemp());
64 | Serial.print(F(", volt.: "));
65 | Serial.println(rf.getVoltage());
66 | Serial.println(F("\rSelect mode:"));
67 | Serial.println(F(" 1 - Free mode"));
68 | Serial.println(F(" 2 - Specified pager(s)"));
69 | Serial.println(F(" 3 - Saved pagers"));
70 | Serial.flush();
71 | printDiv();
72 | }
73 |
74 |
75 | /**
76 | * Меню базовых команд
77 | */
78 | void printFreeMode() {
79 | // curPage = 1;
80 | Serial.println("\r\r\r\r\r");
81 | Serial.println(F("-----===[ Free mode ]===-----"));
82 | Serial.println(F("Here you can set manual CAP, freq and other options"));
83 | Serial.println(F("Command \"send\" and base commands:"));
84 | Serial.println(F(" [f] - frequency, kHz"));
85 | Serial.println(F(" [c] - set CAP code"));
86 | Serial.println(F(" [r] - set data rate (512, 1200 or 2400)"));
87 | Serial.println(F(" [m] - text message, must be at the end of the prompt"));
88 | Serial.println(F("\r Example: \"send f 160218 c 123456 m Hello world!\""));
89 | Serial.println(F("\r full - see all commands"));
90 | Serial.println(F(" 0 - go back"));
91 | printDiv();
92 | }
93 |
94 | /**
95 | * Меню всех команд
96 | */
97 | void printFreeModeAdv() {
98 | Serial.println(F("Advanced commands:"));
99 | Serial.println(F(" [n] - send numeric message (e.g. \"n U *123*456*789\")"));
100 | Serial.println(F(" [t] - send tone message"));
101 | Serial.println(F(" [d] - set frequency deviation in kHz"));
102 | Serial.println(F(" [i] - set data inversion (0 - disabled, 1 - enabled)"));
103 | Serial.println(F(" [s] - set message source code (1 to 3)"));
104 | Serial.println(F(" [e] - set encoding"));
105 | Serial.println(F(" 0 - EN Motorola"));
106 | Serial.println(F(" 1 - EN/RU Motorola"));
107 | Serial.println(F(" 2 - EN/RU Philips"));
108 | Serial.println(F(" 3 - RU Motorola"));
109 | Serial.println(F(" [x] - run transmiter test"));
110 | printDiv();
111 | }
112 |
113 |
114 |
115 | /**
116 | * Вывод информации о пейджере
117 | */
118 | void printPager(Pager *pager, bool detailed, bool wHeader) {
119 | // Serial.println(pager->cap);
120 | if (wHeader) {
121 | Serial.print(F("\r ID | Name | CAP |"));
122 | if (detailed) {
123 | Serial.print(F(" Freq | Rate | Source | Enc | Inv |"));
124 | }
125 | Serial.println();
126 | for (int i = 0; i < (detailed ? 64 : 27); i++) {
127 | Serial.print("-");
128 | }
129 | Serial.println();
130 | }
131 |
132 | String det = "";
133 | char buf[7];
134 | char spc = ' ';
135 | char dev = '|';
136 |
137 | ltoa(pager->addr, buf, DEC);
138 | det += alignStr(buf, 5) + dev;
139 |
140 | det += spc + alignStr(pager->alias, 10) + dev;
141 |
142 | ltoa(pager->cap, buf, DEC);
143 | det += spc + alignStr(buf, 7) + dev;
144 |
145 |
146 | if (detailed) {
147 | ltoa(pager->frequency, buf, DEC);
148 | det += spc + alignStr(buf, 6) + dev;
149 |
150 | ltoa(pager->rate, buf, DEC);
151 | det += spc + alignStr(buf, 5) + dev;
152 |
153 | ltoa(pager->msgSource, buf, DEC);
154 | det += spc + alignStr(buf, 7) + dev;
155 |
156 | ltoa(pager->enconding, buf, DEC);
157 | det += spc + alignStr(buf, 5) + dev;
158 |
159 | //ltoa(pager->inversion, buf, DEC);
160 | // det += spc + alignStr(buf, 4) + dev;
161 | buf[0] = pager->inversion==1?'y':'n';
162 | det += spc + alignStr(buf, 4) + dev;
163 | }
164 |
165 | Serial.println(det);
166 | det = "";
167 | }
168 |
169 | void printFixAdded(byte *arr) {
170 | Serial.print(F("Fixed IDs: "));
171 |
172 | for (byte i = 0; i < STORAGE_COUNT; i++) {
173 | if (arr[i] < 0xff) {
174 | Serial.print(arr[i]);
175 | Serial.print(F(" "));
176 | }
177 | }
178 |
179 | Serial.println(F(" "));
180 | }
181 |
182 | /**
183 | * Меню отправки на сохраненные устройства
184 | */
185 | void printSpecMode() {
186 | Serial.println(F("\r\r-----===[ Sending to saved devices ]===-----\r"));
187 | boolean header = true;
188 | struct Pager pager;
189 | for (byte i = 0; i < STORAGE_COUNT; i++) {
190 | getPager(i, &pager);
191 |
192 | if (pager.crc[0] == CRC[0] && pager.crc[1] == CRC[1]) {
193 | printPager(&pager, true, header);
194 | header = false;
195 | }
196 | }
197 | memset(&pager, 0, sizeof(Pager));
198 | Serial.println(F("\r to [ID ID] [send [text], numeric [0-9,-,*,\" \",(,)], tone] - Send message"));
199 | Serial.println(F(" to selected IDs"));
200 | Serial.println(F(" fix [ID ID] - select IDs (then just \"send [text]\")"));
201 | Serial.println(F(" 0 - go back"));
202 |
203 | Serial.println(String(F("\r Example: \"to 0 4 12 7 send Hello! Get out of here!\"")));
204 | Serial.println(String(F(" \"to 4 12 numeric 8-800-2000-600\"")));
205 | Serial.println(String(F(" \"to 3 5 tone\"")));
206 | printDiv();
207 | }
208 |
209 | /**
210 | * Меню операций с хранилищем
211 | */
212 | void printListMode() {
213 | Serial.println(F("\r\r\r-----===[ Stored list mode ]===-----\r"));
214 |
215 | boolean header = true;
216 | struct Pager pager;
217 | for (byte i = 0; i < STORAGE_COUNT; i++) {
218 | getPager(i, &pager);
219 | if (pager.crc[0] == CRC[0] && pager.crc[1] == CRC[1]) {
220 | printPager(&pager, true, header);
221 | header = false;
222 | }
223 | }
224 |
225 | Serial.println(F("\r add - add device"));
226 | Serial.println(F(" edit [ID] - edit device"));
227 | Serial.println(F(" del [ID] - remove device"));
228 | Serial.println(F(" 0 - go back"));
229 |
230 | printDiv();
231 | }
232 |
233 | /**
234 | * Функция добавления/редактирования пейджера
235 | */
236 | void printAddDevice(byte stepC, Pager* pager) { //stepC - for enter parametr
237 | if (pager->addr == 0xff) {
238 | // Create default params
239 |
240 | pager->cap = 0;
241 | pager->frequency = 0;
242 | pager->msgSource = 0;
243 | pager->enconding = 4;
244 | pager->inversion = 0;
245 | pager->rate = 1200;
246 | }
247 | int srs;
248 | long srsL;
249 | String arg = "";
250 | switch (stepC) {
251 | case 0: {
252 | reserBuf();
253 | if (pager->addr != 0xff) {
254 | arg = getCurStr() + pager->addr;
255 | }
256 | Serial.print(F("Enter ID (0-20)"));
257 | Serial.println(arg);
258 |
259 | while (Serial.available() == 0) {
260 | }
261 |
262 | if (pager->addr != 0xff && Serial.peek() == '\r') {
263 | printSet(String(pager->addr));
264 | printAddDevice(1, pager);
265 | return;
266 | }
267 |
268 | srs = Serial.parseInt();
269 |
270 | if (srs > 20 | srs < 0) {
271 | Serial.println(F("Incorrect data"));
272 | printAddDevice(0, pager);
273 | } else {
274 | pager->addr = srs;
275 | printSet(String(srs));
276 | printAddDevice(1, pager);
277 | }
278 |
279 | return;
280 | }
281 | case 1: {
282 | reserBuf();
283 | if (pager->cap > 0) {
284 | arg = getCurStr() + pager->cap;
285 | }
286 | Serial.print(F("Enter CAP"));
287 | Serial.println(arg);
288 |
289 | while (Serial.available() == 0) {
290 | }
291 |
292 |
293 | if (pager->cap > 0 && Serial.peek() == '\r') {
294 | printSet(String(pager->cap));
295 | printAddDevice(2, pager);
296 | return;
297 | }
298 |
299 | srsL = Serial.parseInt();
300 |
301 | if (srsL < 100 | srsL > 9999999) {
302 | Serial.println(F("Incorrect data"));
303 | printAddDevice(1, pager);
304 | } else {
305 | pager->cap = srsL;
306 | }
307 |
308 | printSet(String(pager->cap));
309 | printAddDevice(2, pager);
310 |
311 | return;
312 | }
313 |
314 | case 2: {
315 | reserBuf();
316 | Serial.print(F("Enter name (max 10 symbols)"));
317 | if (pager->alias[0] > 0) {
318 | arg = getCurStr() + pager->alias;
319 | }
320 | Serial.println(arg);
321 |
322 | while (Serial.available() == 0) {
323 | }
324 |
325 | if (pager->alias[0] > 0 && Serial.peek() == '\r') {
326 | printSet(String(pager->alias));
327 | printAddDevice(3, pager);
328 | return;
329 | }
330 |
331 | String alias = Serial.readString();
332 | alias.replace("\n", "");
333 | alias.replace("\r", "");
334 | alias.trim();
335 | alias.toCharArray(pager->alias, 10);
336 | printAddDevice(3, pager);
337 | return;
338 | }
339 |
340 | case 3: {
341 | reserBuf();
342 | if (pager->frequency > 0) {
343 | arg = getCurStr() + pager->frequency;
344 | }
345 |
346 | Serial.print(F("Enter frequency, kHz"));
347 | Serial.println(arg);
348 |
349 | while (Serial.available() == 0) {}
350 |
351 | if (pager->frequency > 0 && Serial.peek() == '\r') {
352 | printSet(String(pager->frequency));
353 | printAddDevice(4, pager);
354 | return;
355 | }
356 |
357 | srsL = Serial.readString().toInt();
358 |
359 | if (srsL < 100000 | srsL > 500000) {
360 | Serial.println(F("Incorrect data"));
361 | printAddDevice(3, pager);
362 | } else {
363 | pager->frequency = srsL;
364 | printSet(String(srsL ));
365 | printAddDevice(4, pager);
366 | }
367 |
368 | return;
369 | }
370 |
371 | case 4: {
372 | reserBuf();
373 |
374 | arg = getCurStr() + pager->msgSource;
375 | Serial.print(F("Enter source (0-3) or empty by default"));
376 | Serial.println(arg);
377 |
378 | while (Serial.available() == 0) {
379 | }
380 |
381 | if (Serial.peek() == '\r') {
382 | printSet(String(pager->msgSource));
383 | printAddDevice(5, pager);
384 | return;
385 | }
386 |
387 | srs = Serial.parseInt();
388 |
389 | if (srs >= 0 & srs <= 3) {
390 | pager->msgSource = srs;
391 | }
392 |
393 | printSet(String( pager->msgSource));
394 | printAddDevice(5, pager);
395 |
396 | return;
397 | }
398 |
399 | case 5: {
400 | reserBuf();
401 | arg = getCurStr() + pager->enconding;
402 | Serial.print(F("Enter enconding (0-EN Moto 1-EN/RU Moto 2-EN/RU Philips 3-RU Motorola)\r or empty by default"));
403 | Serial.println(arg);
404 |
405 |
406 | while (Serial.available() == 0) {
407 | }
408 |
409 | if (Serial.peek() == '\r') {
410 | printSet(String(pager->enconding));
411 | printAddDevice(6, pager);
412 | return;
413 | }
414 |
415 | srs = Serial.parseInt();
416 | if (srs > 0 & srs <= 3) {
417 | pager->enconding = srs;
418 | }
419 | printSet(String( pager->enconding));
420 | printAddDevice(6, pager);
421 |
422 | return;
423 | }
424 |
425 | case 6: {
426 | reserBuf();
427 |
428 | Serial.println(F("Enable inversion? Enter y/n or empty by default (n)"));
429 |
430 | while (Serial.available() == 0) {
431 | }
432 |
433 | if (Serial.peek() == '\r') {
434 | printSet(String(pager->inversion));
435 | printAddDevice(7, pager);
436 | return;
437 | }
438 |
439 |
440 | char s = Serial.readString().charAt(0);
441 | if (s == 'y') {
442 | pager->inversion = 1;
443 | } else {
444 | pager->inversion = 0;
445 | }
446 | printSet(String( pager->inversion == 1 ? "Yes" : "No"));
447 | printAddDevice(7, pager);
448 |
449 | return;
450 | }
451 |
452 | case 7: {
453 | reserBuf();
454 | arg = getCurStr() + pager->rate;
455 | Serial.print(F("Enter rate (512, 1200, 2400) or empty by default"));
456 | Serial.println(arg);
457 |
458 | while (Serial.available() == 0) {
459 | }
460 |
461 | if (Serial.peek() == '\r') {
462 | printSet(String(pager->rate));
463 | printAddDevice(8, pager);
464 | return;
465 | }
466 |
467 | srs = Serial.parseInt();
468 |
469 | if (srs == 512 | srs == 1200 | srs == 2400) {
470 | pager->rate = srs;
471 | }
472 |
473 | printSet(String(pager->rate));
474 | printAddDevice(8, pager);
475 | return;
476 | }
477 |
478 | case 8: {
479 | reserBuf();
480 | printPager(pager, true, true);
481 | Serial.println(F("\n\n [1] - Save, [2] - Cancel"));
482 | while (Serial.available() == 0) {
483 | }
484 | srs = Serial.parseInt();
485 | switch (srs) {
486 | case 1: {
487 | addPager(pager, false);
488 | // memset(&pager, 0, sizeof(Pager));
489 | Serial.println(F("Saved!\r\r\r"));
490 | printListMode();
491 | reserBuf();
492 | pauseCmd(0);
493 | break;
494 | }
495 | case 2: {
496 | reserBuf();
497 | pauseCmd(0);
498 | printListMode();
499 | break;
500 | }
501 | default: {
502 | reserBuf();
503 | Serial.println(F("Sorry?"));
504 | printAddDevice(8, pager);
505 | break;
506 | }
507 | }
508 |
509 | }
510 | }
511 | }
512 |
513 |
514 |
515 |
516 |
517 | void printSending() {
518 | Serial.println(F("Sending..."));
519 | }
520 |
521 | void printSent() {
522 | Serial.println(F("Message sent"));
523 | }
524 |
525 | void printTrError() {
526 | Serial.println(F("Transmit error =/"));
527 | }
528 |
--------------------------------------------------------------------------------
/UneversalPagerSender-arduino/UneversalPagerSender.ino:
--------------------------------------------------------------------------------
1 | /*
2 | POCSAG Universal Transmitter for Arduino Nano
3 |
4 | Extended by Hot Pixel 2022
5 |
6 | Based on https://github.com/SinuXVR/arduino-pocsag-transcoder
7 | Copyright (c) 2021, SinuX. All rights reserved.
8 |
9 | This library is distributed "as is" without any warranty.
10 | See MIT License for more details.
11 | */
12 | #include "Rf7021.h"
13 | #include "PocsagEncoder.h"
14 | #include "CmdProc.h"
15 | #include "Cmd.h"
16 | #include "Storage.h"
17 | #include
18 | #include "MemoryFree.h"
19 |
20 |
21 | // RF7021 Wiring
22 | #define RF_CE_PIN 6
23 | #define RF_SLE_PIN 7
24 | #define RF_SDATA_PIN 8
25 | #define RF_SREAD_PIN 9
26 | #define RF_SCLK_PIN 10
27 | #define RF_TX_CLK_PIN 11
28 | #define RF_TX_DATA_PIN 12
29 |
30 |
31 | // RF7021 settings
32 | //#define RF_TCXO 12287154UL // 12.288 MHz TCXO
33 | #define RF_TCXO 12288114UL // 12.288 MHz TCXO
34 | #define RF_PRINT_ADF_INFO // Read and print chip revision, temperature and voltage at startup
35 | #define RF_TEST_MODE 4 // Test mode - "010101..." pattern
36 | #define RF_TEST_DURATION 10000 // Test duration 10 seconds
37 |
38 | // Pocsag default settings
39 | #define PCSG_DEFAULT_DATA_RATE 1200 // 1200bps
40 | #define PCSG_DEFAULT_FREQ 160000000UL // 160.000 MHz
41 | #define PCSG_DEFAULT_FREQ_DEV 4500 // 4.5 KHz
42 | #define PCSG_DEFAULT_CAP_CODE 1234567 // 7th frame
43 | #define PCSG_DEFAULT_SOURCE 3 // Alphanumeric
44 | #define PCSG_DEFAULT_ENCODING 0 // Latin (Motorola)
45 |
46 | static byte fixedIDs[STORAGE_COUNT];
47 |
48 | Rf7021 rf = Rf7021();
49 | PocsagEncoder pocsagEncoder = PocsagEncoder();
50 |
51 |
52 | void resetFix() {
53 | for (int i = 0; i < STORAGE_COUNT; i++) {
54 | fixedIDs[i] = 0xFF;
55 | }
56 | }
57 | void resetDefaults() {
58 | rf.setDataRate(PCSG_DEFAULT_DATA_RATE);
59 | rf.setFrequency(PCSG_DEFAULT_FREQ);
60 | // Apply default encoder params
61 | pocsagEncoder.setCapCode(PCSG_DEFAULT_CAP_CODE);
62 | pocsagEncoder.setSource(PCSG_DEFAULT_SOURCE);
63 | pocsagEncoder.setEncodingId(PCSG_DEFAULT_ENCODING);
64 | }
65 |
66 | void setup() {
67 |
68 | // Set transmitter control pins
69 | rf.setCEPin(RF_CE_PIN);
70 | rf.setSLEPin(RF_SLE_PIN);
71 | rf.setSDATAPin(RF_SDATA_PIN);
72 | rf.setSREADPin(RF_SREAD_PIN);
73 | rf.setSCLKPin(RF_SCLK_PIN);
74 | rf.setTxRxCLKPin(RF_TX_CLK_PIN);
75 | rf.setTxRxDataPin(RF_TX_DATA_PIN);
76 |
77 |
78 | // Reset fixed IDs
79 | resetFix();
80 |
81 |
82 | // Apply default frequency and deviation
83 | rf.setXtalFrequency(RF_TCXO);
84 | rf.setHasExternalInductor(1);
85 |
86 | rf.setFrequencyDeviation(PCSG_DEFAULT_FREQ_DEV);
87 | rf.setPowerAmplifierEnabled(1);
88 | resetDefaults();
89 |
90 |
91 | cmdInit(9600);
92 |
93 | setWelcome();
94 | printFree();
95 | }
96 |
97 | void printFree() {
98 | // Serial.print(F("Free RAM = "));
99 | // Serial.println(freeMemory());
100 | }
101 |
102 |
103 | void transmit(String& msg, const Pager& pager, byte mode, byte raw) {
104 |
105 | rf.setFrequency(pager.frequency * 1000);
106 | rf.setDataInvertEnabled(pager.inversion);
107 | if (pager.rate != 1200 | pager.rate != 500 | pager.rate != 2400)
108 | rf.setDataRate(1200);
109 | else
110 | rf.setDataRate(pager.rate);
111 | pocsagEncoder.setCapCode(pager.cap);
112 | pocsagEncoder.setSource(pager.msgSource);
113 | pocsagEncoder.setEncodingId(pager.enconding);
114 |
115 | PocsagEncoder::PocsagMessage message;
116 | if (mode == 0)
117 | message = pocsagEncoder.encodeAlphanumeric(msg);
118 | else if (mode == 1)
119 | message = pocsagEncoder.encodeNumeric(msg);
120 | else if (mode == 2) {
121 | Serial.println(F("Dsnt work. Guru meditation..."));
122 | // message = pocsagEncoder.encodeTone();
123 | }
124 |
125 |
126 | Serial.print(String(F("Sending to ")));
127 | if (raw)
128 | Serial.print(pager.cap);
129 | else
130 | Serial.print(pager.alias);
131 | Serial.print(F("... "));
132 |
133 | if (rf.sendMessage(message.dataBytes, message.messageLength))
134 | printSent();
135 | else
136 | printTrError();
137 | }
138 |
139 | /**
140 | Отправка команды в ручном режиме
141 | */
142 | void sendCommands(int arg_cnt, char **args) {
143 | printFree();
144 | Pager pager;
145 | for (int i = 0; i < arg_cnt; i++) {
146 | String arg = String(args[i]);
147 |
148 | // Deviation
149 | if (arg == "d") {
150 | if (arg_cnt > i + 1) {
151 | uint32_t freqDev = atoi(args[i + 1]);
152 | if (freqDev == 0 | freqDev > 10000) {
153 | errorIn(F("d"));
154 | return;
155 | }
156 | rf.setFrequencyDeviation(freqDev);
157 | Serial.print(F("Frequency Deviation: "));
158 | Serial.print(freqDev / 1000.0, 2);
159 | Serial.println(F(" KHz"));
160 | } else {
161 | errorIn(F("d"));
162 | }
163 | }
164 |
165 |
166 | // Freq
167 | if (arg == "f") {
168 | if (arg_cnt > i + 1) {
169 | uint32_t freq = atol(args[i + 1]);
170 | if (freq >= 80000 && freq <= 950000) {
171 | pager.frequency = freq;
172 | rf.setFrequency(freq * 1000);
173 | Serial.print(F("Frequency: "));
174 | Serial.print(freq / 1000.0, 3);
175 | Serial.println(F(" MHz"));
176 | } else {
177 | Serial.println(freq);
178 | Serial.println(F("Wrong frequency, should be 80000 to 950000 kHz"));
179 | }
180 | } else {
181 | errorIn(F("f"));
182 | }
183 | }
184 |
185 | //Inversion
186 | if (arg == "i") {
187 | if (arg_cnt > i + 1) {
188 | byte inv = atoi(args[i + 1]);
189 | if (inv > 1) {
190 | errorIn(F("i"));
191 | return;
192 | } else {
193 | pager.inversion = inv;
194 | Serial.print(F("Inversion: "));
195 | Serial.println(inv ? F("enabled") : F("disabled"));
196 | }
197 | } else {
198 | errorIn(F("i"));
199 | }
200 | }
201 |
202 | // Baut
203 | if (arg == "r") {
204 | if (arg_cnt > i + 1) {
205 | word rate = atoi(args[i + 1]);
206 | if (rate == 512 || rate == 1200 || rate == 2400) {
207 | pager.rate = rate;
208 | Serial.print(F("Data rate: "));
209 | Serial.println(rate);
210 | } else {
211 | rf.setDataRate(rate);
212 | Serial.println(F("Wrong data rate, should be 512, 1200 or 2400"));
213 | }
214 | } else {
215 | errorIn(F("r"));
216 | }
217 | }
218 |
219 | // Test
220 | if (arg == "x") {
221 | Serial.println(F("Testing..."));
222 | rf.setFrequency(pager.frequency);
223 | rf.txTest(1, 15000);
224 | Serial.println(F("Test completed"));
225 | }
226 |
227 | // Тонкая подстройка частоты кварца.
228 | // Позволяет компенсировать погрешность кварца и "подтянуть" частоту передачи
229 | // к эталонной. После этой команды передается тестовый сигнал, который поможет
230 | // определить степень подстройки. После подстройки необходимо вписать полученное
231 | // значение в константу RF_TCXO
232 |
233 | // Увеличить частоту, Гц.
234 | if (arg == "h") {
235 | if (arg_cnt > i + 1) {
236 | int argUp = atoi(args[i + 1]);
237 | rf.setXtalFrequency(rf.getXtalFrequency() + argUp);
238 | Serial.println(rf.getXtalFrequency());
239 | rf.txTest(1, 3000);
240 | } else {
241 | errorIn(F("u"));
242 | }
243 | }
244 |
245 | // Понизить частоту, Гц
246 | if (arg == "l") {
247 | if (arg_cnt > i + 1) {
248 | int argUp = atoi(args[i + 1]);
249 | rf.setXtalFrequency(rf.getXtalFrequency() - argUp);
250 | Serial.println(rf.getXtalFrequency());
251 | rf.txTest(1, 3000);
252 | } else {
253 | errorIn(F("j"));
254 | }
255 | }
256 |
257 | // CAP
258 | if (arg == "c") {
259 | if (arg_cnt > i + 1) {
260 | uint32_t cap = atol(args[i + 1]);
261 | if (cap <= 9999999) {
262 | pager.cap = cap;
263 | Serial.print(F("CAP code: "));
264 | Serial.println(cap);
265 | } else {
266 | Serial.println(F("Wrong CAP"));
267 |
268 | return;
269 | }
270 | } else {
271 | errorIn(F("c"));
272 | }
273 | }
274 |
275 | // Source code
276 | if (arg == "s") {
277 | if (arg_cnt > i + 1) {
278 | byte src = atoi(args[i + 1]);
279 | if (src <= 3) {
280 | pager.msgSource = src;
281 | Serial.print(F("Source code: "));
282 | Serial.println(src);
283 | } else {
284 | Serial.println(F("Wrong source code, should be 0, 1, 2 or 3"));
285 |
286 | return;
287 | }
288 | } else {
289 | errorIn(F("s"));
290 | }
291 | }
292 |
293 |
294 | // Encoding
295 | if (arg == "e") {
296 | if (arg_cnt > i + 1) {
297 | byte enc = atoi(args[i + 1]);
298 | if (enc <= 3) {
299 | pager.enconding = enc;
300 | Serial.print(F("Encoding: "));
301 | Serial.print(enc);
302 | Serial.println(enc == 0 ? F(" (EN Motorola)") : enc == 1 ? F(" (EN/RU Motorola)") : enc == 2 ? F(" (EN/RU Philips)") : enc == 3 ? F(" (RU Motorola)") : F(" (Unknown)"));
303 | } else {
304 | Serial.println(F("Wrong encoding, should be 0, 1, 2 or 3"));
305 |
306 | return;
307 | }
308 | } else {
309 | errorIn(F("e"));
310 | }
311 | }
312 |
313 | // Send numeric message
314 | if (arg == "n") {
315 | if (arg_cnt > i + 1) {
316 | String msg = args[i + 1];
317 | transmit(msg, pager, 1, 1);
318 | delay(30);
319 | } else {
320 | errorIn(F("n"));
321 | }
322 | }
323 |
324 | // Send text message
325 | if (arg == "m") {
326 | printFree();
327 | if (arg_cnt > i + 1) {
328 |
329 | String msg = "";
330 | for (int ii = i + 1; ii < arg_cnt; ii++) {
331 | msg = msg + String(args[ii]) + " ";
332 | }
333 |
334 | transmit(msg, pager, 0, 1);
335 | delay(30);
336 | printFree();
337 | } else {
338 | Serial.println(F("Message empty"));
339 | }
340 | break;
341 | }
342 |
343 |
344 | // Send tone message
345 | if (arg == "t") {
346 | // PocsagEncoder::PocsagMessage message = pocsagEncoder.encodeTone();
347 | // printSending();
348 | // rf.sendMessage(message.dataBytes, message.messageLength);
349 |
350 | String msg = "";
351 | transmit(msg, pager, 2, 1);
352 | printSent();
353 | }
354 | }
355 | }
356 |
357 | /**
358 | Фиксация нужных пейджеров (для отпавки одного сообщения на несколько устройств)
359 | */
360 | void addFixedIDs(int arg_cnt, char **args) {
361 | if (arg_cnt == 1) {
362 | Serial.println(F("No IDs.."));
363 | return;
364 | }
365 | resetFix();
366 | for (byte i = 1; i < arg_cnt; i++) {
367 | fixedIDs[i - 1] = atoi( args[i]);
368 | }
369 | printFixAdded(fixedIDs);
370 | }
371 |
372 |
373 | /**
374 | Отправка на зафиксированные пейджеры
375 | */
376 | void sendToFixed(int arg_cnt, char **args) {
377 |
378 | if (arg_cnt == 1) {
379 | Serial.println(F("Message not found"));
380 | return;
381 | }
382 |
383 | if (fixedIDs[0] == 0xff) {
384 | Serial.println(F("Set IDs first"));
385 | return;
386 | }
387 |
388 | String msg = "";
389 | for (byte i = 1; i < arg_cnt; i++) {
390 | for (int ii = i + 1; ii < arg_cnt; ii++) {
391 | msg += String(args[ii]) + " ";
392 | }
393 | }
394 |
395 | for (int i = 0; i < STORAGE_COUNT ; i++) {
396 | if (fixedIDs[i] == 0xff)
397 | continue;
398 |
399 | Pager pager;
400 | getPager(fixedIDs[i], &pager);
401 |
402 | // if detect pager struct
403 | if (pager.crc[0] == CRC[0] && pager.crc[1] == CRC[1]) {
404 | transmit(msg, pager, 0, 0);
405 | } else {
406 | Serial.println(String(F("ID not found: ")) + args[i]);
407 | }
408 | delay(30);
409 | }
410 | printFree();
411 | }
412 |
413 | void sendSpecCmdTo(int arg_cnt, char **args) {
414 | String msg = "";
415 | int indexMsg = -1;
416 | byte mode = 0; // 0 - text, 1 - numeric, 2 - tone
417 |
418 | // Ищем тело сообщения
419 | for (byte i = 0; i < arg_cnt; i++) {
420 | if ((strcmp(args[i], "send") == 0 | strcmp(args[i], "numeric") == 0) && arg_cnt > i + 1) {
421 | indexMsg = i;
422 | if (strcmp(args[i], "send") == 0)
423 | mode = 0;
424 | else
425 | mode = 1;
426 | for (int ii = i + 1; ii < arg_cnt; ii++) {
427 | msg = msg + String(args[ii]) + " ";
428 | }
429 | break;
430 | }
431 | // if Tone mode
432 | if (strcmp(args[i], "tone") == 0) {
433 | indexMsg = i;
434 | mode = 2;
435 | }
436 | }
437 |
438 | if (mode != 2 && indexMsg < 0) {
439 | errorIn(F("Message not found"));
440 | return;
441 | }
442 |
443 | // Ищем IDы
444 | if (indexMsg < 2) {
445 | errorIn(F("IDs not found"));
446 | return;
447 | }
448 | printFree();
449 |
450 | for (int i = 1; i < indexMsg; i++) {
451 | Pager pager;
452 | getPager(atoi(args[i]), &pager);
453 |
454 |
455 | if (pager.crc[0] == CRC[0] && pager.crc[1] == CRC[1]) {
456 | transmit(msg, pager, mode, 0);
457 | delay(30);
458 | } else {
459 | Serial.println(String(F("ID not found: ")) + args[1]);
460 | }
461 | printFree();
462 | }
463 | }
464 |
465 |
466 | /**
467 | Режим приветствия
468 | */
469 | void setWelcome() {
470 | printFree();
471 | printWelcome(rf);
472 | clearCmd();
473 | cmdAdd("1", setFreeMode);
474 | cmdAdd("2", setSpecMode);
475 | cmdAdd("3", setSavedPagers);
476 | cmdAdd("0", setWelcome);
477 | cmdAdd("send", sendCommands);
478 | cmdAdd("testfreq", startTestFreq);
479 | cmdAdd("testrate", startRateTest);
480 | printFree();
481 | }
482 |
483 | /**
484 | Режим отправки на сохраненные устройства
485 | */
486 | void setSpecMode() {
487 | printSpecMode();
488 | clearCmd();
489 | cmdAdd("to", sendSpecCmdTo);
490 | cmdAdd("fix", addFixedIDs);
491 | cmdAdd("send", sendToFixed);
492 | cmdAdd("0", setWelcome);
493 | printFree();
494 | }
495 |
496 |
497 | void addDevice() {
498 | struct Pager pager;
499 | pager.addr = -1;
500 | printAddDevice(0, &pager);
501 | }
502 |
503 | void removeDevice(int arg_cnt, char **args) {
504 | if (arg_cnt == 1) {
505 | return;
506 | }
507 | struct Pager pager;
508 | getPager(atoi(args[1]), &pager);
509 | addPager(&pager, true);
510 | setSavedPagers() ;
511 | }
512 |
513 |
514 | void editDevice(int arg_cnt, char **args) {
515 | if (arg_cnt == 0) {
516 | return;
517 | }
518 | pauseCmd(1);
519 | struct Pager pager ;
520 | getPager(String(args[1]).toInt(), &pager);
521 | printAddDevice(0, &pager);
522 | }
523 |
524 | void setSavedPagers() {
525 | printListMode();
526 | clearCmd();
527 | cmdAdd("add", addDevice);
528 | cmdAdd("del", removeDevice);
529 | cmdAdd("edit", editDevice);
530 | cmdAdd("0", setWelcome );
531 | printFree();
532 | }
533 |
534 |
535 | void setFreeMode() {
536 | printFreeMode();
537 | clearCmd();
538 | cmdAdd("full", printFreeModeAdv);
539 | cmdAdd("0", setWelcome);
540 | cmdAdd("send", sendCommands);
541 | printFree();
542 | }
543 |
544 | /**
545 | Тест для поиска точной частоты приемника
546 | Базовой установленной частоте дается гистерезис 20 кГц
547 | и производится цикличная отправка с текстом текущей частоты
548 | */
549 | void startTestFreq() {
550 | long fr = rf.getFrequency() - 20000;
551 | for (int i = 0; i < 40; i = i + 1) {
552 | fr += 1000;
553 | rf.setFrequency(fr);
554 | PocsagEncoder::PocsagMessage message = pocsagEncoder.encodeAlphanumeric(String(fr / 1000));
555 | Serial.println(String("sending ") + (fr / 1000));
556 | rf.sendMessage(message.dataBytes, message.messageLength);
557 | delay(20);
558 | }
559 | Serial.println(String("Complete."));
560 | }
561 |
562 | /**
563 | Тест для поиска рабочей скорости передачи.
564 | Если используется кварц без термостабилизации (не TCXO),
565 | возможен фактический уход таймингов от установленных
566 | */
567 | void startRateTest() {
568 | word rate = 1190;
569 | for (int i = 0; i < 20; i = i + 1) {
570 | rate = rate + 1;
571 | rf.setDataRate(rate);
572 | PocsagEncoder::PocsagMessage message = pocsagEncoder.encodeAlphanumeric(String(rate));
573 | Serial.println(String("sending ") + (rate));
574 | rf.sendMessage(message.dataBytes, message.messageLength);
575 | delay(130);
576 | }
577 | Serial.println(String("sending "));
578 | }
579 |
580 |
581 | void unrecognized()
582 | {
583 | Serial.println(F("Sorry?"));
584 | }
585 |
586 | void errorIn(const & msg) {
587 | Serial.print(F("Error in ") );
588 | Serial.println(msg);
589 | }
590 |
591 |
592 | void loop() {
593 | cmdPoll();
594 | }
595 |
--------------------------------------------------------------------------------