diff --git a/firmware/application/CMakeLists.txt b/firmware/application/CMakeLists.txt index 0892fda4..197dc5bb 100644 --- a/firmware/application/CMakeLists.txt +++ b/firmware/application/CMakeLists.txt @@ -141,6 +141,7 @@ set(CPPSRC ${COMMON}/bch_code.cpp bht.cpp ctcss.cpp + dcs.cpp encoder.cpp freqman.cpp rds.cpp @@ -155,7 +156,7 @@ set(CPPSRC ui_afsksetup.cpp ui_alphanum.cpp ui_audio.cpp - ui_audiotx.cpp + ui_mictx.cpp ui_baseband_stats_view.cpp ui_bht_tx.cpp ui_channel.cpp diff --git a/firmware/application/baseband_api.cpp b/firmware/application/baseband_api.cpp index 27a7e8df..24067603 100644 --- a/firmware/application/baseband_api.cpp +++ b/firmware/application/baseband_api.cpp @@ -255,4 +255,9 @@ void replay_stop() { send_message(&message); } +void request_beep() { + RequestSignalMessage message { RequestSignalMessage::Signal::BeepRequest }; + send_message(&message); +} + } /* namespace baseband */ diff --git a/firmware/application/baseband_api.hpp b/firmware/application/baseband_api.hpp index 303c1318..1f3089c2 100644 --- a/firmware/application/baseband_api.hpp +++ b/firmware/application/baseband_api.hpp @@ -72,6 +72,7 @@ void set_adsb(); void set_jammer(const bool run, const jammer::JammerType type, const uint32_t speed); void set_rds_data(const uint16_t message_length); void set_spectrum(const size_t sampling_rate, const size_t trigger); +void request_beep(); void run_image(const portapack::spi_flash::image_tag_t image_tag); void shutdown(); diff --git a/firmware/application/dcs.cpp b/firmware/application/dcs.cpp new file mode 100644 index 00000000..95bfaf1f --- /dev/null +++ b/firmware/application/dcs.cpp @@ -0,0 +1,547 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "dcs.hpp" + +namespace dcs { + +const uint16_t dcs_parity[DCS_CODES_NB] = { + 0b11000111010, // 0 + 0b01001001111, // 1 + 0b01010100101, // 2 + 0b11011010000, // 3 + 0b01101110001, // 4 + 0b11100000100, // 5 + 0b11111101110, // 6 + 0b01110011011, // 7 + 0b00011011001, // 8 + 0b10010101100, // 9 + 0b10001000110, // 10 + 0b00000110011, // 11 + 0b10110010010, // 12 + 0b00111100111, // 13 + 0b00100001101, // 14 + 0b10101111000, // 15 + 0b11110001001, // 16 + 0b01111111100, // 17 + 0b01100010110, // 18 + 0b11101100011, // 19 + 0b01011000010, // 20 + 0b11010110111, // 21 + 0b11001011101, // 22 + 0b01000101000, // 23 + 0b00101101010, // 24 + 0b10100011111, // 25 + 0b10111110101, // 26 + 0b00110000000, // 27 + 0b10000100001, // 28 + 0b00001010100, // 29 + 0b00010111110, // 30 + 0b10011001011, // 31 + 0b10101011100, // 32 + 0b00100101001, // 33 + 0b00111000011, // 34 + 0b10110110110, // 35 + 0b00000010111, // 36 + 0b10001100010, // 37 + 0b10010001000, // 38 + 0b00011111101, // 39 + 0b01110111111, // 40 + 0b11111001010, // 41 + 0b11100100000, // 42 + 0b01101010101, // 43 + 0b11011110100, // 44 + 0b01010000001, // 45 + 0b01001101011, // 46 + 0b11000011110, // 47 + 0b10011101111, // 48 + 0b00010011010, // 49 + 0b00001110000, // 50 + 0b10000000101, // 51 + 0b00110100100, // 52 + 0b10111010001, // 53 + 0b10100111011, // 54 + 0b00101001110, // 55 + 0b01000001100, // 56 + 0b11001111001, // 57 + 0b11010010011, // 58 + 0b01011100110, // 59 + 0b11101000111, // 60 + 0b01100110010, // 61 + 0b01111011000, // 62 + 0b11110101101, // 63 + 0b00011110110, // 64 + 0b10010000011, // 65 + 0b10001101001, // 66 + 0b00000011100, // 67 + 0b10110111101, // 68 + 0b00111001000, // 69 + 0b00100100010, // 70 + 0b10101010111, // 71 + 0b11000010101, // 72 + 0b01001100000, // 73 + 0b01010001010, // 74 + 0b11011111111, // 75 + 0b01101011110, // 76 + 0b11100101011, // 77 + 0b11111000001, // 78 + 0b01110110100, // 79 + 0b00101000101, // 80 + 0b10100110000, // 81 + 0b10111011010, // 82 + 0b00110101111, // 83 + 0b10000001110, // 84 + 0b00001111011, // 85 + 0b00010010001, // 86 + 0b10011100100, // 87 + 0b11110100110, // 88 + 0b01111010011, // 89 + 0b01100111001, // 90 + 0b11101001100, // 91 + 0b01011101101, // 92 + 0b11010011000, // 93 + 0b11001110010, // 94 + 0b01000000111, // 95 + 0b01110010000, // 96 + 0b11111100101, // 97 + 0b11100001111, // 98 + 0b01101111010, // 99 + 0b11011011011, // 100 + 0b01010101110, // 101 + 0b01001000100, // 102 + 0b11000110001, // 103 + 0b10101110011, // 104 + 0b00100000110, // 105 + 0b00111101100, // 106 + 0b10110011001, // 107 + 0b00000111000, // 108 + 0b10001001101, // 109 + 0b10010100111, // 110 + 0b00011010010, // 111 + 0b01000100011, // 112 + 0b11001010110, // 113 + 0b11010111100, // 114 + 0b01011001001, // 115 + 0b11101101000, // 116 + 0b01100011101, // 117 + 0b01111110111, // 118 + 0b11110000010, // 119 + 0b10011000000, // 120 + 0b00010110101, // 121 + 0b00001011111, // 122 + 0b10000101010, // 123 + 0b00110001011, // 124 + 0b10111111110, // 125 + 0b10100010100, // 126 + 0b00101100001, // 127 + 0b11111010111, // 128 + 0b01110100010, // 129 + 0b01101001000, // 130 + 0b11100111101, // 131 + 0b01010011100, // 132 + 0b11011101001, // 133 + 0b11000000011, // 134 + 0b01001110110, // 135 + 0b00100110100, // 136 + 0b10101000001, // 137 + 0b10110101011, // 138 + 0b00111011110, // 139 + 0b10001111111, // 140 + 0b00000001010, // 141 + 0b00011100000, // 142 + 0b10010010101, // 143 + 0b11001100100, // 144 + 0b01000010001, // 145 + 0b01011111011, // 146 + 0b11010001110, // 147 + 0b01100101111, // 148 + 0b11101011010, // 149 + 0b11110110000, // 150 + 0b01111000101, // 151 + 0b00010000111, // 152 + 0b10011110010, // 153 + 0b10000011000, // 154 + 0b00001101101, // 155 + 0b10111001100, // 156 + 0b00110111001, // 157 + 0b00101010011, // 158 + 0b10100100110, // 159 + 0b10010110001, // 160 + 0b00011000100, // 161 + 0b00000101110, // 162 + 0b10001011011, // 163 + 0b00111111010, // 164 + 0b10110001111, // 165 + 0b10101100101, // 166 + 0b00100010000, // 167 + 0b01001010010, // 168 + 0b11000100111, // 169 + 0b11011001101, // 170 + 0b01010111000, // 171 + 0b11100011001, // 172 + 0b01101101100, // 173 + 0b01110000110, // 174 + 0b11111110011, // 175 + 0b10100000010, // 176 + 0b00101110111, // 177 + 0b00110011101, // 178 + 0b10111101000, // 179 + 0b00001001001, // 180 + 0b10000111100, // 181 + 0b10011010110, // 182 + 0b00010100011, // 183 + 0b01111100001, // 184 + 0b11110010100, // 185 + 0b11101111110, // 186 + 0b01100001011, // 187 + 0b11010101010, // 188 + 0b01011011111, // 189 + 0b01000110101, // 190 + 0b11001000000, // 191 + 0b00100011011, // 192 + 0b10101101110, // 193 + 0b10110000100, // 194 + 0b00111110001, // 195 + 0b10001010000, // 196 + 0b00000100101, // 197 + 0b00011001111, // 198 + 0b10010111010, // 199 + 0b11111111000, // 200 + 0b01110001101, // 201 + 0b01101100111, // 202 + 0b11100010010, // 203 + 0b01010110011, // 204 + 0b11011000110, // 205 + 0b11000101100, // 206 + 0b01001011001, // 207 + 0b00010101000, // 208 + 0b10011011101, // 209 + 0b10000110111, // 210 + 0b00001000010, // 211 + 0b10111100011, // 212 + 0b00110010110, // 213 + 0b00101111100, // 214 + 0b10100001001, // 215 + 0b11001001011, // 216 + 0b01000111110, // 217 + 0b01011010100, // 218 + 0b11010100001, // 219 + 0b01100000000, // 220 + 0b11101110101, // 221 + 0b11110011111, // 222 + 0b01111101010, // 223 + 0b01001111101, // 224 + 0b11000001000, // 225 + 0b11011100010, // 226 + 0b01010010111, // 227 + 0b11100110110, // 228 + 0b01101000011, // 229 + 0b01110101001, // 230 + 0b11111011100, // 231 + 0b10010011110, // 232 + 0b00011101011, // 233 + 0b00000000001, // 234 + 0b10001110100, // 235 + 0b00111010101, // 236 + 0b10110100000, // 237 + 0b10101001010, // 238 + 0b00100111111, // 239 + 0b01111001110, // 240 + 0b11110111011, // 241 + 0b11101010001, // 242 + 0b01100100100, // 243 + 0b11010000101, // 244 + 0b01011110000, // 245 + 0b01000011010, // 246 + 0b11001101111, // 247 + 0b10100101101, // 248 + 0b00101011000, // 249 + 0b00110110010, // 250 + 0b10111000111, // 251 + 0b00001100110, // 252 + 0b10000010011, // 253 + 0b10011111001, // 254 + 0b00010001100, // 255 + 0b10111100000, // 256 + 0b00110010101, // 257 + 0b00101111111, // 258 + 0b10100001010, // 259 + 0b00010101011, // 260 + 0b10011011110, // 261 + 0b10000110100, // 262 + 0b00001000001, // 263 + 0b01100000011, // 264 + 0b11101110110, // 265 + 0b11110011100, // 266 + 0b01111101001, // 267 + 0b11001001000, // 268 + 0b01000111101, // 269 + 0b01011010111, // 270 + 0b11010100010, // 271 + 0b10001010011, // 272 + 0b00000100110, // 273 + 0b00011001100, // 274 + 0b10010111001, // 275 + 0b00100011000, // 276 + 0b10101101101, // 277 + 0b10110000111, // 278 + 0b00111110010, // 279 + 0b01010110000, // 280 + 0b11011000101, // 281 + 0b11000101111, // 282 + 0b01001011010, // 283 + 0b11111111011, // 284 + 0b01110001110, // 285 + 0b01101100100, // 286 + 0b11100010001, // 287 + 0b11010000110, // 288 + 0b01011110011, // 289 + 0b01000011001, // 290 + 0b11001101100, // 291 + 0b01111001101, // 292 + 0b11110111000, // 293 + 0b11101010010, // 294 + 0b01100100111, // 295 + 0b00001100101, // 296 + 0b10000010000, // 297 + 0b10011111010, // 298 + 0b00010001111, // 299 + 0b10100101110, // 300 + 0b00101011011, // 301 + 0b00110110001, // 302 + 0b10111000100, // 303 + 0b11100110101, // 304 + 0b01101000000, // 305 + 0b01110101010, // 306 + 0b11111011111, // 307 + 0b01001111110, // 308 + 0b11000001011, // 309 + 0b11011100001, // 310 + 0b01010010100, // 311 + 0b00111010110, // 312 + 0b10110100011, // 313 + 0b10101001001, // 314 + 0b00100111100, // 315 + 0b10010011101, // 316 + 0b00011101000, // 317 + 0b00000000010, // 318 + 0b10001110111, // 319 + 0b01100101100, // 320 + 0b11101011001, // 321 + 0b11110110011, // 322 + 0b01111000110, // 323 + 0b11001100111, // 324 + 0b01000010010, // 325 + 0b01011111000, // 326 + 0b11010001101, // 327 + 0b10111001111, // 328 + 0b00110111010, // 329 + 0b00101010000, // 330 + 0b10100100101, // 331 + 0b00010000100, // 332 + 0b10011110001, // 333 + 0b10000011011, // 334 + 0b00001101110, // 335 + 0b01010011111, // 336 + 0b11011101010, // 337 + 0b11000000000, // 338 + 0b01001110101, // 339 + 0b11111010100, // 340 + 0b01110100001, // 341 + 0b01101001011, // 342 + 0b11100111110, // 343 + 0b10001111100, // 344 + 0b00000001001, // 345 + 0b00011100011, // 346 + 0b10010010110, // 347 + 0b00100110111, // 348 + 0b10101000010, // 349 + 0b10110101000, // 350 + 0b00111011101, // 351 + 0b00001001010, // 352 + 0b10000111111, // 353 + 0b10011010101, // 354 + 0b00010100000, // 355 + 0b10100000001, // 356 + 0b00101110100, // 357 + 0b00110011110, // 358 + 0b10111101011, // 359 + 0b11010101001, // 360 + 0b01011011100, // 361 + 0b01000110110, // 362 + 0b11001000011, // 363 + 0b01111100010, // 364 + 0b11110010111, // 365 + 0b11101111101, // 366 + 0b01100001000, // 367 + 0b00111111001, // 368 + 0b10110001100, // 369 + 0b10101100110, // 370 + 0b00100010011, // 371 + 0b10010110010, // 372 + 0b00011000111, // 373 + 0b00000101101, // 374 + 0b10001011000, // 375 + 0b11100011010, // 376 + 0b01101101111, // 377 + 0b01110000101, // 378 + 0b11111110000, // 379 + 0b01001010001, // 380 + 0b11000100100, // 381 + 0b11011001110, // 382 + 0b01010111011, // 383 + 0b10000001101, // 384 + 0b00001111000, // 385 + 0b00010010010, // 386 + 0b10011100111, // 387 + 0b00101000110, // 388 + 0b10100110011, // 389 + 0b10111011001, // 390 + 0b00110101100, // 391 + 0b01011101110, // 392 + 0b11010011011, // 393 + 0b11001110001, // 394 + 0b01000000100, // 395 + 0b11110100101, // 396 + 0b01111010000, // 397 + 0b01100111010, // 398 + 0b11101001111, // 399 + 0b10110111110, // 400 + 0b00111001011, // 401 + 0b00100100001, // 402 + 0b10101010100, // 403 + 0b00011110101, // 404 + 0b10010000000, // 405 + 0b10001101010, // 406 + 0b00000011111, // 407 + 0b01101011101, // 408 + 0b11100101000, // 409 + 0b11111000010, // 410 + 0b01110110111, // 411 + 0b11000010110, // 412 + 0b01001100011, // 413 + 0b01010001001, // 414 + 0b11011111100, // 415 + 0b11101101011, // 416 + 0b01100011110, // 417 + 0b01111110100, // 418 + 0b11110000001, // 419 + 0b01000100000, // 420 + 0b11001010101, // 421 + 0b11010111111, // 422 + 0b01011001010, // 423 + 0b00110001000, // 424 + 0b10111111101, // 425 + 0b10100010111, // 426 + 0b00101100010, // 427 + 0b10011000011, // 428 + 0b00010110110, // 429 + 0b00001011100, // 430 + 0b10000101001, // 431 + 0b11011011000, // 432 + 0b01010101101, // 433 + 0b01001000111, // 434 + 0b11000110010, // 435 + 0b01110010011, // 436 + 0b11111100110, // 437 + 0b11100001100, // 438 + 0b01101111001, // 439 + 0b00000111011, // 440 + 0b10001001110, // 441 + 0b10010100100, // 442 + 0b00011010001, // 443 + 0b10101110000, // 444 + 0b00100000101, // 445 + 0b00111101111, // 446 + 0b10110011010, // 447 + 0b01011000001, // 448 + 0b11010110100, // 449 + 0b11001011110, // 450 + 0b01000101011, // 451 + 0b11110001010, // 452 + 0b01111111111, // 453 + 0b01100010101, // 454 + 0b11101100000, // 455 + 0b10000100010, // 456 + 0b00001010111, // 457 + 0b00010111101, // 458 + 0b10011001000, // 459 + 0b00101101001, // 460 + 0b10100011100, // 461 + 0b10111110110, // 462 + 0b00110000011, // 463 + 0b01101110010, // 464 + 0b11100000111, // 465 + 0b11111101101, // 466 + 0b01110011000, // 467 + 0b11000111001, // 468 + 0b01001001100, // 469 + 0b01010100110, // 470 + 0b11011010011, // 471 + 0b10110010001, // 472 + 0b00111100100, // 473 + 0b00100001110, // 474 + 0b10101111011, // 475 + 0b00011011010, // 476 + 0b10010101111, // 477 + 0b10001000101, // 478 + 0b00000110000, // 479 + 0b00110100111, // 480 + 0b10111010010, // 481 + 0b10100111000, // 482 + 0b00101001101, // 483 + 0b10011101100, // 484 + 0b00010011001, // 485 + 0b00001110011, // 486 + 0b10000000110, // 487 + 0b11101000100, // 488 + 0b01100110001, // 489 + 0b01111011011, // 490 + 0b11110101110, // 491 + 0b01000001111, // 492 + 0b11001111010, // 493 + 0b11010010000, // 494 + 0b01011100101, // 495 + 0b00000010100, // 496 + 0b10001100001, // 497 + 0b10010001011, // 498 + 0b00011111110, // 499 + 0b10101011111, // 500 + 0b00100101010, // 501 + 0b00111000000, // 502 + 0b10110110101, // 503 + 0b11011110111, // 504 + 0b01010000010, // 505 + 0b01001101000, // 506 + 0b11000011101, // 507 + 0b01110111100, // 508 + 0b11111001001, // 509 + 0b11100100011, // 510 + 0b01101010110 // 511 +}; + +uint32_t dcs_word(uint32_t code) { + code &= 511; + return (dcs_parity[code] << 12) | (0b100 << 9) | code; +} + +} diff --git a/firmware/application/dcs.hpp b/firmware/application/dcs.hpp new file mode 100644 index 00000000..c6556c43 --- /dev/null +++ b/firmware/application/dcs.hpp @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __DCS_H_ +#define __DCS_H_ + +#include + +#define DCS_CODES_NB 512 + +namespace dcs { + +uint32_t dcs_word(uint32_t code); + +} + +#endif/*__DCS_H_*/ diff --git a/firmware/application/ui_audiotx.cpp b/firmware/application/ui_audiotx.cpp index 8bbaeaef..20bf4b08 100644 --- a/firmware/application/ui_audiotx.cpp +++ b/firmware/application/ui_audiotx.cpp @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include "ui_audiotx.hpp" +#include "ui_mictx.hpp" #include "baseband_api.hpp" #include "hackrf_gpio.hpp" diff --git a/firmware/application/ui_mictx.cpp b/firmware/application/ui_mictx.cpp new file mode 100644 index 00000000..03e5a44a --- /dev/null +++ b/firmware/application/ui_mictx.cpp @@ -0,0 +1,238 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include "ui_mictx.hpp" + +#include "baseband_api.hpp" +#include "hackrf_gpio.hpp" +#include "audio.hpp" +#include "portapack.hpp" +#include "pins.hpp" +#include "string_format.hpp" +#include "irq_controls.hpp" +#include "portapack_shared_memory.hpp" + +#include + +using namespace ctcss; +using namespace portapack; +using namespace hackrf::one; + +namespace ui { + +void MicTXView::focus() { + field_frequency.focus(); +} + +void MicTXView::update_vumeter() { + vumeter.set_value(audio_level); +} + +void MicTXView::on_tx_done() { + // Roger beep transmitted, stop transmitting + transmitting = false; + set_tx(false); +} + +void MicTXView::set_tx(bool enable) { + uint32_t ctcss_index; + bool ctcss_enabled; + + if (enable) { + ctcss_index = options_ctcss.selected_index(); + + if (ctcss_index) { + ctcss_enabled = true; + ctcss_index--; + } else + ctcss_enabled = false; + + baseband::set_audiotx_data( + 1536000U / 20, // 20Hz level update + transmitter_model.bandwidth(), + mic_gain_x10, + ctcss_enabled, + (uint32_t)((ctcss_tones[ctcss_index].frequency / 1536000.0) * 0xFFFFFFFFULL) + ); + gpio_tx.write(1); + led_tx.on(); + transmitting = true; + } else { + if (transmitting && rogerbeep_enabled) { + baseband::request_beep(); + } else { + baseband::set_audiotx_data( + 1536000U / 20, // 20Hz level update + 0, // BW 0 = TX off + mic_gain_x10, + false, // Ignore CTCSS + 0 + ); + gpio_tx.write(0); + led_tx.off(); + transmitting = false; + } + } +} + +void MicTXView::do_timing() { + if (va_enabled) { + if (!transmitting) { + // Attack + if (audio_level >= va_level) { + if ((attack_timer >> 8) >= attack_ms) { + decay_timer = 0; + attack_timer = 0; + set_tx(true); + } else { + attack_timer += ((256 * 1000) / 60); // 1 frame @ 60fps in ms .8 fixed point + } + } else { + attack_timer = 0; + } + } else { + // Decay + if (audio_level < va_level) { + if ((decay_timer >> 8) >= decay_ms) { + decay_timer = 0; + attack_timer = 0; + set_tx(false); + } else { + decay_timer += ((256 * 1000) / 60); // 1 frame @ 60fps in ms .8 fixed point + } + } else { + decay_timer = 0; + } + } + } else { + // PTT disable :( + const auto switches_state = get_switches_state(); + if (!switches_state[1]) // Left button + set_tx(false); + } +} + +void MicTXView::on_tuning_frequency_changed(rf::Frequency f) { + transmitter_model.set_tuning_frequency(f); +} + +MicTXView::MicTXView( + NavigationView& nav +) +{ + pins[P6_2].mode(3); // Set P6_2 pin function to I2S0_RX_SDA + + baseband::run_image(portapack::spi_flash::image_tag_mic_tx); + + add_children({ + &labels, + &vumeter, + &options_gain, + &check_va, + &field_va_level, + &field_va_attack, + &field_va_decay, + &field_bw, + &field_frequency, + &options_ctcss, + &check_rogerbeep, + &text_ptt, + &button_exit + }); + + ctcss_populate(options_ctcss); + options_ctcss.set_selected_index(0); + + options_gain.on_change = [this](size_t, int32_t v) { + mic_gain_x10 = v; + }; + options_gain.set_selected_index(1); // x1.0 + + field_frequency.set_value(transmitter_model.tuning_frequency()); + field_frequency.set_step(receiver_model.frequency_step()); + field_frequency.on_change = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + }; + field_frequency.on_edit = [this, &nav]() { + // TODO: Provide separate modal method/scheme? + auto new_view = nav.push(receiver_model.tuning_frequency()); + new_view->on_changed = [this](rf::Frequency f) { + this->on_tuning_frequency_changed(f); + this->field_frequency.set_value(f); + }; + }; + + field_bw.on_change = [this](uint32_t v) { + transmitter_model.set_bandwidth(v * 1000); + }; + field_bw.set_value(10); + + check_va.on_select = [this](Checkbox&, bool v) { + va_enabled = v; + text_ptt.hidden(v); + set_dirty(); + }; + check_va.set_value(false); + + check_rogerbeep.on_select = [this](Checkbox&, bool v) { + rogerbeep_enabled = v; + }; + check_rogerbeep.set_value(false); + + field_va_level.on_change = [this](int32_t v) { + va_level = v; + vumeter.set_mark(v); + }; + field_va_level.set_value(40); + + field_va_attack.on_change = [this](int32_t v) { + attack_ms = v; + }; + field_va_attack.set_value(500); + + field_va_decay.on_change = [this](int32_t v) { + decay_ms = v; + }; + field_va_decay.set_value(2000); + + button_exit.on_select = [&nav](Button&){ + nav.pop(); + }; + + // Run baseband as soon as the app starts to get audio levels without transmitting (rf amp off) + transmitter_model.set_sampling_rate(1536000U); + transmitter_model.set_rf_amp(true); + transmitter_model.set_baseband_bandwidth(1750000); + transmitter_model.enable(); + + set_tx(false); + + audio::set_rate(audio::Rate::Hz_24000); + audio::input::start(); +} + +MicTXView::~MicTXView() { + transmitter_model.disable(); + baseband::shutdown(); +} + +} diff --git a/firmware/application/ui_mictx.hpp b/firmware/application/ui_mictx.hpp new file mode 100644 index 00000000..1aeb1b38 --- /dev/null +++ b/firmware/application/ui_mictx.hpp @@ -0,0 +1,197 @@ +/* + * Copyright (C) 2015 Jared Boone, ShareBrained Technology, Inc. + * Copyright (C) 2016 Furrtek + * + * This file is part of PortaPack. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __UI_MICTX_H__ +#define __UI_MICTX_H__ + +#include "ui.hpp" +#include "hal.h" +#include "ui_widget.hpp" +#include "ui_navigation.hpp" +#include "ui_font_fixed_8x16.hpp" +#include "message.hpp" +#include "ui_receiver.hpp" +#include "transmitter_model.hpp" +#include "ctcss.hpp" + +namespace ui { + +class MicTXView : public View { +public: + MicTXView(NavigationView& nav); + ~MicTXView(); + + MicTXView(const MicTXView&) = delete; + MicTXView(MicTXView&&) = delete; + MicTXView& operator=(const MicTXView&) = delete; + MicTXView& operator=(MicTXView&&) = delete; + + void focus() override; + + // PTT: Enable through KeyEvent (only works with presses), disable by polling :( + bool on_key(const KeyEvent key) { + if ((key == KeyEvent::Left) && (!va_enabled)) { + set_tx(true); + return true; + } else + return false; + }; + + std::string title() const override { return "Microphone TX"; }; + +private: + void update_vumeter(); + void do_timing(); + void set_tx(bool enable); + void on_tuning_frequency_changed(rf::Frequency f); + void on_ctcss_changed(uint32_t v); + void on_tx_done(); + + bool transmitting { false }; + bool va_enabled { }; + bool rogerbeep_enabled { }; + uint32_t mic_gain_x10 { }; + uint32_t audio_level { 0 }; + uint32_t va_level { }; + uint32_t attack_ms { }; + uint32_t decay_ms { }; + uint32_t attack_timer { 0 }; + uint32_t decay_timer { 0 }; + + Labels labels { + { { 7 * 8, 1 * 8 }, "Mic. gain:", Color::light_grey() }, + { { 7 * 8, 4 * 8 }, "Voice activation:", Color::light_grey() }, + { { 8 * 8, 9 * 8 }, "Level: /255", Color::light_grey() }, + { { 8 * 8, 11 * 8 }, "Attack: ms", Color::light_grey() }, + { { 8 * 8, 13 * 8 }, "Decay: ms", Color::light_grey() }, + { { 7 * 8, 17 * 8 }, "Bandwidth: kHz", Color::light_grey() }, + { { 7 * 8, 19 * 8 }, "Frequency:", Color::light_grey() }, + { { 11 * 8, 21 * 8 }, "CTCSS:", Color::light_grey() } + }; + + VuMeter vumeter { + { 1 * 8, 2 * 8, 5 * 8, 26 * 8 }, + 16 + }; + + OptionsField options_gain { + { 17 * 8, 1 * 8 }, + 4, + { + { "x0.5", 5 }, + { "x1.0", 10 }, + { "x1.5", 15 }, + { "x2.0", 20 } + } + }; + + Checkbox check_va { + { 8 * 8, 6 * 8 }, + 7, + "Enabled", + false + }; + + NumberField field_va_level { + { 14 * 8, 9 * 8 }, + 3, + { 0, 255 }, + 2, + ' ' + }; + NumberField field_va_attack { + { 15 * 8, 11 * 8 }, + 3, + { 0, 999 }, + 20, + ' ' + }; + NumberField field_va_decay { + { 14 * 8, 13 * 8 }, + 4, + { 0, 9999 }, + 100, + ' ' + }; + + NumberField field_bw { + { 17 * 8, 17 * 8 }, + 3, + { 0, 150 }, + 1, + ' ' + }; + FrequencyField field_frequency { + { 17 * 8, 19 * 8 }, + }; + + OptionsField options_ctcss { + { 17 * 8, 21 * 8 }, + 8, + { } + }; + + Checkbox check_rogerbeep { + { 8 * 8, 23 * 8 }, + 10, + "Roger beep", + false + }; + + Text text_ptt { + { 7 * 8, 28 * 8, 16 * 8, 16 }, + "PTT: LEFT BUTTON" + }; + + Button button_exit { + { 18 * 8, 32 * 8, 10 * 8, 40 }, + "Exit" + }; + + MessageHandlerRegistration message_handler_lcd_sync { + Message::ID::DisplayFrameSync, + [this](const Message* const) { + this->update_vumeter(); + this->do_timing(); + } + }; + + MessageHandlerRegistration message_handler_audio_level { + Message::ID::AudioLevel, + [this](const Message* const p) { + const auto message = static_cast(p); + this->audio_level = message->value; + } + }; + + MessageHandlerRegistration message_handler_tx_done { + Message::ID::TXDone, + [this](const Message* const p) { + const auto message = *reinterpret_cast(p); + if (message.done) this->on_tx_done(); + } + }; +}; + +} /* namespace ui */ + +#endif/*__UI_MICTX_H__*/ diff --git a/firmware/application/ui_navigation.cpp b/firmware/application/ui_navigation.cpp index 83b6b3b1..bc174697 100644 --- a/firmware/application/ui_navigation.cpp +++ b/firmware/application/ui_navigation.cpp @@ -33,7 +33,7 @@ #include "ui_about.hpp" #include "ui_adsbtx.hpp" -#include "ui_audiotx.hpp" +#include "ui_mictx.hpp" #include "ui_bht_tx.hpp" #include "ui_closecall.hpp" #include "ui_cw.hpp" @@ -323,7 +323,7 @@ TransmitterAudioMenuView::TransmitterAudioMenuView(NavigationView& nav) { add_items<4>({ { { "Soundboard", ui::Color::green(), &bitmap_icon_soundboard, [&nav](){ nav.push(); } }, { "Numbers station", ui::Color::orange(),&bitmap_icon_numbers, [&nav](){ nav.push(); } }, - { "Microphone", ui::Color::green(), &bitmap_icon_microphone, [&nav](){ nav.push(); } }, + { "Microphone", ui::Color::green(), &bitmap_icon_microphone, [&nav](){ nav.push(); } }, { "Whistle", ui::Color::yellow(),&bitmap_icon_whistle, [&nav](){ nav.push(); } }, } }); on_left = [&nav](){ nav.pop(); }; diff --git a/firmware/application/ui_numbers.hpp b/firmware/application/ui_numbers.hpp index 7be75e51..3aacb453 100644 --- a/firmware/application/ui_numbers.hpp +++ b/firmware/application/ui_numbers.hpp @@ -150,10 +150,10 @@ private: }; MessageHandlerRegistration message_handler_fifo_signal { - Message::ID::FIFOSignal, + Message::ID::RequestSignal, [this](const Message* const p) { - const auto message = static_cast(p); - if (message->signaltype == 1) { + const auto message = static_cast(p); + if (message->signal == RequestSignalMessage::Signal::FillRequest) { this->prepare_audio(); } } diff --git a/firmware/application/ui_soundboard.hpp b/firmware/application/ui_soundboard.hpp index 37bfbc32..d1ceb5f5 100644 --- a/firmware/application/ui_soundboard.hpp +++ b/firmware/application/ui_soundboard.hpp @@ -176,10 +176,10 @@ private: }; MessageHandlerRegistration message_handler_fifo_signal { - Message::ID::FIFOSignal, + Message::ID::RequestSignal, [this](const Message* const p) { - const auto message = static_cast(p); - if (message->signaltype == 1) { + const auto message = static_cast(p); + if (message->signal == RequestSignalMessage::Signal::FillRequest) { this->prepare_audio(); } } diff --git a/firmware/baseband/proc_audiotx.cpp b/firmware/baseband/proc_audiotx.cpp index a4b1d202..7d422e36 100644 --- a/firmware/baseband/proc_audiotx.cpp +++ b/firmware/baseband/proc_audiotx.cpp @@ -45,8 +45,7 @@ void AudioTXProcessor::execute(const buffer_c8_t& buffer){ if ((audio_fifo.len() < 512) && (asked == false)) { // Ask application to fill up fifo - sigmessage.signaltype = 1; - shared_memory.application_queue.push(sigmessage); + shared_memory.application_queue.push(sig_message); asked = true; } } else { diff --git a/firmware/baseband/proc_audiotx.hpp b/firmware/baseband/proc_audiotx.hpp index 655a22e7..d5414093 100644 --- a/firmware/baseband/proc_audiotx.hpp +++ b/firmware/baseband/proc_audiotx.hpp @@ -60,7 +60,7 @@ private: sizeof(int16_t)*64 };*/ - FIFOSignalMessage sigmessage { }; + RequestSignalMessage sig_message { RequestSignalMessage::Signal::FillRequest }; }; #endif diff --git a/firmware/baseband/proc_mictx.cpp b/firmware/baseband/proc_mictx.cpp index 6aabfedd..5cba94de 100644 --- a/firmware/baseband/proc_mictx.cpp +++ b/firmware/baseband/proc_mictx.cpp @@ -78,18 +78,26 @@ void MicTXProcessor::execute(const buffer_c8_t& buffer){ } void MicTXProcessor::on_message(const Message* const msg) { - const auto message = *reinterpret_cast(msg); + const AudioTXConfigMessage config_message = *reinterpret_cast(msg); + const RequestSignalMessage request_message = *reinterpret_cast(msg); switch(msg->id) { case Message::ID::AudioTXConfig: - fm_delta = message.fm_delta * (0xFFFFFFULL / 1536000); - gain_x10 = message.gain_x10; - divider = message.divider; - ctcss_enabled = message.ctcss_enabled; - ctcss_phase_inc = message.ctcss_phase_inc; + fm_delta = config_message.fm_delta * (0xFFFFFFULL / 1536000); + gain_x10 = config_message.gain_x10; + divider = config_message.divider; + ctcss_enabled = config_message.ctcss_enabled; + ctcss_phase_inc = config_message.ctcss_phase_inc; configured = true; break; + + case Message::ID::RequestSignal: + if (request_message.signal == RequestSignalMessage::Signal::BeepRequest) { + // TODO + txdone_message.done = true; + } + break; default: break; diff --git a/firmware/baseband/proc_mictx.hpp b/firmware/baseband/proc_mictx.hpp index c3a1a85c..4c63d847 100644 --- a/firmware/baseband/proc_mictx.hpp +++ b/firmware/baseband/proc_mictx.hpp @@ -58,6 +58,7 @@ private: int8_t re { 0 }, im { 0 }; AudioLevelMessage level_message { }; + TXDoneMessage txdone_message { }; }; #endif diff --git a/firmware/common/message.hpp b/firmware/common/message.hpp index c834cc01..d24369c8 100644 --- a/firmware/common/message.hpp +++ b/firmware/common/message.hpp @@ -89,7 +89,7 @@ public: POCSAGPacket = 50, - FIFOSignal = 52, + RequestSignal = 52, FIFOData = 53, AudioLevel = 54, @@ -794,14 +794,21 @@ public: }; // TODO: use streaming buffer instead -class FIFOSignalMessage : public Message { +class RequestSignalMessage : public Message { public: - constexpr FIFOSignalMessage( - ) : Message { ID::FIFOSignal } + enum class Signal : char { + FillRequest = 1, + BeepRequest = 2, + }; + + constexpr RequestSignalMessage( + Signal signal + ) : Message { ID::RequestSignal }, + signal ( signal ) { } - char signaltype = 0; + Signal signal; }; class FIFODataMessage : public Message { diff --git a/firmware/tools/make_dcs.py b/firmware/tools/make_dcs.py new file mode 100644 index 00000000..0879f07b --- /dev/null +++ b/firmware/tools/make_dcs.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python + +# Copyright (C) 2016 Furrtek +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2, or (at your option) +# any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +# From http://mmi-comm.tripod.com/dcs.html + +import sys +import struct + +cb = [0,0,0,0,0,0,0,0,0] +for c in range (0, 0x200): # DCS code is 9 bits + for bit in range(0, 9): + cb[bit] = (c >> bit) & 1 + + p1 = cb[0] ^ cb[1] ^ cb[2] ^ cb[3] ^ cb[4] ^ cb[7]; + p2 = cb[1] ^ cb[2] ^ cb[3] ^ cb[4] ^ cb[5] ^ cb[8] ^ 1; + p3 = cb[0] ^ cb[1] ^ cb[5] ^ cb[6] ^ cb[7]; + p4 = cb[1] ^ cb[2] ^ cb[6] ^ cb[7] ^ cb[8] ^ 1; + p5 = cb[0] ^ cb[1] ^ cb[4] ^ cb[8] ^ 1; + p6 = cb[0] ^ cb[3] ^ cb[4] ^ cb[5] ^ cb[7] ^ 1; + p7 = cb[0] ^ cb[2] ^ cb[3] ^ cb[5] ^ cb[6] ^ cb[7] ^ cb[8]; + p8 = cb[1] ^ cb[3] ^ cb[4] ^ cb[6] ^ cb[7] ^ cb[8]; + p9 = cb[2] ^ cb[4] ^ cb[5] ^ cb[7] ^ cb[8]; + p10 = cb[3] ^ cb[5] ^ cb[6] ^ cb[8] ^ 1; + p11 = cb[0] ^ cb[1] ^ cb[2] ^ cb[3] ^ cb[6] ^ 1; + + print ' 0b{0:011b}'.format((p11<<10) | (p10<<9) | (p9<<8) |(p8<<7) | (p7<<6) | (p6<<5) | (p5<<4) | (p4<<3) | (p3<<2) | (p2<<1) | (p1)) + ', // ' + str(c);