First commit

master
cheetah 5 years ago
commit dfb7af9459

5
.gitignore vendored

@ -0,0 +1,5 @@
.pio
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json
.vscode/ipch

@ -0,0 +1,67 @@
# Continuous Integration (CI) is the practice, in software
# engineering, of merging all developer working copies with a shared mainline
# several times a day < https://docs.platformio.org/page/ci/index.html >
#
# Documentation:
#
# * Travis CI Embedded Builds with PlatformIO
# < https://docs.travis-ci.com/user/integration/platformio/ >
#
# * PlatformIO integration with Travis CI
# < https://docs.platformio.org/page/ci/travis.html >
#
# * User Guide for `platformio ci` command
# < https://docs.platformio.org/page/userguide/cmd_ci.html >
#
#
# Please choose one of the following templates (proposed below) and uncomment
# it (remove "# " before each line) or use own configuration according to the
# Travis CI documentation (see above).
#
#
# Template #1: General project. Test it using existing `platformio.ini`.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio run
#
# Template #2: The project is intended to be used as a library with examples.
#
# language: python
# python:
# - "2.7"
#
# sudo: false
# cache:
# directories:
# - "~/.platformio"
#
# env:
# - PLATFORMIO_CI_SRC=path/to/test/file.c
# - PLATFORMIO_CI_SRC=examples/file.ino
# - PLATFORMIO_CI_SRC=path/to/test/directory
#
# install:
# - pip install -U platformio
# - platformio update
#
# script:
# - platformio ci --lib="." --board=ID_1 --board=ID_2 --board=ID_N

@ -0,0 +1,7 @@
{
// See http://go.microsoft.com/fwlink/?LinkId=827846
// for the documentation about the extensions.json format
"recommendations": [
"platformio.platformio-ide"
]
}

@ -0,0 +1,51 @@
{
"terminal.integrated.env.windows": {
"PATH": "C:\\Users\\BadWoofsky\\.platformio\\penv\\Scripts;C:\\Users\\BadWoofsky\\.platformio\\penv;C:\\Program Files\\ImageMagick-7.0.8-Q16;C:\\Program Files (x86)\\Common Files\\Intel\\Shared Libraries\\redist\\intel64_win\\compiler;M:\\TBuild\\ThirdParty\\Ninja;M:\\TBuild\\ThirdParty\\gyp;M:\\TBuild\\ThirdParty\\Perl\\site\\bin;M:\\TBuild\\ThirdParty\\Perl\\bin;C:\\Program Files\\Java\\jdk1.8.0_211\\bin;C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\libnvvp;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.2\\bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.2\\libnvvp;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\PuTTY\\;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd;C:\\Program Files\\Microsoft VS Code\\bin;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files (x86)\\Common Files\\Adobe\\AG;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;M:\\AndroidSDKs\\tools;M:\\AndroidSDKs\\platform-tools;C:\\Program Files\\nodejs\\;C:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;C:\\Python27\\;C:\\Users\\BadWoofsky\\AppData\\Local\\Programs\\Python\\Python36\\Scripts\\;C:\\Users\\BadWoofsky\\AppData\\Local\\Programs\\Python\\Python36\\;C:\\Users\\BadWoofsky\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Program Files\\Microsoft VS Code\\bin;C:\\Users\\BadWoofsky\\AppData\\Local\\Programs\\Fiddler;C:\\Program Files\\nodejs\\;C:\\Users\\BadWoofsky\\Documents\\Tensorflow Projekte\\cuda\\bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\bin;C:\\Users\\BadWoofsky\\Downloads\\Documents\\Tensorflow Projekte\\cuda\\bin;C:\\Users\\BadWoofsky\\AppData\\Local\\Microsoft\\WindowsApps;G:\\ALT\\PATH;M:\\PremFoto\\buildenv\\apache-ant-1.10.6\\bin;C:\\Users\\BadWoofsky\\AppData\\Roaming\\npm;C:\\Program Files\\ImageMagick-7.0.8-Q16;C:\\Program Files (x86)\\Common Files\\Intel\\Shared Libraries\\redist\\intel64_win\\compiler;M:\\TBuild\\ThirdParty\\Ninja;M:\\TBuild\\ThirdParty\\gyp;M:\\TBuild\\ThirdParty\\Perl\\site\\bin;M:\\TBuild\\ThirdParty\\Perl\\bin;C:\\Program Files\\Java\\jdk1.8.0_211\\bin;C:\\Program Files (x86)\\Common Files\\Oracle\\Java\\javapath;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\libnvvp;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.2\\bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.2\\libnvvp;C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\;C:\\Program Files\\PuTTY\\;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files\\Git\\cmd;C:\\Program Files\\Microsoft VS Code\\bin;C:\\WINDOWS\\system32;C:\\WINDOWS;C:\\WINDOWS\\System32\\Wbem;C:\\WINDOWS\\System32\\WindowsPowerShell\\v1.0\\;C:\\WINDOWS\\System32\\OpenSSH\\;C:\\Program Files (x86)\\Common Files\\Adobe\\AG;C:\\Program Files (x86)\\NVIDIA Corporation\\PhysX\\Common;M:\\AndroidSDKs\\tools;M:\\AndroidSDKs\\platform-tools;C:\\Program Files\\nodejs\\;C:\\Program Files\\NVIDIA Corporation\\NVIDIA NvDLISR;C:\\Python27\\;C:\\Users\\BadWoofsky\\AppData\\Local\\Programs\\Python\\Python36\\Scripts\\;C:\\Users\\BadWoofsky\\AppData\\Local\\Programs\\Python\\Python36\\;C:\\Users\\BadWoofsky\\AppData\\Local\\Microsoft\\WindowsApps;C:\\Program Files\\Microsoft VS Code\\bin;C:\\Users\\BadWoofsky\\AppData\\Local\\Programs\\Fiddler;C:\\Program Files\\nodejs\\;C:\\Users\\BadWoofsky\\Documents\\Tensorflow Projekte\\cuda\\bin;C:\\Program Files\\NVIDIA GPU Computing Toolkit\\CUDA\\v9.0\\bin;C:\\Users\\BadWoofsky\\Downloads\\Documents\\Tensorflow Projekte\\cuda\\bin;C:\\Users\\BadWoofsky\\AppData\\Local\\Microsoft\\WindowsApps;G:\\ALT\\PATH;M:\\PremFoto\\buildenv\\apache-ant-1.10.6\\bin;C:\\Users\\BadWoofsky\\AppData\\Roaming\\npm",
"PLATFORMIO_CALLER": "vscode"
},
"C_Cpp.errorSquiggles": "Disabled",
"files.associations": {
"system_error": "cpp",
"string": "cpp",
"array": "cpp",
"*.tcc": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"memory": "cpp",
"new": "cpp",
"ostream": "cpp",
"numeric": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"streambuf": "cpp",
"cinttypes": "cpp",
"utility": "cpp",
"typeinfo": "cpp"
}
}

@ -0,0 +1,39 @@
This directory is intended for project header files.
A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.
```src/main.c
#include "header.h"
int main (void)
{
...
}
```
Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.
In C, the usual convention is to give header files names that end with `.h'.
It is most portable to use only letters, digits, dashes, and underscores in
header file names, and at most one dot.
Read more about using header files in official GCC documentation:
* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html

@ -0,0 +1,46 @@
This directory is intended for project specific (private) libraries.
PlatformIO will compile them to static libraries and link into executable file.
The source code of each library should be placed in a an own separate directory
("lib/your_library_name/[here are source files]").
For example, see a structure of the following two libraries `Foo` and `Bar`:
|--lib
| |
| |--Bar
| | |--docs
| | |--examples
| | |--src
| | |- Bar.c
| | |- Bar.h
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
| |
| |--Foo
| | |- Foo.c
| | |- Foo.h
| |
| |- README --> THIS FILE
|
|- platformio.ini
|--src
|- main.c
and a contents of `src/main.c`:
```
#include <Foo.h>
#include <Bar.h>
int main (void)
{
...
}
```
PlatformIO Library Dependency Finder will find automatically dependent
libraries scanning project source files.
More information about PlatformIO Library Dependency Finder
- https://docs.platformio.org/page/librarymanager/ldf.html

@ -0,0 +1,16 @@
;PlatformIO Project Configuration File
;
; Build options: build flags, source filter
; Upload options: custom upload port, speed and extra flags
; Library options: dependencies, extra library storages
; Advanced options: extra scripting
;
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:nodemcu-32s]
platform = espressif32
board = nodemcu-32s
framework = arduino
upload_speed = 921600
monitor_speed = 57600 ; 115200 ;57600

@ -0,0 +1,378 @@
#include <cuddlycheetah.pocsag.h>
/**
* Calculate the CRC error checking code for the given word.
* Messages use a 10 bit CRC computed from the 21 data bits.
* This is calculated through a binary polynomial long division, returning
* the remainder.
* See https://en.wikipedia.org/wiki/Cyclic_redundancy_check#Computation
* for more information.
*/
uint32_t crc(uint32_t inputMsg) {
//Align MSB of denominatorerator with MSB of message
uint32_t denominator = CRC_GENERATOR << 20;
//Message is right-padded with zeroes to the message length + crc length
uint32_t msg = inputMsg << CRC_BITS;
//We iterate until denominator has been right-shifted back to it's original value.
for (int column = 0; column <= 20; column++) {
//Bit for the column we're aligned to
int msgBit = (msg >> (30 - column)) & 1;
//If the current bit is zero, we don't modify the message this iteration
if (msgBit != 0) {
//While we would normally subtract in long division, we XOR here.
msg ^= denominator;
}
//Shift the denominator over to align with the next column
denominator >>= 1;
}
//At this point 'msg' contains the CRC value we've calculated
return msg & 0x3FF;
}
/**
* Calculates the even parity bit for a message.
* If the number of bits in the message is even, return 0, else return 1.
*/
uint32_t parity(uint32_t x) {
//Our parity bit
uint32_t p = 0;
//We xor p with each bit of the input value. This works because
//xoring two one-bits will cancel out and leave a zero bit. Thus
//xoring any even number of one bits will result in zero, and xoring
//any odd number of one bits will result in one.
for (int i = 0; i < 32; i++) {
p ^= (x & 1);
x >>= 1;
}
return p;
}
/**
* Encodes a 21-bit message by calculating and adding a CRC code and parity bit.
*/
uint32_t encodeCodeword(uint32_t msg) {
uint32_t fullCRC = (msg << CRC_BITS) | crc(msg);
uint32_t p = parity(fullCRC);
return (fullCRC << 1) | p;
}
/**
* ASCII encode a null-terminated string as a series of codewords, written
* to (*out). Returns the number of codewords written. Caller should ensure
* that enough memory is allocated in (*out) to contain the message
*
* initial_offset indicates which word in the current batch the function is
* beginning at, so that it can insert SYNC words at appropriate locations.
*/
uint32_t encodeASCII(uint32_t initial_offset, char* str, uint32_t strLen, uint32_t* out) {
//Number of words written to *out
uint32_t numWordsWritten = 0;
//Data for the current word we're writing
uint32_t currentWord = 0;
//Nnumber of bits we've written so far to the current word
uint32_t currentNumBits = 0;
//Position of current word in the current batch
uint32_t wordPosition = initial_offset;
// while (*str != 0) {
for (int x = 0; x < strLen; x++) {
unsigned char c = *str;
str++;
//Encode the character bits backwards
for (int i = 0; i < TEXT_BITS_PER_CHAR; i++) {
currentWord <<= 1;
currentWord |= (c >> i) & 1;
currentNumBits++;
if (currentNumBits == TEXT_BITS_PER_WORD) {
//Add the MESSAGE flag to our current word and encode it.
*out = encodeCodeword(currentWord | FLAG_MESSAGE);
out++;
currentWord = 0;
currentNumBits = 0;
numWordsWritten++;
wordPosition++;
if (wordPosition == BATCH_SIZE) {
//We've filled a full batch, time to insert a SYNC word
//and start a new one.
*out = SYNC;
out++;
numWordsWritten++;
wordPosition = 0;
}
}
}
}
//Write remainder of message
if (currentNumBits > 0) {
//Pad out the word to 20 bits with zeroes
currentWord <<= 20 - currentNumBits;
*out = encodeCodeword(currentWord | FLAG_MESSAGE);
out++;
numWordsWritten++;
wordPosition++;
if (wordPosition == BATCH_SIZE) {
//We've filled a full batch, time to insert a SYNC word
//and start a new one.
*out = SYNC;
out++;
numWordsWritten++;
wordPosition = 0;
}
}
return numWordsWritten;
}
// Char Translationtable
char* mirrorTab = new char[10]{ 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, 0x01, 0x09 };
char encodeDigit(char ch) {
if (ch >= '0' && ch <= '9')
return mirrorTab[ch - '0'];
switch (ch) {
case ' ':
return 0x03;
case 'u':
case 'U':
return 0x0d;
case '-':
case '_':
return 0x0b;
case '(':
case '[':
return 0x0f;
case ')':
case ']':
return 0x07;
}
return 0x05;
}
uint32_t encodeNumeric(uint32_t initial_offset, char* str, uint32_t strLen, uint32_t* out) {
//Number of words written to *out
uint32_t numWordsWritten = 0;
//Data for the current word we're writing
uint32_t currentWord = 0;
//Nnumber of bits we've written so far to the current word
uint32_t currentNumBits = 0;
//Position of current word in the current batch
uint32_t wordPosition = initial_offset;
Serial.print("ENCODE NUMERIC="); Serial.println(strLen);
// while (*str != 0) {
for (int x = 0; x < strLen; x++) {
unsigned char c = *str;
str++;
//Encode the digit bits backwards
for (int i = 0; i < NUMERIC_BITS_PER_DIGIT; i++) {
currentWord <<= 1;
char digit = encodeDigit(c);
digit = ((digit & 1) <<3) |
((digit & 2) <<1) |
((digit & 4) >>1) |
((digit & 8)>>3);
currentWord |= (digit >> i) & 1;
currentNumBits++;
if (currentNumBits == NUMERIC_BITS_PER_WORD) {
//Add the MESSAGE flag to our current word and encode it.
*out = encodeCodeword(currentWord | FLAG_MESSAGE);
out++;
currentWord = 0;
currentNumBits = 0;
numWordsWritten++;
wordPosition++;
if (wordPosition == BATCH_SIZE) {
//We've filled a full batch, time to insert a SYNC word
//and start a new one.
*out = SYNC;
out++;
numWordsWritten++;
wordPosition = 0;
}
}
}
}
//Write remainder of message
if (currentNumBits > 0) {
//Pad out the word to 20 bits with zeroes
currentWord <<= 20 - currentNumBits;
*out = encodeCodeword(currentWord | FLAG_MESSAGE);
out++;
numWordsWritten++;
wordPosition++;
if (wordPosition == BATCH_SIZE) {
//We've filled a full batch, time to insert a SYNC word
//and start a new one.
*out = SYNC;
out++;
numWordsWritten++;
wordPosition = 0;
}
}
return numWordsWritten;
}
/**
* An address of 21 bits, but only 18 of those bits are encoded in the address
* word itself. The remaining 3 bits are derived from which frame in the batch
* is the address word. This calculates the number of words (not frames!)
* which must precede the address word so that it is in the right spot. These
* words will be filled with the idle value.
*/
int addressOffset(int address) {
return (address & 0x7) * FRAME_SIZE;
}
/**
* Encode a full text POCSAG transmission addressed to (address).
* (*message) is a null terminated C string.
* (*out) is the destination to which the transmission will be written.
*/
void encodeTransmission(bool numeric, int address, int fb, char* message, uint32_t strLen, uint32_t* out) {
//Encode preamble
//Alternating 1,0,1,0 bits for 576 bits, used for receiver to synchronize
//with transmitter
for (int i = 0; i < PREAMBLE_LENGTH / 32; i++) {
*out = 0xAAAAAAAA;
out++;
}
uint32_t* start = out;
//Sync
*out = SYNC;
out++;
//Write out padding before adderss word
int prefixLength = addressOffset(address);
for (int i = 0; i < prefixLength; i++) {
*out = IDLE;
out++;
}
//Write address word.
//The last two bits of word's data contain the message type (function bits)
//The 3 least significant bits are dropped, as those are encoded by the
//word's location.
*out = encodeCodeword( ((address >> 3) << 2) | fb);
out++;
//Encode the message itself
Serial.print("ENCODE TRANSMISSION="); Serial.println(strLen);
if (numeric == true) {
out += encodeNumeric(addressOffset(address) + 1, message, strLen, out);
} else {
out += encodeASCII(addressOffset(address) + 1, message, strLen, out);
}
//Finally, write an IDLE word indicating the end of the message
*out = IDLE;
out++;
//Pad out the last batch with IDLE to write multiple of BATCH_SIZE + 1
//words (+ 1 is there because of the SYNC words)
size_t written = out - start;
size_t padding = (BATCH_SIZE + 1) - written % (BATCH_SIZE + 1);
for (size_t i = 0; i < padding; i++) {
*out = IDLE;
out++;
}
}
/**
* Calculates the length in words of a text POCSAG message, given the address
* and the number of characters to be transmitted.
*/
size_t textMessageLength(int address, int numChars) {
size_t numWords = 0;
//Padding before address word.
numWords += addressOffset(address);
//Address word itself
numWords++;
//numChars * 7 bits per character / 20 bits per word, rounding up
numWords += (numChars * TEXT_BITS_PER_CHAR + (TEXT_BITS_PER_WORD - 1))
/ TEXT_BITS_PER_WORD;
//Idle word representing end of message
numWords++;
//Pad out last batch with idles
numWords += BATCH_SIZE - (numWords % BATCH_SIZE);
//Batches consist of 16 words each and are preceded by a sync word.
//So we add one word for every 16 message words
numWords += numWords / BATCH_SIZE;
//Preamble of 576 alternating 1,0,1,0 bits before the message
//Even though this comes first, we add it to the length last so it
//doesn't affect the other word-based calculations
numWords += PREAMBLE_LENGTH / 32;
return numWords;
}
/**
* Calculates the length in words of a numeric POCSAG message, given the address
* and the number of characters to be transmitted.
*/
size_t numericMessageLength(int address, int numChars) {
size_t numWords = 0;
//Padding before address word.
numWords += addressOffset(address);
//Address word itself
numWords++;
//numChars * 7 bits per character / 20 bits per word, rounding up
numWords += (numChars * NUMERIC_BITS_PER_DIGIT + (NUMERIC_BITS_PER_WORD - 1))
/ NUMERIC_BITS_PER_WORD;
//Idle word representing end of message
numWords++;
//Pad out last batch with idles
numWords += BATCH_SIZE - (numWords % BATCH_SIZE);
//Batches consist of 16 words each and are preceded by a sync word.
//So we add one word for every 16 message words
numWords += numWords / BATCH_SIZE;
//Preamble of 576 alternating 1,0,1,0 bits before the message
//Even though this comes first, we add it to the length last so it
//doesn't affect the other word-based calculations
numWords += PREAMBLE_LENGTH / 32;
return numWords;
}

@ -0,0 +1,39 @@
#include <Arduino.h>
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
#define SYNC 0x7CD215D8
#define IDLE 0x7A89C197
#define FRAME_SIZE 2
#define BATCH_SIZE 16
#define PREAMBLE_LENGTH 576
#define FLAG_ADDRESS 0x000000
#define FLAG_MESSAGE 0x100000
#define FLAG_TEXT_DATA 0x3
#define FLAG_NUMERIC_DATA 0x0
#define TEXT_BITS_PER_WORD 20
#define TEXT_BITS_PER_CHAR 7
#define NUMERIC_BITS_PER_WORD 20
#define NUMERIC_BITS_PER_DIGIT 4
#define CRC_BITS 10
#define CRC_GENERATOR 0b11101101001
uint32_t crc(uint32_t inputMsg);
uint32_t parity(uint32_t x);
uint32_t encodeCodeword(uint32_t msg);
uint32_t encodeASCII(uint32_t initial_offset, char* str, uint32_t strLen, uint32_t* out);
// Char Translationtable
char encodeDigit(char ch);
uint32_t encodeNumeric(uint32_t initial_offset, char* str, uint32_t strLen, uint32_t* out);
int addressOffset(int address);
void encodeTransmission(bool numeric, int address, int fb, char* message, uint32_t strLen, uint32_t* out);
size_t textMessageLength(int address, int numChars);
size_t numericMessageLength(int address, int numChars);

@ -0,0 +1,162 @@
#include <Arduino.h>
#pragma region "Bluetooth"
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <BLE2902.h>
// BLE UUIDs
#define GENERIC_DISPLAY 0x1811
#define SERVICE_180A_UUID "0000180a-0000-1000-8000-00805f9b34fb"
#define SERVICE_CCCC_UUID "0000CCCC-CCCC-CCCC-1337-00805f9b34fb"
static const BLEUUID ALERT_DISPLAY_SERVICE_UUID = BLEUUID("3db02924-b2a6-4d47-be1f-0f90ad62a048");
static const BLEUUID DISPLAY_MESSAGE_CHARACTERISTIC_UUID = BLEUUID("8d8218b6-97bc-4527-a8db-13094ac06b1d");
// #define BUFF_LEN 140
// char* payload = new char[BUFF_LEN];
class MyServerCallback: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
//todo display `connected` on the screen
Serial.println("LE onConnect");
// memset(payload, 0x00, BUFF_LEN);
/*connected = true;
hasLongText = false;
hasText = false;
hasTimeText = false;
yScrollPos = 0;*/
}
void onDisconnect(BLEServer* pServer) {
// todo display `disconnected` on the screen
Serial.println("LE onDisconnect");
//connected = false;
}
};
void emulatePOCSAG(const char* msg);
class DisplayCharacteristicCallback: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* pCharacteristic) {
// write text to OLED
std::string str = pCharacteristic->getValue();
BLEUUID uuid = pCharacteristic->getUUID();
std::string uuid_s = uuid.toString();
Serial.print("onWrite() {uuid=");
Serial.print(String(uuid_s.c_str()));
Serial.print(",len=");
Serial.print(str.length());
Serial.println("}");
Serial.println(str.c_str());
emulatePOCSAG(str.c_str());
}
};
void setupBT() {
BLEDevice::init("CC-Bluetooth-Pager");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallback());
BLEService *pServiceDeviceInfo = pServer->createService(SERVICE_180A_UUID);
BLECharacteristic *pCharacteristicDeviceInfo_ManufacturerName = new BLECharacteristic((uint16_t)0x2A29,BLECharacteristic::PROPERTY_READ);
pCharacteristicDeviceInfo_ManufacturerName->setValue("CuddlyCheetah");
pServiceDeviceInfo->addCharacteristic(pCharacteristicDeviceInfo_ManufacturerName);
pServiceDeviceInfo->start();
BLEService *pService = pServer->createService(SERVICE_CCCC_UUID);
BLECharacteristic *pCharacteristicText = new BLECharacteristic(DISPLAY_MESSAGE_CHARACTERISTIC_UUID, BLECharacteristic::PROPERTY_WRITE_NR); //Request MTU=500 from client
pCharacteristicText->setCallbacks(new DisplayCharacteristicCallback());
pService->addCharacteristic(pCharacteristicText);;
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->setAppearance(GENERIC_DISPLAY); //Generic Display
pAdvertising->setScanResponse(true);
/*pAdvertising->setMinPreferred(0x06); // functions that help with iPhone connections issue
pAdvertising->setMinPreferred(0x12);*/
pAdvertising->start();
Serial.println("Waiting a client connection to notify...");
BLEDevice::startAdvertising();
}
#pragma endregion
#pragma region "POCSAG"
#include <cuddlycheetah.pocsag.h>
#define BAUDPAUSE 1000000 / 1200
#define POCSAG_PIN 19
#define FUNCTION_BITS 3
#define CAPCODE 924395
#define IS_NUMERIC true
#define INVERTED false
void setupPOCSAG() {
pinMode(POCSAG_PIN, OUTPUT);
digitalWrite(POCSAG_PIN, 1);
}
// to simulate some activity
void emulatePOCSAG(const char* msg) {
char* message = (char*)msg;
Serial.print("emulatePOCSAG "); Serial.println(message);
Serial.print("length="); Serial.println(strlen(message));
size_t messageLength = IS_NUMERIC
? numericMessageLength(CAPCODE, strlen(message))
: textMessageLength(CAPCODE, strlen(message));
uint32_t* transmission = (uint32_t*) malloc(sizeof(uint32_t) * messageLength+2);
int Sym=0;
// https://raw.githubusercontent.com/nkolban/ESP32_BLE_Arduino/master/examples/BLE_server_multiconnect/BLE_server_multiconnect.ino
encodeTransmission(IS_NUMERIC, CAPCODE, FUNCTION_BITS, message, strlen(message), transmission);
char *pocsagData=(char *)malloc(messageLength*32 + 1);
//Serial.println("generating");
for (int i = 0;i < messageLength; i++) {
if (!INVERTED) transmission[i] = ~transmission[i];
for (int j = 31; j >= 0; j--) {
pocsagData[Sym] = (transmission[i] >> j) & 0x1 == 1 ? '1' : '0';
Sym++;
}
}
pocsagData[Sym] = 0x00;
for (const char* p = pocsagData; *p; p++) {
bool bit = (*p == '1');
Serial.print(bit ? '1' :'0');
}
for (const char* p = pocsagData; *p; p++) {
bool bit = (*p == '1');
digitalWrite(POCSAG_PIN, bit);
delayMicroseconds(1000000 / 1200);
}
/*Serial.println("");
Serial.println("transmitting");
for (int i = 0; i < messageLength * 32; i++) {
digitalWrite(POCSAG_PIN, TabSymbol[i]);
Serial.print(TabSymbol[i] ? '1' : '0');
delayMicroseconds(BAUDPAUSE);
}*/
delayMicroseconds(BAUDPAUSE);
digitalWrite(POCSAG_PIN, 1);
}
void fakePOCSAG() {
for (int i = 0; i < PREAMBLE_LENGTH / 32; i++) {
digitalWrite(POCSAG_PIN, i % 2 == 0);
delayMicroseconds(BAUDPAUSE);
}
delayMicroseconds(BAUDPAUSE);
digitalWrite(POCSAG_PIN, 1);
}
#pragma endregion
void setup() {
Serial.begin(57600);
Serial.println('Bluetooth Empfänger V1 - by <@cuddlycheetah>');
setupBT();
setupPOCSAG();
emulatePOCSAG("42");
}
void loop() {
}

@ -0,0 +1,11 @@
This directory is intended for PIO Unit Testing and project tests.
Unit Testing is a software testing method by which individual units of
source code, sets of one or more MCU program modules together with associated
control data, usage procedures, and operating procedures, are tested to
determine whether they are fit for use. Unit testing finds problems early
in the development cycle.
More information about PIO Unit Testing:
- https://docs.platformio.org/page/plus/unit-testing.html
Loading…
Cancel
Save