Advertisement
edovino

Feld-Hell sender

Mar 10th, 2025 (edited)
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 9.30 KB | None | 0 0
  1. #include <WiFi.h>
  2. #include <WebServer.h>
  3. #include <DNSServer.h>
  4.  
  5. // Define the radio pins
  6. int radioPin = 8;   // GPIO8 for the encoded signal
  7. int audioPin = 10;  // GPIO10 for the 1 kHz tone
  8.  
  9. // Define the glyph structure and table
  10. typedef struct glyph {
  11.   char ch;
  12.   word col[7];
  13. } Glyph;
  14.  
  15. const Glyph glyphtab[] PROGMEM = {
  16.   { ' ', { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 } },
  17.   { 'A', { 0x07fc, 0x0e60, 0x0c60, 0x0e60, 0x07fc, 0x0000, 0x0000 } },
  18.   { 'B', { 0x0c0c, 0x0ffc, 0x0ccc, 0x0ccc, 0x0738, 0x0000, 0x0000 } },
  19.   { 'C', { 0x0ffc, 0x0c0c, 0x0c0c, 0x0c0c, 0x0c0c, 0x0000, 0x0000 } },
  20.   { 'D', { 0x0c0c, 0x0ffc, 0x0c0c, 0x0c0c, 0x07f8, 0x0000, 0x0000 } },
  21.   { 'E', { 0x0ffc, 0x0ccc, 0x0ccc, 0x0c0c, 0x0c0c, 0x0000, 0x0000 } },
  22.   { 'F', { 0x0ffc, 0x0cc0, 0x0cc0, 0x0c00, 0x0c00, 0x0000, 0x0000 } },
  23.   { 'G', { 0x0ffc, 0x0c0c, 0x0c0c, 0x0ccc, 0x0cfc, 0x0000, 0x0000 } },
  24.   { 'H', { 0x0ffc, 0x00c0, 0x00c0, 0x00c0, 0x0ffc, 0x0000, 0x0000 } },
  25.   { 'I', { 0x0ffc, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 } },
  26.   { 'J', { 0x003c, 0x000c, 0x000c, 0x000c, 0x0ffc, 0x0000, 0x0000 } },
  27.   { 'K', { 0x0ffc, 0x00c0, 0x00e0, 0x0330, 0x0e1c, 0x0000, 0x0000 } },
  28.   { 'L', { 0x0ffc, 0x000c, 0x000c, 0x000c, 0x000c, 0x0000, 0x0000 } },
  29.   { 'M', { 0x0ffc, 0x0600, 0x0300, 0x0600, 0x0ffc, 0x0000, 0x0000 } },
  30.   { 'N', { 0x0ffc, 0x0700, 0x01c0, 0x0070, 0x0ffc, 0x0000, 0x0000 } },
  31.   { 'O', { 0x0ffc, 0x0c0c, 0x0c0c, 0x0c0c, 0x0ffc, 0x0000, 0x0000 } },
  32.   { 'P', { 0x0c0c, 0x0ffc, 0x0ccc, 0x0cc0, 0x0780, 0x0000, 0x0000 } },
  33.   { 'Q', { 0x0ffc, 0x0c0c, 0x0c3c, 0x0ffc, 0x000f, 0x0000, 0x0000 } },
  34.   { 'R', { 0x0ffc, 0x0cc0, 0x0cc0, 0x0cf0, 0x079c, 0x0000, 0x0000 } },
  35.   { 'S', { 0x078c, 0x0ccc, 0x0ccc, 0x0ccc, 0x0c78, 0x0000, 0x0000 } },
  36.   { 'T', { 0x0c00, 0x0c00, 0x0ffc, 0x0c00, 0x0c00, 0x0000, 0x0000 } },
  37.   { 'U', { 0x0ff8, 0x000c, 0x000c, 0x000c, 0x0ff8, 0x0000, 0x0000 } },
  38.   { 'V', { 0x0ffc, 0x0038, 0x00e0, 0x0380, 0x0e00, 0x0000, 0x0000 } },
  39.   { 'W', { 0x0ff8, 0x000c, 0x00f8, 0x000c, 0x0ff8, 0x0000, 0x0000 } },
  40.   { 'X', { 0x0e1c, 0x0330, 0x01e0, 0x0330, 0x0e1c, 0x0000, 0x0000 } },
  41.   { 'Y', { 0x0e00, 0x0380, 0x00fc, 0x0380, 0x0e00, 0x0000, 0x0000 } },
  42.   { 'Z', { 0x0c1c, 0x0c7c, 0x0ccc, 0x0f8c, 0x0e0c, 0x0000, 0x0000 } },
  43.   { '0', { 0x07f8, 0x0c0c, 0x0c0c, 0x0c0c, 0x07f8, 0x0000, 0x0000 } },
  44.   { '1', { 0x0300, 0x0600, 0x0ffc, 0x0000, 0x0000, 0x0000, 0x0000 } },
  45.   { '2', { 0x061c, 0x0c3c, 0x0ccc, 0x078c, 0x000c, 0x0000, 0x0000 } },
  46.   { '3', { 0x0006, 0x1806, 0x198c, 0x1f98, 0x00f0, 0x0000, 0x0000 } },
  47.   { '4', { 0x1fe0, 0x0060, 0x0060, 0x0ffc, 0x0060, 0x0000, 0x0000 } },
  48.   { '5', { 0x000c, 0x000c, 0x1f8c, 0x1998, 0x18f0, 0x0000, 0x0000 } },
  49.   { '6', { 0x07fc, 0x0c66, 0x18c6, 0x00c6, 0x007c, 0x0000, 0x0000 } },
  50.   { '7', { 0x181c, 0x1870, 0x19c0, 0x1f00, 0x1c00, 0x0000, 0x0000 } },
  51.   { '8', { 0x0f3c, 0x19e6, 0x18c6, 0x19e6, 0x0f3c, 0x0000, 0x0000 } },
  52.   { '9', { 0x0f80, 0x18c6, 0x18cc, 0x1818, 0x0ff0, 0x0000, 0x0000 } },
  53.   { '*', { 0x018c, 0x0198, 0x0ff0, 0x0198, 0x018c, 0x0000, 0x0000 } },
  54.   { '.', { 0x001c, 0x001c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 } },
  55.   { '?', { 0x1800, 0x1800, 0x19ce, 0x1f00, 0x0000, 0x0000, 0x0000 } },
  56.   { '!', { 0x1f9c, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 } },
  57.   { '(', { 0x01e0, 0x0738, 0x1c0e, 0x0000, 0x0000, 0x0000, 0x0000 } },
  58.   { ')', { 0x1c0e, 0x0738, 0x01e0, 0x0000, 0x0000, 0x0000, 0x0000 } },
  59.   { '#', { 0x0330, 0x0ffc, 0x0330, 0x0ffc, 0x0330, 0x0000, 0x0000 } },
  60.   { '$', { 0x078c, 0x0ccc, 0x1ffe, 0x0ccc, 0x0c78, 0x0000, 0x0000 } },
  61.   { '/', { 0x001c, 0x0070, 0x01c0, 0x0700, 0x1c00, 0x0000, 0x0000 } }
  62. };
  63.  
  64. #define NGLYPHS (sizeof(glyphtab) / sizeof(glyphtab[0]))
  65.  
  66. // Web server and DNS server
  67. WebServer server(80);
  68. DNSServer dnsServer;
  69.  
  70. // Variables
  71. String text = "";
  72. String binaryString = "";
  73. bool isSending = false;
  74. unsigned long lastTransmitTime = 0;
  75. int currentBitIndex = 0;
  76.  
  77. // Function to compile text into a binary string
  78. String compileTextToBinary(const char *text) {
  79.   String binaryString = "";
  80.   for (int i = 0; text[i] != '\0'; i++) {
  81.     char ch = text[i];
  82.     Serial.print(ch);
  83.     Serial.print(" -> ");
  84.     for (int j = 0; j < NGLYPHS; j++) {
  85.       if (pgm_read_byte(&glyphtab[j].ch) == ch) {
  86.         for (int x = 0; x < 7; x++) {
  87.           word col = pgm_read_word(&glyphtab[j].col[x]);
  88.           for (int y = 0; y < 14; y++) {
  89.             binaryString += (col & (1 << y)) ? '1' : '0';
  90.             Serial.print((col & (1 << y)) ? '1' : '0');
  91.           }
  92.         }
  93.         break;
  94.       }
  95.     }
  96.     Serial.println();
  97.   }
  98.   Serial.println("Total:" + binaryString);
  99.   return binaryString;
  100. }
  101.  
  102. // Function to transmit one bit
  103. void transmitBit(char bit) {
  104.   digitalWrite(radioPin, bit == '1' ? HIGH : LOW);
  105.  
  106.   // Modulate GPIO10 with 1 kHz tone when GPIO8 is HIGH
  107.   if (bit == '1') {
  108.     tone(audioPin, 1000);  // Generate 1 kHz tone
  109.   } else {
  110.     noTone(audioPin);  // Turn off the tone
  111.   }
  112. }
  113.  
  114. // Web interface handlers
  115. void handleRoot() {
  116.   String html = "<!DOCTYPE html>"
  117.                 "<html>"
  118.                 "<head>"
  119.                 "<title>Feld-Hell Transmitter</title>"
  120.                 "<style>"
  121.                 "body { font-family: Arial, sans-serif; text-align: center; margin-top: 50px; }"
  122.                 "textarea { width: 300px; height: 100px; margin-bottom: 20px; }"
  123.                 "#sendButton { padding: 10px 20px; font-size: 16px; cursor: pointer; border: none; border-radius: 5px; color: white; }"
  124.                 ".green { background-color: green; }"
  125.                 ".red { background-color: red; }"
  126.                 ".disabled { background-color: #ccc; cursor: not-allowed; }"
  127.                 "</style>"
  128.                 "<script>"
  129.                 "function toggleSend() {"
  130.                 "const text = document.getElementById('text').value.toUpperCase();"
  131.                 "const sendButton = document.getElementById('sendButton');"
  132.                 "const textArea = document.getElementById('text');"
  133.                 "if (sendButton.classList.contains('green')) {"
  134.                 "fetch('/send', {"
  135.                 "method: 'POST',"
  136.                 "headers: { 'Content-Type': 'application/x-www-form-urlencoded' },"
  137.                 "body: 'text=' + encodeURIComponent(text)"
  138.                 "}).then(response => {"
  139.                 "if (response.ok) {"
  140.                 "sendButton.classList.remove('green');"
  141.                 "sendButton.classList.add('red');"
  142.                 "sendButton.textContent = 'Stop Sending';"
  143.                 "textArea.disabled = true;"
  144.                 "textArea.classList.add('disabled');"
  145.                 "}"
  146.                 "});"
  147.                 "} else {"
  148.                 "fetch('/stop').then(response => {"
  149.                 "if (response.ok) {"
  150.                 "sendButton.classList.remove('red');"
  151.                 "sendButton.classList.add('green');"
  152.                 "sendButton.textContent = 'Send';"
  153.                 "textArea.disabled = false;"
  154.                 "textArea.classList.remove('disabled');"
  155.                 "}"
  156.                 "});"
  157.                 "}"
  158.                 "}"
  159.                 "</script>"
  160.                 "</head>"
  161.                 "<body>"
  162.                 "<h1>Feld-Hell Transmitter</h1>"
  163.                 "<textarea id=\"text\" placeholder=\"Enter text here\"></textarea><br>"
  164.                 "<button id=\"sendButton\" class=\"green\" onclick=\"toggleSend()\">Send</button>"
  165.                 "</body>"
  166.                 "</html>";
  167.   server.send(200, "text/html", html);
  168. }
  169.  
  170. void handleSend() {
  171.   if (server.hasArg("text")) {
  172.     text = server.arg("text");
  173.     binaryString = compileTextToBinary(text.c_str());
  174.     isSending = true;
  175.     currentBitIndex = 0;
  176.     lastTransmitTime = micros();  // Use micros() for precise timing
  177.     server.send(200, "text/plain", "Sending started");
  178.   } else {
  179.     server.send(400, "text/plain", "Error: No text provided");
  180.   }
  181. }
  182.  
  183. void handleStop() {
  184.   isSending = false;
  185.   digitalWrite(radioPin, LOW);  // Ensure the signal ends low
  186.   noTone(audioPin);             // Ensure the tone is turned off
  187.   server.send(200, "text/plain", "Sending stopped");
  188. }
  189.  
  190. void setup() {
  191.   digitalWrite(LED_BUILTIN, LOW);
  192.  
  193.   // Start Serial communication
  194.   Serial.begin(115200);
  195.   while (!Serial) delay(100);  // wait until serial is up
  196.  
  197.   // Set the radio and audio pins as output
  198.   pinMode(radioPin, OUTPUT);
  199.   pinMode(audioPin, OUTPUT);
  200.  
  201.   // Start Wi-Fi access point
  202.   WiFi.softAP("Feld-Hell Transmitter");
  203.   IPAddress IP = WiFi.softAPIP();
  204.   Serial.println("Access Point IP: " + IP.toString());
  205.  
  206.   // Start DNS server for captive portal
  207.   dnsServer.start(53, "*", IP);
  208.  
  209.   // Set up web server routes
  210.   server.on("/", handleRoot);
  211.   server.on("/send", HTTP_POST, handleSend);
  212.   server.on("/stop", handleStop);
  213.  
  214.   // Start the web server
  215.   server.begin();
  216.   digitalWrite(LED_BUILTIN, HIGH);
  217. }
  218.  
  219. void loop() {
  220.   // Handle DNS and web server requests
  221.   dnsServer.processNextRequest();
  222.   server.handleClient();
  223.  
  224.   // Non-blocking transmission with precise timing
  225.   if (isSending && (micros() - lastTransmitTime >= 4080)) {
  226.     if (currentBitIndex < binaryString.length()) {
  227.       transmitBit(binaryString[currentBitIndex]);
  228.       currentBitIndex++;
  229.     } else {
  230.       // Restart transmission from the beginning
  231.       currentBitIndex = 0;
  232.     }
  233.     lastTransmitTime = micros();  // Reset the timer
  234.   }
  235. }
  236.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement