mirror of
https://github.com/adrcs/ip400.git
synced 2025-04-21 11:13:42 +03:00
Delete code directory
This commit is contained in:
parent
ced1a78d1e
commit
b092877ded
|
@ -1,58 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
Module: <module description here>
|
|
||||||
|
|
||||||
File Name: queue.h
|
|
||||||
|
|
||||||
Date Created: Jan 9, 2025
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: <what it does>
|
|
||||||
|
|
||||||
Copyright © 2024-25, Alberta Digital Radio Communications Society,
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef INC_DATAQ_H_
|
|
||||||
#define INC_DATAQ_H_
|
|
||||||
|
|
||||||
#ifndef __CCALL
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define __CCALL extern "C"
|
|
||||||
#else
|
|
||||||
#define __CCALL
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define Q_TYPECAST (struct qelem *)
|
|
||||||
|
|
||||||
// queue structure
|
|
||||||
typedef struct qelem {
|
|
||||||
struct qelem *q_forw;
|
|
||||||
struct qelem *q_back;
|
|
||||||
} QUEUE_ELEM;
|
|
||||||
|
|
||||||
// frame data queue
|
|
||||||
typedef struct frame_data_queue_t {
|
|
||||||
struct frame_data_queue_t *q_forw; // forwared pointer
|
|
||||||
struct frame_data_queue_t *q_back; // backward pointer
|
|
||||||
void *frame; // IP400 Frame
|
|
||||||
uint16_t length; // length (in some cases)
|
|
||||||
} FRAME_QUEUE;
|
|
||||||
|
|
||||||
// queue functions
|
|
||||||
BOOL enqueFrame(FRAME_QUEUE *que, IP400_FRAME *fr);
|
|
||||||
IP400_FRAME *dequeFrame(FRAME_QUEUE *que);
|
|
||||||
|
|
||||||
// queue management
|
|
||||||
void insque (struct qelem *elem, struct qelem *pred);
|
|
||||||
void remque (struct qelem *elem);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INC_DATAQ_H_ */
|
|
|
@ -1,195 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
Module: <module description here>
|
|
||||||
|
|
||||||
File Name: frame.h
|
|
||||||
|
|
||||||
Date Created: Jan 8, 2025
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: <what it does>
|
|
||||||
|
|
||||||
Copyright © 2024-25, Alberta Digital Radio Communications Society,
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef FRAME_H_
|
|
||||||
#define FRAME_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
// frame defines
|
|
||||||
#define N_CALL 4 // octets in the excess-40 compressed callsign
|
|
||||||
#define MAX_CALL 6 // max callsign size
|
|
||||||
#define EXT_CALL 4*MAX_CALL // extended call sign field
|
|
||||||
#define PAYLOAD_MIN 56 // min octets in payload
|
|
||||||
#define PAYLOAD_MAX 1053 // max octets in payload
|
|
||||||
#define MAX_CALL_BUFFER 20 // max buffering for callsign in payload
|
|
||||||
#define N_FEC 4 // number of bytes in the FEC
|
|
||||||
#define BROADCAST_ADDR 0xFF // broadcast address
|
|
||||||
|
|
||||||
#define MAX_HOP_COUNT 15 // max hop count
|
|
||||||
|
|
||||||
// radio error register
|
|
||||||
#define SEQ_COMPLETE_ERR 0x8000 // Sequencer error
|
|
||||||
#define SEQ_ACT_TIMEOUT 0x4000 // Sequencer action timeout
|
|
||||||
#define PLL_CALAMP_ERR 0x0800 // VCO amplitude calibration error
|
|
||||||
#define PLL_CALFREQ_ERR 0x0400 // VCO frequency calibration error
|
|
||||||
#define PLL_UNLOCK_ERR 0x0200 // PLL is unlocked
|
|
||||||
#define PLL_LOCK_FAIL 0x0100 // PLL lock failure
|
|
||||||
#define DBM_FIFO_ERR 0x0020 // Data buffer failure
|
|
||||||
#define N_RADIO_ERRS 7 // number of the above
|
|
||||||
|
|
||||||
// radio FSM states
|
|
||||||
enum fsm_states_e {
|
|
||||||
FSM_IDLE=0, // idle
|
|
||||||
FSM_ENA_RF_REG, // enable RF registers
|
|
||||||
FSM_WAIT_ACTIVE2, // wait for active 2
|
|
||||||
FSM_ACTIVE2, // active 2
|
|
||||||
FSM_ENA_CURR, // enable current
|
|
||||||
FSM_SYNTH_SETUP, // synth setup
|
|
||||||
FSM_CALIB_VCO, // VCO calibration
|
|
||||||
FSM_LOCKRXTX, // lock Rx and Rx
|
|
||||||
FSM_LOCKONTX, // lock on Rx
|
|
||||||
FSM_EN_PA, // enable PA
|
|
||||||
FSM_TX, // transmit
|
|
||||||
FSM_PA_DWN_ANA, // Analog power down
|
|
||||||
FSM_END_TX, // end transmit
|
|
||||||
FSM_LOCKONRX, // lock on Rx
|
|
||||||
FSM_EN_RX, // Enable Rx
|
|
||||||
FSM_EN_LNA, // enable LNA
|
|
||||||
FSM_RX, // recieve
|
|
||||||
FSM_END_RX, // end rx
|
|
||||||
FSM_SYNTH_PWDN, // synth power down
|
|
||||||
FSM_N_FSM_STATES
|
|
||||||
};
|
|
||||||
|
|
||||||
// header flags
|
|
||||||
typedef struct frame_flags_t {
|
|
||||||
unsigned hop_count: 4; // hop count
|
|
||||||
unsigned coding: 4; // coding method
|
|
||||||
unsigned compression: 2; // compression method
|
|
||||||
unsigned unused: 1; // unused
|
|
||||||
unsigned srcExt: 1; // source call is extended
|
|
||||||
unsigned destExt: 1; // dest call is extended
|
|
||||||
unsigned command: 1; // command packet
|
|
||||||
unsigned noconnect: 1; // connectionless
|
|
||||||
unsigned repeat: 1; // repeat flag
|
|
||||||
} IP400_FLAGS;
|
|
||||||
|
|
||||||
// callsign field
|
|
||||||
typedef struct callsign_t {
|
|
||||||
union {
|
|
||||||
uint8_t bytes[N_CALL]; // compressed callsign
|
|
||||||
uint32_t encoded;
|
|
||||||
} callbytes;
|
|
||||||
uint16_t port; // port information
|
|
||||||
} IP400_CALL;
|
|
||||||
|
|
||||||
// complete frame
|
|
||||||
typedef struct ip400_frame_t {
|
|
||||||
IP400_CALL source; // source call sign
|
|
||||||
IP400_CALL dest; // destination call sign
|
|
||||||
union {
|
|
||||||
IP400_FLAGS flags; // flag bit field
|
|
||||||
uint16_t allflags; // all flags
|
|
||||||
} flagfld;
|
|
||||||
uint32_t seqNum; // packet sequence number
|
|
||||||
void *buf; // data to send
|
|
||||||
uint16_t length; // data length
|
|
||||||
} IP400_FRAME;
|
|
||||||
|
|
||||||
// min/max payload sizes
|
|
||||||
#define IP_400_CALL_SIZE N_CALL + sizeof(uint16_t)
|
|
||||||
#define IP_400_FLAG_SIZE sizeof(uint16_t)
|
|
||||||
#define IP_400_HDR_SIZE (2*IP_400_CALL_SIZE + IP_400_FLAG_SIZE)
|
|
||||||
#define IP_400_LEN_SIZE sizeof(uint16_t)
|
|
||||||
#define MIN_FRAME_SIZE sizeof(IP400_FRAME) + PAYLOAD_MIN + N_FEC
|
|
||||||
#define MAX_FRAME_SIZE MIN_FRAME_SIZE - PAYLOAD_MIN + PAYLOAD_MAX
|
|
||||||
// packet types
|
|
||||||
enum {
|
|
||||||
UTF8_TEXT_PACKET=0, // Text packet
|
|
||||||
COMPRESSED_AUDIO, // compressed audio packet
|
|
||||||
COMPREESSD_VIDEO, // compressed video packet
|
|
||||||
DATA_PACKET, // data packet
|
|
||||||
PING_PACKET, // ping packet
|
|
||||||
IP_ENCAPSULATED, // IP encapsulated packet
|
|
||||||
AX_25_PACKET, // AX.25 encapsulated packet
|
|
||||||
RFC4733_DTMF, // DTMF packet
|
|
||||||
DMR_FRAME, // DMR Frame
|
|
||||||
DSTAR_FRAME, // Dstar Frame
|
|
||||||
P25_FRAME, // TIA project 25
|
|
||||||
NXDN_FRAME, // NXDN
|
|
||||||
M17_FRAME, // M17
|
|
||||||
TBD_1,
|
|
||||||
TBD_2,
|
|
||||||
LOCAL_COMMAND // local command frame
|
|
||||||
};
|
|
||||||
|
|
||||||
// audio compression types
|
|
||||||
enum {
|
|
||||||
AUDIO_RAW, // raw 16-bit PCM
|
|
||||||
AUDIO_ULAW, // mu law compression
|
|
||||||
AUDIO_CODEC2, // codec 2 encoded
|
|
||||||
AUDIO_AMBE // AMBE encoded
|
|
||||||
};
|
|
||||||
|
|
||||||
// H.246 Video compression
|
|
||||||
enum {
|
|
||||||
H264_240_180_24, // H.264: 240x180, 24FPS
|
|
||||||
H264_320_240_24, // H.264: 320x240, 24FPS
|
|
||||||
H264_480_360_12, // H.264: 480x360, 12FPS
|
|
||||||
H264_640_480_6 // H.264: 640x480, 6FPS
|
|
||||||
};
|
|
||||||
|
|
||||||
// callsign fields
|
|
||||||
enum {
|
|
||||||
SRC_CALLSIGN=0, // dest for encode is source callsign
|
|
||||||
DEST_CALLSIGN // dest for encode is dest callsign
|
|
||||||
};
|
|
||||||
|
|
||||||
// frame stats
|
|
||||||
typedef struct frame_stats_t {
|
|
||||||
uint32_t TxFrameCnt; // transmit frame count
|
|
||||||
uint32_t RxFrameCnt; // good receive frame count
|
|
||||||
uint32_t CRCErrors; // CRC Errors
|
|
||||||
uint32_t TimeOuts; // Timeouts
|
|
||||||
uint32_t lastRSSI; // last RSSI reading
|
|
||||||
uint32_t framesOK; // processed frames
|
|
||||||
uint32_t dropped; // rejected frames
|
|
||||||
uint32_t duplicates; // duplicates
|
|
||||||
uint32_t nBeacons; // number of beacons processed
|
|
||||||
uint32_t nRepeated; // repeated frames
|
|
||||||
} FRAME_STATS;
|
|
||||||
|
|
||||||
// packet types
|
|
||||||
#define ICMP_TYPE 1 // control message type
|
|
||||||
#define ENC_IP_TYPE 4 // encapsulated IP
|
|
||||||
#define AUDIO_TYPE 11 // audio packets
|
|
||||||
#define TEXT_TYPE 17 // port for text chat (UDP)
|
|
||||||
#define VIDEO_TYPE 75 // H.264 video
|
|
||||||
#define ENC_AX25_TYPE 93 // encapsulated AX25 packets
|
|
||||||
|
|
||||||
// references
|
|
||||||
uint8_t callEncode(char *callsign, uint16_t port, IP400_FRAME *frame, uint8_t dest, uint8_t offset);
|
|
||||||
BOOL callDecode(IP400_CALL *encCall, char *callsign, uint16_t *port);
|
|
||||||
|
|
||||||
// frame senders
|
|
||||||
BOOL SendTextFrame(char *srcCall, uint16_t srcPort, char *destCall, uint16_t dstPort, char *buf, uint16_t length, BOOL repeat);
|
|
||||||
void SendBeaconFrame(char *srcCall, uint8_t *payload, int bcnlen);
|
|
||||||
|
|
||||||
//
|
|
||||||
BOOL EnqueChatFrame(void *Frame); // queue a chat frame
|
|
||||||
FRAME_STATS *GetFrameStats(void); // return the frame stats
|
|
||||||
uint32_t GetRadioStatus(void); // get the radio status
|
|
||||||
uint8_t GetFSMState(void); // get FSM state
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* FRAME_H_ */
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: led.h
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 26, 2025
|
|
||||||
|
|
||||||
Description: Definitions for the LED module
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) 2024-25 Alberta Digital Radio Communications Society
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#ifndef INC_LED_H_
|
|
||||||
#define INC_LED_H_
|
|
||||||
|
|
||||||
// LED functions
|
|
||||||
enum {
|
|
||||||
|
|
||||||
BICOLOR_OFF=0, // turn LED off
|
|
||||||
BICOLOR_RED, // red mode steady
|
|
||||||
BICOLOR_RED_FLASH, // red mode flashing
|
|
||||||
BICOLOR_GREEN, // green mode steady
|
|
||||||
BICOLOR_GREEN_FLASH, // green mode flashing
|
|
||||||
BICOLOR_RED_GREEN, // alternate RED/GREEN
|
|
||||||
TX_LED_ON, // tx LED on
|
|
||||||
TX_LED_OFF, // tx LED OFF
|
|
||||||
N_LED_MODE // modes1
|
|
||||||
};
|
|
||||||
|
|
||||||
void SetLEDMode(uint8_t mode);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INC_LED_H_ */
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* FreeRTOS Kernel V10.6.2
|
|
||||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*
|
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
||||||
* this software and associated documentation files (the "Software"), to deal in
|
|
||||||
* the Software without restriction, including without limitation the rights to
|
|
||||||
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
|
||||||
* the Software, and to permit persons to whom the Software is furnished to do so,
|
|
||||||
* subject to the following conditions:
|
|
||||||
*
|
|
||||||
* The above copyright notice and this permission notice shall be included in all
|
|
||||||
* copies or substantial portions of the Software.
|
|
||||||
*
|
|
||||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
|
||||||
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
|
||||||
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
||||||
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
||||||
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
*
|
|
||||||
* https://www.FreeRTOS.org
|
|
||||||
* https://github.com/FreeRTOS
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INC_NEWLIB_FREERTOS_H
|
|
||||||
#define INC_NEWLIB_FREERTOS_H
|
|
||||||
|
|
||||||
/* Note Newlib support has been included by popular demand, but is not
|
|
||||||
* used by the FreeRTOS maintainers themselves. FreeRTOS is not
|
|
||||||
* responsible for resulting newlib operation. User must be familiar with
|
|
||||||
* newlib and must provide system-wide implementations of the necessary
|
|
||||||
* stubs. Be warned that (at the time of writing) the current newlib design
|
|
||||||
* implements a system-wide malloc() that must be provided with locks.
|
|
||||||
*
|
|
||||||
* See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
|
|
||||||
* for additional information. */
|
|
||||||
|
|
||||||
#include <reent.h>
|
|
||||||
|
|
||||||
#define configUSE_C_RUNTIME_TLS_SUPPORT 1
|
|
||||||
|
|
||||||
#ifndef configTLS_BLOCK_TYPE
|
|
||||||
#define configTLS_BLOCK_TYPE struct _reent
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef configINIT_TLS_BLOCK
|
|
||||||
#define configINIT_TLS_BLOCK( xTLSBlock, pxTopOfStack ) _REENT_INIT_PTR( &( xTLSBlock ) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef configSET_TLS_BLOCK
|
|
||||||
#define configSET_TLS_BLOCK( xTLSBlock ) ( _impure_ptr = &( xTLSBlock ) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef configDEINIT_TLS_BLOCK
|
|
||||||
#define configDEINIT_TLS_BLOCK( xTLSBlock ) _reclaim_reent( &( xTLSBlock ) )
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif /* INC_NEWLIB_FREERTOS_H */
|
|
|
@ -1,133 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: setup.h
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 13, 2025
|
|
||||||
|
|
||||||
Description: Definitions for setup data
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) 2024-25 Alberta Digital Radio Communications Society
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#ifndef INC_SETUP_H_
|
|
||||||
#define INC_SETUP_H_
|
|
||||||
|
|
||||||
#include <stm32wl3x_hal_mrsubg.h>
|
|
||||||
|
|
||||||
#include "frame.h"
|
|
||||||
#include "usart.h"
|
|
||||||
|
|
||||||
#define __USE_SETUP_PARAMS 1 // set to 1 to use setup parameters
|
|
||||||
#define US 0 // station is in the US
|
|
||||||
|
|
||||||
// defined elsewhere
|
|
||||||
extern char *modTypes[];
|
|
||||||
extern char *paModes[];
|
|
||||||
|
|
||||||
typedef struct setup_flags_t {
|
|
||||||
unsigned fsk: 1; // can run FSK
|
|
||||||
unsigned ofdm: 1; // can run OFDM
|
|
||||||
unsigned aredn: 1; // is an AREDN node
|
|
||||||
unsigned repeat: 1; // repeat mode default
|
|
||||||
unsigned ext: 1; // use extended callsign
|
|
||||||
unsigned rate: 3; // data rate in use
|
|
||||||
} SETUP_FLAGS;
|
|
||||||
|
|
||||||
// data rates in the flag field (FSK mode)
|
|
||||||
enum {
|
|
||||||
FSK_1200,
|
|
||||||
FSK_9600,
|
|
||||||
FSK_56K,
|
|
||||||
FSK_100K,
|
|
||||||
FSK_200K,
|
|
||||||
FSK_400K,
|
|
||||||
FSK_600K
|
|
||||||
};
|
|
||||||
|
|
||||||
// setup data struct
|
|
||||||
typedef struct setup_data_t {
|
|
||||||
SETUP_FLAGS flags; // flags
|
|
||||||
char stnCall[MAX_CALL]; // station call sign
|
|
||||||
char extCall[EXT_CALL]; // extended call sign
|
|
||||||
char latitude[10]; // latititude
|
|
||||||
char longitude[10]; // longitude
|
|
||||||
char gridSq[10]; // grid square
|
|
||||||
uint16_t beaconInt; // beacon interval
|
|
||||||
} SETUP_DATA;
|
|
||||||
|
|
||||||
// Radio setup struct
|
|
||||||
typedef struct radio_setup_t {
|
|
||||||
uint32_t lFrequencyBase; /*!< Specifies the base carrier frequency (in Hz) */
|
|
||||||
MRSubGModSelect xModulationSelect; /*!< Specifies the modulation @ref MRSubGModSelect */
|
|
||||||
uint32_t lDatarate; /*!< Specifies the datarate expressed in sps.*/
|
|
||||||
uint32_t lFreqDev; /*!< Specifies the frequency deviation expressed in Hz. */
|
|
||||||
uint32_t lBandwidth; /*!< Specifies the channel filter bandwidth expressed in Hz. */
|
|
||||||
uint8_t dsssExp; /*!< Specifies the DSSS spreading exponent. Use 0 to disable DSSS. */
|
|
||||||
uint8_t outputPower; /*!< PA value to write expressed in dBm. */
|
|
||||||
MRSubG_PA_DRVMode PADrvMode; /*!< PA drive mode. */
|
|
||||||
int16_t rxSquelch; // rx squelch level
|
|
||||||
} RADIO_SETUP;
|
|
||||||
|
|
||||||
// setup struct
|
|
||||||
typedef struct stn_params_t {
|
|
||||||
SETUP_DATA setup_data; // basic setup data
|
|
||||||
RADIO_SETUP radio_setup; // radio setup
|
|
||||||
uint8_t FirmwareVerMajor; // firmware major rev
|
|
||||||
uint8_t FirmwareVerMinor; // firmware minor vers
|
|
||||||
uint32_t Magic; // magic number: "DEBEADEF"
|
|
||||||
uint32_t SetupCRC; // CRC
|
|
||||||
} STN_PARAMS;
|
|
||||||
|
|
||||||
// beacon header
|
|
||||||
typedef union {
|
|
||||||
struct beacon_hdr_t {
|
|
||||||
SETUP_FLAGS flags;
|
|
||||||
uint8_t txPower;
|
|
||||||
} setup;
|
|
||||||
uint8_t hdrBytes[sizeof(struct beacon_hdr_t)];
|
|
||||||
} BEACON_HEADER;
|
|
||||||
|
|
||||||
#define SETUP_MAGIC 0xDEBEADEF // magic number
|
|
||||||
|
|
||||||
typedef union {
|
|
||||||
STN_PARAMS params;
|
|
||||||
uint8_t bytes[sizeof(STN_PARAMS)];
|
|
||||||
uint32_t flashwords[sizeof(STN_PARAMS)/sizeof(uint32_t)];
|
|
||||||
} SETUP_MEMORY;
|
|
||||||
|
|
||||||
extern SETUP_MEMORY setup_memory;
|
|
||||||
extern SETUP_MEMORY def_params;
|
|
||||||
extern CRC_HandleTypeDef hcrc;
|
|
||||||
|
|
||||||
// validations used by key entry
|
|
||||||
#if US
|
|
||||||
#define MIN_FREQ 420000000 // min freq (US only)
|
|
||||||
#else
|
|
||||||
#define MIN_FREQ 430000000 // min freq (CAN only)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// links in
|
|
||||||
void printStationSetup(void); // print setup struct
|
|
||||||
void printRadioSetup(void); // print radio setup
|
|
||||||
char *GetMyCall(void); // return the station's callsign
|
|
||||||
STN_PARAMS *GetStationParams(void); // get the station params
|
|
||||||
BOOL CompareToMyCall(char *call);
|
|
||||||
//
|
|
||||||
BOOL VerifySetup(void);
|
|
||||||
BOOL ReadSetup(void);
|
|
||||||
BOOL WriteSetup(void);
|
|
||||||
void SetDefSetup(void);
|
|
||||||
BOOL UpdateSetup(void);
|
|
||||||
|
|
||||||
#endif /* INC_SETUP_H_ */
|
|
|
@ -1,18 +0,0 @@
|
||||||
/*
|
|
||||||
* streambuffer.h
|
|
||||||
*
|
|
||||||
* Created on: Jan 11, 2025
|
|
||||||
* Author: MartinA
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef INC_STREAMBUFFER_H_
|
|
||||||
#define INC_STREAMBUFFER_H_
|
|
||||||
|
|
||||||
// data buffer defs
|
|
||||||
typedef uint8_t DATA_ELEMENT; // data element
|
|
||||||
#define BUFFER_EMPTY(x) (x.nDataBytes == 0)
|
|
||||||
#define BUFFER_NO_DATA 0
|
|
||||||
#define bufferSIZE 512 // large buffer
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INC_STREAMBUFFER_H_ */
|
|
|
@ -1,40 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: tod.h
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 23, 2025
|
|
||||||
|
|
||||||
Description: <decription here?
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) 2024-25 Alberta Digital Radio Communications Society
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#ifndef INC_TOD_H_
|
|
||||||
#define INC_TOD_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
// TOD struct
|
|
||||||
typedef struct tod_t {
|
|
||||||
uint8_t Seconds;
|
|
||||||
uint8_t Minutes;
|
|
||||||
uint8_t Hours;
|
|
||||||
} TIMEOFDAY;
|
|
||||||
|
|
||||||
// links in
|
|
||||||
void TOD_10SecTimer(void); // 10 second timer
|
|
||||||
void getTOD(TIMEOFDAY *time);
|
|
||||||
BOOL setTOD(char *todString);
|
|
||||||
|
|
||||||
#endif /* INC_TOD_H_ */
|
|
|
@ -1,54 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
Module: Type definitions
|
|
||||||
|
|
||||||
File Name: types.h
|
|
||||||
|
|
||||||
Date Created: Jan 9, 2025
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: Useful data types
|
|
||||||
|
|
||||||
Copyright © 2024-25, Alberta Digital Radio Communications Society,
|
|
||||||
All rights reserved
|
|
||||||
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef INC_TYPES_H_
|
|
||||||
#define INC_TYPES_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
// boolean type
|
|
||||||
#ifndef BOOL
|
|
||||||
typedef uint8_t BOOL; // boolean
|
|
||||||
typedef uint8_t BOOLEAN; // alternate
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef TRUE
|
|
||||||
#define TRUE ((BOOL)1U)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef FALSE
|
|
||||||
#define FALSE ((BOOL)0U)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef __CCALL
|
|
||||||
#ifdef __cplusplus
|
|
||||||
#define __CCALL extern "C"
|
|
||||||
#else
|
|
||||||
#define __CCALL
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// macros
|
|
||||||
#define islower(c) ((c >= 'a') && (c <= 'z'))
|
|
||||||
#define toupper(c) (c-0x20)
|
|
||||||
|
|
||||||
#endif /* INC_TYPES_H_ */
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: usart.h
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 12, 2025
|
|
||||||
|
|
||||||
Description: <decription here?
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) 2024-25 Alberta Digital Radio Communications Society
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#ifndef INC_USART_H_
|
|
||||||
#define INC_USART_H_
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "main.h"
|
|
||||||
|
|
||||||
// definitions
|
|
||||||
typedef uint32_t UART_TIMEOUT_T; // uart timer type
|
|
||||||
typedef uint16_t BUFFER_SIZE_T; // buffer size type
|
|
||||||
typedef uint8_t DATA_ELEMENT; // buffer data element
|
|
||||||
|
|
||||||
// uart HAL handle
|
|
||||||
extern UART_HandleTypeDef huart1; // console UART
|
|
||||||
extern UART_HandleTypeDef hlpuart1 ; // GPS UART
|
|
||||||
|
|
||||||
// logger defines
|
|
||||||
#define LOG_NOTICE 0 // notice
|
|
||||||
#define LOG_ERROR 1 // error
|
|
||||||
#define LOG_SEVERE 2 // severe error
|
|
||||||
|
|
||||||
// logger
|
|
||||||
void logger(int severity, char *format, ...);
|
|
||||||
|
|
||||||
// API calls
|
|
||||||
void USART_RxBuffer_reset(void);
|
|
||||||
size_t databuffer_bytesInBuffer(void);
|
|
||||||
DATA_ELEMENT databuffer_get(UART_TIMEOUT_T timeout);
|
|
||||||
BOOL databuffer_contains(const char *tag, UART_TIMEOUT_T rx_timeout, BOOL saveData, char *SaveBuffer);
|
|
||||||
BOOL USART_Send_String(const char *string, size_t len);
|
|
||||||
BOOL USART_Send_Char(const char c);
|
|
||||||
void USART_Print_string(char *format, ...);
|
|
||||||
|
|
||||||
// same as USART but for LPUART: no Tx functions
|
|
||||||
void LPUART_RxBuffer_reset(void);
|
|
||||||
size_t gpsbuffer_bytesInBuffer(void);
|
|
||||||
DATA_ELEMENT gpsbuffer_get(UART_TIMEOUT_T timeout);
|
|
||||||
void LPUART_Send_String(char *str, uint16_t len);
|
|
||||||
|
|
||||||
#endif /* INC_USART_H_ */
|
|
|
@ -1,42 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: utils.h
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 20, 2025
|
|
||||||
|
|
||||||
Description: Utility routines
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) 2024-25 Alberta Digital Radio Communications Society
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#ifndef INC_UTILS_H_
|
|
||||||
#define INC_UTILS_H_
|
|
||||||
|
|
||||||
// replacement for missing itoa
|
|
||||||
int ascii2Dec(char *dec);
|
|
||||||
|
|
||||||
// and its double counterpart...
|
|
||||||
double ascii2double(char *val);
|
|
||||||
|
|
||||||
// hex to ascii
|
|
||||||
void hex2ascii(uint8_t hex, char *buf);
|
|
||||||
|
|
||||||
// check an entry for floating point
|
|
||||||
BOOL isfloat(char *val);
|
|
||||||
|
|
||||||
// useful in parsing NMEA sentences
|
|
||||||
int explode_string(char *str, char *strp[], int limit, char delim, char quote);
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* INC_UTILS_H_ */
|
|
|
@ -1,398 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: beacon.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: Beacon task. Sends a beacon frame periodically, based on timer in the setup
|
|
||||||
structure. The beacon include position data in a readable format, which
|
|
||||||
can come from a GPS receiver or the setup struct. Lat/Long data
|
|
||||||
is sent in DDMM.MMMMM format.
|
|
||||||
|
|
||||||
Define __ENABLE_GPS to enable the code.
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <cmsis_os2.h>
|
|
||||||
#include <FreeRTOS.h>
|
|
||||||
#include <stm32wl3x_hal.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "tasks.h"
|
|
||||||
#include "setup.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "tod.h"
|
|
||||||
#include "usart.h"
|
|
||||||
|
|
||||||
// config
|
|
||||||
#define __SPEED_DAEMON 0 // send beacon every 5 seconds for testing purposes
|
|
||||||
|
|
||||||
// local defines
|
|
||||||
#define MAX_BEACON 80 // max beacon string
|
|
||||||
#define GPS_FIX_LEN 20 // gps fix length
|
|
||||||
#define GPS_BFR_SIZE 140 // GPS buffer size
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// NMEA GGA Sentence fields
|
|
||||||
char *nmeaMsgTag = "RMC"; // sentence we are processing
|
|
||||||
enum {
|
|
||||||
NMEA_TAG=0, // message tag
|
|
||||||
NMEA_TIMESTAMP, // time of fix'
|
|
||||||
NMEA_STATUS, // status
|
|
||||||
NMEA_LATITUDE, // latitude
|
|
||||||
NMEA_NS_HEMI, // latitude hemisphere
|
|
||||||
NMEA_LONGITUDE, // longitude
|
|
||||||
NMEA_EW_HEMI, // longitude hemisphere
|
|
||||||
NMEA_MIN_FLDS // minimum fields in GPS message
|
|
||||||
};
|
|
||||||
|
|
||||||
// NMEA processing states
|
|
||||||
enum {
|
|
||||||
NMEA_STATE_SOM=0, // start of message
|
|
||||||
NMEA_STATE_MSG, // in the message
|
|
||||||
};
|
|
||||||
|
|
||||||
#define N_NMEA_SEN 14 // number of NMEA sentences
|
|
||||||
enum {
|
|
||||||
NMEA_CMD_DISABLED=0, // disabled
|
|
||||||
NMEA_CMD_ONCE, // once per fix
|
|
||||||
NMEA_CMD_2FIX, // once every 2 fixes
|
|
||||||
NMEA_CMD_3FIX, // once every 3 fixes
|
|
||||||
NMEA_CMD_4FIX, // once every 4 fixes
|
|
||||||
NMEA_CMD_5FIX, // once every 5 fixes
|
|
||||||
};
|
|
||||||
|
|
||||||
char *nmeaCmd = "$PMTK314"; // command
|
|
||||||
uint8_t senCmds[N_NMEA_SEN] = {
|
|
||||||
NMEA_CMD_DISABLED, // 0:GLL disabled
|
|
||||||
NMEA_CMD_ONCE, // 1: RMC once
|
|
||||||
NMEA_CMD_DISABLED, // 2: VTG disabled
|
|
||||||
NMEA_CMD_DISABLED, // 3: GGA disabled
|
|
||||||
NMEA_CMD_DISABLED, // 4: GSA disabled
|
|
||||||
NMEA_CMD_DISABLED, // 5: GSV disabled
|
|
||||||
NMEA_CMD_DISABLED, // 6 not used
|
|
||||||
NMEA_CMD_DISABLED, // 7
|
|
||||||
NMEA_CMD_DISABLED, // 13
|
|
||||||
NMEA_CMD_DISABLED, // 14
|
|
||||||
NMEA_CMD_DISABLED, // 15
|
|
||||||
NMEA_CMD_DISABLED, // 16
|
|
||||||
NMEA_CMD_DISABLED, // 17
|
|
||||||
NMEA_CMD_DISABLED // 18
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// hemispheres
|
|
||||||
enum {
|
|
||||||
N_HEMI=0, // North
|
|
||||||
S_HEMI, // South
|
|
||||||
E_HEMI, // East
|
|
||||||
W_HEMI, // West
|
|
||||||
N_HEMIS
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t hemispheres[N_HEMIS] = {
|
|
||||||
'N', 'S', 'E', 'W'
|
|
||||||
};
|
|
||||||
|
|
||||||
uint32_t timerInitValue; // value to initialize timer
|
|
||||||
uint32_t timerCtrValue; // current counter
|
|
||||||
BEACON_HEADER beacon_hdr; // beacon header
|
|
||||||
uint8_t bcnPayload[MAX_BEACON]; // beacon payload
|
|
||||||
BOOL gpsMessageRx = FALSE;
|
|
||||||
BOOL GPSBusy=FALSE;
|
|
||||||
TIMEOFDAY wallClockTime;
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// data for GPS
|
|
||||||
uint8_t GPSMsgBuf[GPS_BFR_SIZE];
|
|
||||||
uint8_t GPSEchoBuf[GPS_BFR_SIZE];
|
|
||||||
uint8_t GPSProcBuf[GPS_BFR_SIZE];
|
|
||||||
uint8_t *GPSBufPtr;
|
|
||||||
uint8_t GPSMsgSize;
|
|
||||||
uint8_t NMEAState;
|
|
||||||
char cmdBuf[MAX_BEACON];
|
|
||||||
//
|
|
||||||
BOOL haveGPSFix = FALSE;
|
|
||||||
BOOL gpsEchoReady=FALSE;
|
|
||||||
//
|
|
||||||
char GPSLat[GPS_FIX_LEN];
|
|
||||||
char GPSLong[GPS_FIX_LEN];
|
|
||||||
char GPSFixTime[GPS_FIX_LEN];
|
|
||||||
char *gpsFlds[GPS_BFR_SIZE];
|
|
||||||
|
|
||||||
// fwd Refs in this module in GPS mode
|
|
||||||
BOOL processGPSMessage(uint8_t *GPSMsgBuf, uint8_t bufferSize);
|
|
||||||
void sendGPSCmd(void);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//fwd refs w/o GPS
|
|
||||||
void GPSFormat(char *buffer, double value, uint8_t hePos, uint8_t heNeg);
|
|
||||||
|
|
||||||
// initialization: calculate the init value in
|
|
||||||
// quanta of MAIN_TASK_SCHED
|
|
||||||
void Beacon_Task_init(void)
|
|
||||||
{
|
|
||||||
// higher speed for testing...
|
|
||||||
#if __SPEED_DAEMON
|
|
||||||
timerInitValue = 5 *1000/MAIN_TASK_SCHED; // every 5 seconds for testing
|
|
||||||
timerCtrValue = 0;
|
|
||||||
#else
|
|
||||||
uint32_t timerTick = 60 * 1000/MAIN_TASK_SCHED;
|
|
||||||
timerInitValue = setup_memory.params.setup_data.beaconInt * timerTick;
|
|
||||||
timerCtrValue = 0; // set to timerInitValue to wait
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// GPS Init
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
gpsMessageRx = FALSE;
|
|
||||||
haveGPSFix = FALSE;
|
|
||||||
gpsEchoReady = FALSE;
|
|
||||||
GPSBufPtr = GPSMsgBuf;
|
|
||||||
GPSBusy = FALSE;
|
|
||||||
NMEAState=NMEA_STATE_SOM;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// this runs every MAIN_TASK_SCHED ms
|
|
||||||
void Beacon_Task_exec(void)
|
|
||||||
{
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
if(gpsMessageRx) {
|
|
||||||
// process the message
|
|
||||||
if(processGPSMessage(GPSProcBuf, (uint8_t)strlen((char *)GPSProcBuf))) {
|
|
||||||
haveGPSFix = TRUE;
|
|
||||||
}
|
|
||||||
gpsMessageRx = FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if(timerCtrValue > 0) {
|
|
||||||
timerCtrValue--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
timerCtrValue = timerInitValue;
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// send a command to the GPS every beacon interval
|
|
||||||
sendGPSCmd();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// start with the header
|
|
||||||
beacon_hdr.setup.flags = setup_memory.params.setup_data.flags;
|
|
||||||
beacon_hdr.setup.txPower = setup_memory.params.radio_setup.outputPower;
|
|
||||||
uint8_t *buf = bcnPayload;
|
|
||||||
|
|
||||||
// brute force copy: compiler rounds SETUP_FLAGS to 32 bits
|
|
||||||
*buf++ = beacon_hdr.hdrBytes[0];
|
|
||||||
*buf++ = beacon_hdr.hdrBytes[4];
|
|
||||||
|
|
||||||
char *pPayload = (char *)buf;
|
|
||||||
char *p2 = pPayload;
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
//GPS generated payload
|
|
||||||
if(haveGPSFix) {
|
|
||||||
strcpy(pPayload, "GPS,");
|
|
||||||
strcat(pPayload, GPSLat);
|
|
||||||
strcat(pPayload, ",");
|
|
||||||
strcat(pPayload, GPSLong);
|
|
||||||
strcat(pPayload, ",");
|
|
||||||
strcat(pPayload, GPSFixTime);
|
|
||||||
strcat(pPayload, ",");
|
|
||||||
} else {
|
|
||||||
#endif
|
|
||||||
// setup struct generated payload
|
|
||||||
strcpy(pPayload, "FXD,");
|
|
||||||
pPayload += strlen(pPayload);
|
|
||||||
double dlat = ascii2double(setup_memory.params.setup_data.latitude);
|
|
||||||
GPSFormat(pPayload, dlat, N_HEMI, S_HEMI);
|
|
||||||
strcat(pPayload, ",");
|
|
||||||
pPayload += strlen(pPayload);
|
|
||||||
double dlong = ascii2double(setup_memory.params.setup_data.longitude);
|
|
||||||
GPSFormat(pPayload, dlong, E_HEMI, W_HEMI);
|
|
||||||
strcat(pPayload, ",,");
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
pPayload += strlen(pPayload);
|
|
||||||
|
|
||||||
// Use RTC for time
|
|
||||||
getTOD(&wallClockTime);
|
|
||||||
sprintf(pPayload, "%02d%02d%02d", wallClockTime.Hours, wallClockTime.Minutes, wallClockTime.Seconds);
|
|
||||||
strcat(pPayload, ",");
|
|
||||||
|
|
||||||
// home grid square
|
|
||||||
strcat(pPayload, setup_memory.params.setup_data.gridSq);
|
|
||||||
|
|
||||||
// firmware version
|
|
||||||
int pos = strlen((char *)p2);
|
|
||||||
buf[pos++] = def_params.params.FirmwareVerMajor + '0';
|
|
||||||
buf[pos++] = def_params.params.FirmwareVerMinor + '0';
|
|
||||||
buf[pos++] = '\0'; // null terminated
|
|
||||||
|
|
||||||
// time to send a beacon frame..
|
|
||||||
SendBeaconFrame(setup_memory.params.setup_data.stnCall, bcnPayload, pos+1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Format the +/-ddd.dddd lat/long format into DDMM.MMMMM format
|
|
||||||
*/
|
|
||||||
void GPSFormat(char *buffer, double value, uint8_t hePos, uint8_t heNeg)
|
|
||||||
{
|
|
||||||
// Set hemi, get abs value
|
|
||||||
uint8_t hemi = value > 0.00 ? hePos : heNeg;
|
|
||||||
value = fabs(value);
|
|
||||||
|
|
||||||
// separate whole and fractional
|
|
||||||
int whole = (int)value;
|
|
||||||
double fract = value - (double)whole;
|
|
||||||
|
|
||||||
// calculate minutes and fraction
|
|
||||||
double dmin = 60.0 * fract;
|
|
||||||
dmin = round(dmin * 100.0)/100.0;
|
|
||||||
|
|
||||||
int min = floor(dmin);
|
|
||||||
int ifract = (int)ceil((dmin-min) * 100000);
|
|
||||||
|
|
||||||
sprintf(buffer, "%d%02d.%05d%c", whole, min, ifract, hemispheres[hemi]);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Process GPS data from LPUART: runs at a higher priority
|
|
||||||
*/
|
|
||||||
void GPS_Task_exec(void)
|
|
||||||
{
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
char c;
|
|
||||||
int nBytesinBuff;
|
|
||||||
|
|
||||||
if((nBytesinBuff=gpsbuffer_bytesInBuffer()) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
for(int i=0;i<nBytesinBuff;i++) {
|
|
||||||
c = (char)gpsbuffer_get(0);
|
|
||||||
|
|
||||||
switch(NMEAState) {
|
|
||||||
|
|
||||||
// waiting for a start of message
|
|
||||||
case NMEA_STATE_SOM:
|
|
||||||
if(c != '$')
|
|
||||||
break;
|
|
||||||
GPSBufPtr = GPSMsgBuf;
|
|
||||||
NMEAState=NMEA_STATE_MSG;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// collecting chars in a message
|
|
||||||
case NMEA_STATE_MSG:
|
|
||||||
*GPSBufPtr++ = c;
|
|
||||||
GPSMsgSize = GPSBufPtr - GPSMsgBuf;
|
|
||||||
if((c == '*') || (GPSMsgSize >= GPS_BFR_SIZE)) {
|
|
||||||
*GPSBufPtr = '\0';
|
|
||||||
GPSMsgSize++;
|
|
||||||
memcpy(GPSEchoBuf, GPSMsgBuf, GPSMsgSize);
|
|
||||||
gpsMessageRx = TRUE;
|
|
||||||
memcpy(GPSProcBuf, GPSMsgBuf, GPSMsgSize);
|
|
||||||
memcpy(GPSEchoBuf, GPSMsgBuf, GPSMsgSize);
|
|
||||||
gpsEchoReady = TRUE;
|
|
||||||
NMEAState=NMEA_STATE_SOM;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
return; // unused code
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
/*
|
|
||||||
* Send a command to the GPS device to limit traffic
|
|
||||||
*/
|
|
||||||
void sendGPSCmd(void)
|
|
||||||
{
|
|
||||||
uint8_t cksum = 0;
|
|
||||||
char *buf = cmdBuf;
|
|
||||||
strcpy(buf, nmeaCmd);
|
|
||||||
buf += strlen(nmeaCmd);
|
|
||||||
|
|
||||||
for(int j=1;j<strlen(nmeaCmd);j++)
|
|
||||||
cksum ^= nmeaCmd[j];
|
|
||||||
|
|
||||||
for(int i=0;i<N_NMEA_SEN;i++) {
|
|
||||||
*buf = ',';
|
|
||||||
cksum ^= *buf++;
|
|
||||||
*buf = senCmds[i] + '0';
|
|
||||||
cksum ^= *buf++;
|
|
||||||
}
|
|
||||||
|
|
||||||
*buf++ = '*';
|
|
||||||
hex2ascii(cksum, buf);
|
|
||||||
buf += 2;
|
|
||||||
|
|
||||||
*buf++ = '\r';
|
|
||||||
*buf++ = '\n';
|
|
||||||
*buf = '\0';
|
|
||||||
uint16_t buflen = buf - cmdBuf;
|
|
||||||
|
|
||||||
LPUART_Send_String(cmdBuf, buflen);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Process an inbound GPS message
|
|
||||||
*/
|
|
||||||
BOOL processGPSMessage(uint8_t *GPSdata, uint8_t bufferSize)
|
|
||||||
{
|
|
||||||
char *msg = (char *)GPSdata;
|
|
||||||
uint8_t nParams = explode_string(msg, gpsFlds, bufferSize, ',', '"');
|
|
||||||
if ((nParams == 0) || (nParams < NMEA_MIN_FLDS))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// brute force position fix
|
|
||||||
// check for message with GGA at the end
|
|
||||||
char *gpsTag = gpsFlds[NMEA_TAG];
|
|
||||||
gpsTag += strlen(gpsTag)-strlen(nmeaMsgTag);
|
|
||||||
if(strcmp(gpsTag, nmeaMsgTag))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
strcpy(GPSFixTime, gpsFlds[NMEA_TIMESTAMP]);
|
|
||||||
|
|
||||||
strcpy(GPSLat, gpsFlds[NMEA_LATITUDE]);
|
|
||||||
strcat(GPSLat, gpsFlds[NMEA_NS_HEMI]);
|
|
||||||
|
|
||||||
strcpy(GPSLong, gpsFlds[NMEA_LONGITUDE]);
|
|
||||||
strcat(GPSLong, gpsFlds[NMEA_EW_HEMI]);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* echo the last GPS message on the console
|
|
||||||
*/
|
|
||||||
void GPSEcho(void)
|
|
||||||
{
|
|
||||||
if(!gpsEchoReady)
|
|
||||||
return;
|
|
||||||
|
|
||||||
USART_Print_string("%s\r\n", (char *)GPSEchoBuf);
|
|
||||||
gpsEchoReady=FALSE;
|
|
||||||
}
|
|
||||||
#endif
|
|
|
@ -1,194 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: IP400
|
|
||||||
|
|
||||||
Module: Compress and expand a callsign
|
|
||||||
|
|
||||||
File Name: callsign.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 9, 2025
|
|
||||||
|
|
||||||
Description: Comresses an ASCII string of callsign characters. A callsign can
|
|
||||||
have up to 6 characters to fit into the four byte field, if longer
|
|
||||||
the rest are placed in the payload of the data frame. Callsigns can
|
|
||||||
be extended with a '-' character, in this case the call is removed
|
|
||||||
and padded before conversion, and the remainder is also in the
|
|
||||||
frame payload.
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "frame.h"
|
|
||||||
|
|
||||||
#define RADIX_40 40 // alphabet radix
|
|
||||||
|
|
||||||
// Radix 40 callsign alphabet
|
|
||||||
char alphabet[RADIX_40] = {
|
|
||||||
// 0 1 2 3 4 5 6 7 8 9
|
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
||||||
|
|
||||||
// 10 11 12 13 14 15 16 17 18 19
|
|
||||||
' ', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I',
|
|
||||||
|
|
||||||
// 20 21 22 23 24 25 26 27 28 29
|
|
||||||
'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S',
|
|
||||||
|
|
||||||
// 30 31 32 33 34 35 36 37 38 39
|
|
||||||
'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '(', ')', '-'
|
|
||||||
};
|
|
||||||
|
|
||||||
// encode a char into the alphabet
|
|
||||||
uint32_t alphaEncode(char byte)
|
|
||||||
{
|
|
||||||
byte = islower(byte) ? toupper(byte) : byte;
|
|
||||||
|
|
||||||
for(uint32_t i=0;i<RADIX_40;i++) {
|
|
||||||
if(alphabet[i] == byte)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode a byte back into ASCII
|
|
||||||
char alphaDecode(uint32_t alpha)
|
|
||||||
{
|
|
||||||
// numeric
|
|
||||||
if((alpha >= 0) && (alpha <= 9))
|
|
||||||
return '0' + alpha;
|
|
||||||
|
|
||||||
// special cases: see alphabet table
|
|
||||||
|
|
||||||
switch(alpha) {
|
|
||||||
|
|
||||||
case 10:
|
|
||||||
return ' ';
|
|
||||||
|
|
||||||
case 37:
|
|
||||||
return '(';
|
|
||||||
|
|
||||||
case 38:
|
|
||||||
return ')';
|
|
||||||
|
|
||||||
case 39:
|
|
||||||
return '@';
|
|
||||||
|
|
||||||
default:
|
|
||||||
return 'A' + (alpha - 11);
|
|
||||||
}
|
|
||||||
return ' ';
|
|
||||||
}
|
|
||||||
|
|
||||||
void EncodeChunk(char *src, int len, uint32_t *enc)
|
|
||||||
{
|
|
||||||
uint32_t chunk=alphaEncode(src[0]);
|
|
||||||
|
|
||||||
// less than 2 characters
|
|
||||||
if(len < 2) {
|
|
||||||
*enc = chunk;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2 or more
|
|
||||||
for(int i=1;i<len;i++) {
|
|
||||||
uint32_t current = alphaEncode(src[i]);
|
|
||||||
chunk = current + chunk*RADIX_40;
|
|
||||||
}
|
|
||||||
*enc = chunk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// encode a callsign: if less than max_call, then just encode into the frame,
|
|
||||||
// else continue in the data portion of the frame
|
|
||||||
uint8_t callEncode(char *callsign, uint16_t port, IP400_FRAME *frame, uint8_t dest, uint8_t offset)
|
|
||||||
{
|
|
||||||
int len = strlen(callsign);
|
|
||||||
|
|
||||||
uint32_t encChunk;
|
|
||||||
uint32_t *p = (uint32_t *)frame->buf;
|
|
||||||
p += offset;
|
|
||||||
|
|
||||||
if(dest == DEST_CALLSIGN)
|
|
||||||
frame->dest.port = port;
|
|
||||||
else
|
|
||||||
frame->source.port = port;
|
|
||||||
|
|
||||||
// broadcast address
|
|
||||||
if(!strcmp(callsign, "FFFF")) {
|
|
||||||
if(dest == DEST_CALLSIGN)
|
|
||||||
frame->dest.callbytes.encoded = 0xFFFFFFFF;
|
|
||||||
else
|
|
||||||
frame->source.callbytes.encoded = 0xFFFFFFFF;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ensure the callsign is padded out to at least 6 characters
|
|
||||||
char paddedCall[50];
|
|
||||||
strcpy(paddedCall, callsign);
|
|
||||||
strcat(paddedCall, " ");
|
|
||||||
|
|
||||||
// non-broadcast: break it up into chunks of 6 characters
|
|
||||||
int nChunks = len/MAX_CALL;
|
|
||||||
if ((len % MAX_CALL) > 0)
|
|
||||||
nChunks++;
|
|
||||||
|
|
||||||
char *cll = paddedCall;
|
|
||||||
|
|
||||||
for(int k=0;k<nChunks;k++) {
|
|
||||||
EncodeChunk(cll, MAX_CALL, &encChunk);
|
|
||||||
if(k==0) {
|
|
||||||
if(dest == DEST_CALLSIGN)
|
|
||||||
frame->dest.callbytes.encoded = encChunk;
|
|
||||||
else
|
|
||||||
frame->source.callbytes.encoded = encChunk;
|
|
||||||
// callsign less than or equal to MAX_CALL
|
|
||||||
if(nChunks == 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
*p++ = encChunk;
|
|
||||||
cll += MAX_CALL;
|
|
||||||
if(dest == DEST_CALLSIGN)
|
|
||||||
frame->flagfld.flags.destExt = TRUE;
|
|
||||||
else
|
|
||||||
frame->flagfld.flags.srcExt = TRUE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*p++ = 0xFF000000;
|
|
||||||
// return the offset in the buffer
|
|
||||||
return (p-(uint32_t *)frame->buf) + sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
// decode a callsign
|
|
||||||
BOOL callDecode(IP400_CALL *encCall, char *callsign, uint16_t *port)
|
|
||||||
{
|
|
||||||
char tmpBuf[10], *p = tmpBuf;
|
|
||||||
int i;
|
|
||||||
|
|
||||||
uint32_t encoded = encCall->callbytes.encoded;
|
|
||||||
for(i=0;i<MAX_CALL;i++) {
|
|
||||||
*p++ = alphaDecode(encoded % RADIX_40);
|
|
||||||
encoded /= RADIX_40;
|
|
||||||
}
|
|
||||||
*p = '\0';
|
|
||||||
for(i=strlen(tmpBuf)-1;i>=0;i--)
|
|
||||||
*callsign++ = tmpBuf[i];
|
|
||||||
|
|
||||||
*callsign = '\0';
|
|
||||||
*port = encCall->port;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
|
@ -1,297 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: chat.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: This code contains the chat application. It gathers key until the CR
|
|
||||||
is hit to send a packet. Two internal operations are exit and set the
|
|
||||||
destination.
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
#include "setup.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "streambuffer.h"
|
|
||||||
#include "dataq.h"
|
|
||||||
|
|
||||||
#define MAX_KEY 140 // max keys in a buffer
|
|
||||||
#define MAX_DEST 20 // max chars in dest callsign
|
|
||||||
#define BROADCAST "FFFF" // broadcast address
|
|
||||||
|
|
||||||
static char keyBuffer[MAX_KEY]; // buffer for keystrokes
|
|
||||||
uint8_t keyPos; // current position
|
|
||||||
|
|
||||||
#define KEY_EOL 0x0D // carriage return
|
|
||||||
#define KEY_RPT 0x12 // change repeat status
|
|
||||||
#define KEY_EXIT 0x1A // exit key
|
|
||||||
#define KEY_ESC 0x1B // escape key
|
|
||||||
#define KEY_DEL 0x7F // delete key
|
|
||||||
#define KEY_BKSP 0x08 // backspace key
|
|
||||||
#define KEY_DUMP 0x04 // toggle dump mode
|
|
||||||
|
|
||||||
char dest_call[MAX_DEST]; // broadcast destination
|
|
||||||
char *dp = dest_call; // pointer to dest call characters
|
|
||||||
char *entCall = "Enter Destination Callsign";
|
|
||||||
char *rptMode[] = {
|
|
||||||
"Repeat mode->off",
|
|
||||||
"Repeat mode->on"
|
|
||||||
};
|
|
||||||
|
|
||||||
char *dumpStrings[] = {
|
|
||||||
"Dump mode->off",
|
|
||||||
"Dump mode->on"
|
|
||||||
};
|
|
||||||
|
|
||||||
char *welcome = "Welcome to chat. ESC to set destination, CTRL/R to toggle repeat, CTRL/Z to exit";
|
|
||||||
|
|
||||||
BOOL destEnt = FALSE; // not entering destination
|
|
||||||
BOOL repeat = TRUE; // repeating by default
|
|
||||||
BOOL deleteMode = FALSE; // delete mode
|
|
||||||
BOOL welcomed = FALSE; // welcome mat is out
|
|
||||||
BOOL dumpMode = FALSE;
|
|
||||||
|
|
||||||
FRAME_QUEUE chatQueue; // queue for inbound frames
|
|
||||||
|
|
||||||
// fwd refs
|
|
||||||
void sendLine(char *buffer, int len);
|
|
||||||
void PrintFrame(IP400_FRAME *FrameBytes);
|
|
||||||
|
|
||||||
// init entry
|
|
||||||
void Chat_Task_init(void)
|
|
||||||
{
|
|
||||||
strcpy(dest_call, BROADCAST);
|
|
||||||
destEnt = FALSE;
|
|
||||||
chatQueue.q_forw = &chatQueue;
|
|
||||||
chatQueue.q_back = &chatQueue;
|
|
||||||
keyPos = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Chat_Task_welcome(void)
|
|
||||||
{
|
|
||||||
// start with welcome message
|
|
||||||
USART_Print_string("%s\r\n", welcome);
|
|
||||||
USART_Print_string("%s; ", rptMode[repeat]);
|
|
||||||
|
|
||||||
if(!strcmp(dest_call, BROADCAST))
|
|
||||||
USART_Print_string("%s; Destination callsign->(Broadcast)\r\n\n");
|
|
||||||
else
|
|
||||||
USART_Print_string("%s; Destination callsign->%s\r\n\n", dest_call);
|
|
||||||
|
|
||||||
welcomed = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* place a frame on the queue frame content is copied
|
|
||||||
* to alloc'd memory
|
|
||||||
*/
|
|
||||||
BOOL EnqueChatFrame(void *raw)
|
|
||||||
{
|
|
||||||
IP400_FRAME *qFrame, *SrcFrame = (IP400_FRAME *)raw;
|
|
||||||
uint8_t *frameBuffer;
|
|
||||||
|
|
||||||
// allocate an IP400 frame
|
|
||||||
if((qFrame=malloc(sizeof(IP400_FRAME)))== NULL)
|
|
||||||
return FALSE;
|
|
||||||
memcpy(qFrame, SrcFrame, sizeof(IP400_FRAME));
|
|
||||||
|
|
||||||
// alloc the data portion of the frame
|
|
||||||
if((frameBuffer=malloc(SrcFrame->length)) == NULL) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(frameBuffer, (uint8_t *)SrcFrame->buf, SrcFrame->length);
|
|
||||||
qFrame->buf = frameBuffer;
|
|
||||||
qFrame->length = SrcFrame->length;
|
|
||||||
|
|
||||||
if(!enqueFrame(&chatQueue, qFrame))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* chat task main entry
|
|
||||||
* return: TRUE if return to main menu is required
|
|
||||||
* FALSE: more to go
|
|
||||||
*/
|
|
||||||
BOOL Chat_Task_exec(void)
|
|
||||||
{
|
|
||||||
if(!welcomed)
|
|
||||||
Chat_Task_welcome();
|
|
||||||
|
|
||||||
char c;
|
|
||||||
int nBytesinBuff;
|
|
||||||
IP400_FRAME *fr;
|
|
||||||
|
|
||||||
// process any inbound frames first..
|
|
||||||
if((fr=dequeFrame(&chatQueue)) != NULL) {
|
|
||||||
PrintFrame(fr);
|
|
||||||
free(fr->buf);
|
|
||||||
free(fr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
for(int i=0;i<nBytesinBuff;i++) {
|
|
||||||
|
|
||||||
c=databuffer_get(0);
|
|
||||||
|
|
||||||
if(deleteMode) {
|
|
||||||
if((c != KEY_DEL) && (c != KEY_BKSP)) {
|
|
||||||
USART_Print_string("\\%c", c);
|
|
||||||
if(keyPos < MAX_KEY)
|
|
||||||
keyBuffer[keyPos++] = c;
|
|
||||||
deleteMode = FALSE;
|
|
||||||
} else {
|
|
||||||
if(keyPos > 0) {
|
|
||||||
USART_Print_string("%c", keyBuffer[--keyPos]);
|
|
||||||
} else {
|
|
||||||
USART_Print_string("\\\r\n");
|
|
||||||
deleteMode = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// processing a key
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
|
|
||||||
// CTRL/R: change repeat flag
|
|
||||||
case KEY_RPT:
|
|
||||||
repeat = repeat ? FALSE : TRUE;
|
|
||||||
char *r = rptMode[repeat];
|
|
||||||
USART_Print_string("%s\r\n",r);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// CTRL/D: change dump mode
|
|
||||||
case KEY_DUMP:
|
|
||||||
dumpMode = dumpMode ? FALSE : TRUE;
|
|
||||||
char *d = dumpStrings[dumpMode];
|
|
||||||
USART_Print_string("%s\r\n",d);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// escape key: get a destination call sign
|
|
||||||
case KEY_ESC:
|
|
||||||
if(destEnt) {
|
|
||||||
strcpy(dest_call, BROADCAST);
|
|
||||||
USART_Print_string("Destination set to broadcast\r\n");
|
|
||||||
destEnt=FALSE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if(keyPos == 0) {
|
|
||||||
USART_Print_string("%s->", entCall);
|
|
||||||
dp = dest_call;
|
|
||||||
destEnt = TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
// EOL key: sent the packet
|
|
||||||
case KEY_EOL:
|
|
||||||
USART_Print_string("\r\n");
|
|
||||||
if(destEnt) {
|
|
||||||
int cpyLen = keyPos > MAX_CALL ? MAX_CALL : keyPos;
|
|
||||||
strncpy(dest_call, keyBuffer, cpyLen);
|
|
||||||
destEnt = FALSE;
|
|
||||||
} else {
|
|
||||||
if(keyPos != 0) {
|
|
||||||
keyBuffer[keyPos++] = '\0';
|
|
||||||
sendLine(keyBuffer, keyPos);
|
|
||||||
} else {
|
|
||||||
USART_Print_string(">>>not sent\r\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
keyPos = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KEY_EXIT:
|
|
||||||
welcomed = FALSE;
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
case KEY_DEL:
|
|
||||||
case KEY_BKSP:
|
|
||||||
if(keyPos > 0) {
|
|
||||||
USART_Print_string("\\%c", keyBuffer[--keyPos]);
|
|
||||||
deleteMode = TRUE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USART_Send_Char(c);
|
|
||||||
if(keyPos < MAX_KEY)
|
|
||||||
keyBuffer[keyPos++] = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a line of text
|
|
||||||
void sendLine(char *buffer, int len)
|
|
||||||
{
|
|
||||||
SendTextFrame(setup_memory.params.setup_data.stnCall, TEXT_TYPE, dest_call, TEXT_TYPE, buffer, len, repeat);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print a received frame on the console
|
|
||||||
*/
|
|
||||||
void PrintFrame(IP400_FRAME *FrameBytes)
|
|
||||||
{
|
|
||||||
char printBuf[250];
|
|
||||||
char decCall[100];
|
|
||||||
uint16_t port;
|
|
||||||
uint16_t dataLen = FrameBytes->length;
|
|
||||||
|
|
||||||
// dump mode for header debugging
|
|
||||||
if(dumpMode) {
|
|
||||||
/* print the received data */
|
|
||||||
USART_Print_string("RX - Data received: [ ");
|
|
||||||
|
|
||||||
for(uint8_t i=0; i<sizeof(IP400_FRAME); i++)
|
|
||||||
USART_Print_string("%02x ", FrameBytes[i]);
|
|
||||||
|
|
||||||
USART_Print_string("]\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// source call
|
|
||||||
callDecode(&FrameBytes->source, decCall, &port);
|
|
||||||
USART_Print_string("%s(%d)>", decCall, port);
|
|
||||||
|
|
||||||
// dest call
|
|
||||||
if((FrameBytes->dest.callbytes.bytes[0] == BROADCAST_ADDR) &&
|
|
||||||
(FrameBytes->dest.callbytes.bytes[1] == BROADCAST_ADDR)) {
|
|
||||||
USART_Print_string("BROADCAST(%d)", FrameBytes->dest.port);
|
|
||||||
} else {
|
|
||||||
callDecode(&FrameBytes->dest, decCall, &port);
|
|
||||||
USART_Print_string("%s(%d)", decCall, port);
|
|
||||||
}
|
|
||||||
|
|
||||||
// flags
|
|
||||||
USART_Print_string("[%d:%04d]:", FrameBytes->flagfld.flags.hop_count, FrameBytes->seqNum);
|
|
||||||
|
|
||||||
// now dump the data
|
|
||||||
memcpy(printBuf, FrameBytes->buf, dataLen);
|
|
||||||
printBuf[dataLen] = '\0';
|
|
||||||
USART_Print_string("%s\r\n", printBuf);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,67 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: dataq.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: This module enques and deques an IP400 Frame type on a queue
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <malloc.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "dataq.h"
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enque a frame. The frame data buffer must have
|
|
||||||
* alredy been allocated
|
|
||||||
*/
|
|
||||||
BOOL enqueFrame(FRAME_QUEUE *que, IP400_FRAME *fr)
|
|
||||||
{
|
|
||||||
FRAME_QUEUE *f;
|
|
||||||
if((f = malloc(sizeof(FRAME_QUEUE))) == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// set the frame buffer
|
|
||||||
f->frame = fr;
|
|
||||||
f->length = fr->length + sizeof(IP400_FRAME);
|
|
||||||
|
|
||||||
insque((QUEUE_ELEM *)f, (QUEUE_ELEM *)que->q_back);
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Deqeue a frame
|
|
||||||
* Returns null if no frame is one the queue
|
|
||||||
* Does NOT dealloc data or frame or q
|
|
||||||
*/
|
|
||||||
IP400_FRAME *dequeFrame(FRAME_QUEUE *que)
|
|
||||||
{
|
|
||||||
IP400_FRAME *ipFrame;
|
|
||||||
|
|
||||||
if(que->q_back == que)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
FRAME_QUEUE *f = que->q_forw;
|
|
||||||
remque((struct qelem *)f);
|
|
||||||
|
|
||||||
ipFrame = f->frame;
|
|
||||||
|
|
||||||
free(f);
|
|
||||||
return ipFrame;
|
|
||||||
}
|
|
|
@ -1,501 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: IP400
|
|
||||||
|
|
||||||
Module: Frame transmit and receive tasks
|
|
||||||
|
|
||||||
File Name: frame.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Creation Date: Jan 8, 2025
|
|
||||||
|
|
||||||
Description: Handle the transmission and reception of frames
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <cmsis_os2.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
#include <stm32wl3x_hal_mrsubg.h>
|
|
||||||
#if _BOARD_TYPE==NUCLEO_BOARD
|
|
||||||
#include <stm32wl3x_nucleo.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <cmsis_os2.h>
|
|
||||||
#include <FreeRTOS.h>
|
|
||||||
#include <semphr.h>
|
|
||||||
|
|
||||||
#include "frame.h"
|
|
||||||
#include "dataq.h"
|
|
||||||
#include "setup.h"
|
|
||||||
#include "tasks.h"
|
|
||||||
#include "led.h"
|
|
||||||
|
|
||||||
// local defines
|
|
||||||
#define RX_TIMEOUT 2 // return to OS after 5 ms timeout
|
|
||||||
|
|
||||||
// conditionals
|
|
||||||
#define __DUMP_BEACON 0 // dump a beacon frame to console using chat
|
|
||||||
|
|
||||||
// transmit states
|
|
||||||
enum {
|
|
||||||
TX_IDLE=0, // idle - waiting for work
|
|
||||||
TX_SENDING, // sending a frame
|
|
||||||
TX_DONE // done
|
|
||||||
};
|
|
||||||
|
|
||||||
// locals
|
|
||||||
uint8_t txState; // transmitter state
|
|
||||||
uint8_t radioCmd; // current radio command
|
|
||||||
uint8_t prevCmd; // previous state
|
|
||||||
FRAME_QUEUE txQueue; // transmitter frame queue
|
|
||||||
uint32_t subgIRQStatus; // interrupt status
|
|
||||||
BOOL txDone; // transmitter is done
|
|
||||||
BOOL rxReady; // rx is ready...
|
|
||||||
FRAME_STATS Stats; // collected stats
|
|
||||||
uint32_t nextSeq; // next frame sequence number
|
|
||||||
|
|
||||||
// from setup...
|
|
||||||
int16_t rxSquelch; // rx squlech
|
|
||||||
|
|
||||||
// internal fwd references
|
|
||||||
void QueueTxFrame(IP400_FRAME *txframe); // send a frame
|
|
||||||
void EnableRx(void); // enable the rx
|
|
||||||
|
|
||||||
// receive raw frame: we are only interested
|
|
||||||
static uint8_t rawTxFrame[MAX_FRAME_SIZE];
|
|
||||||
static uint8_t rawRxFrame[MAX_FRAME_SIZE];
|
|
||||||
|
|
||||||
// processed frames
|
|
||||||
static IP400_FRAME rFrame;
|
|
||||||
|
|
||||||
// intialize the transmit task
|
|
||||||
void Frame_task_init(void)
|
|
||||||
{
|
|
||||||
txState = TX_IDLE;
|
|
||||||
txQueue.q_forw = &txQueue;
|
|
||||||
txQueue.q_back = &txQueue;
|
|
||||||
|
|
||||||
// init stats and counters
|
|
||||||
memset(&Stats, 0, sizeof(FRAME_STATS));
|
|
||||||
nextSeq = 0xFFFFFFFF;
|
|
||||||
|
|
||||||
// set Rx threshold
|
|
||||||
STN_PARAMS *params = GetStationParams();
|
|
||||||
rxSquelch = params->radio_setup.rxSquelch;
|
|
||||||
HAL_MRSubG_SetRSSIThreshold(rxSquelch);
|
|
||||||
|
|
||||||
// enable the interrupt
|
|
||||||
__HAL_MRSUBG_SET_RFSEQ_IRQ_ENABLE(
|
|
||||||
MR_SUBG_GLOB_DYNAMIC_RFSEQ_IRQ_ENABLE_RX_OK_E
|
|
||||||
| MR_SUBG_GLOB_DYNAMIC_RFSEQ_IRQ_ENABLE_TX_DONE_E
|
|
||||||
| MR_SUBG_GLOB_DYNAMIC_RFSEQ_IRQ_ENABLE_RX_TIMEOUT_E
|
|
||||||
| MR_SUBG_GLOB_DYNAMIC_RFSEQ_IRQ_ENABLE_RX_CRC_ERROR_E
|
|
||||||
);
|
|
||||||
HAL_NVIC_EnableIRQ(MR_SUBG_IRQn);
|
|
||||||
|
|
||||||
// enable the Rx
|
|
||||||
rxReady = FALSE;
|
|
||||||
EnableRx();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* return the stats
|
|
||||||
*/
|
|
||||||
FRAME_STATS *GetFrameStats(void)
|
|
||||||
{
|
|
||||||
return &Stats;
|
|
||||||
}
|
|
||||||
// return the radio status
|
|
||||||
uint32_t GetRadioStatus(void)
|
|
||||||
{
|
|
||||||
uint32_t radioStats = READ_REG(MR_SUBG_GLOB_STATUS->RFSEQ_STATUS_DETAIL);
|
|
||||||
return radioStats;
|
|
||||||
}
|
|
||||||
// get the FSM state
|
|
||||||
uint8_t GetFSMState(void)
|
|
||||||
{
|
|
||||||
uint32_t fsmState = READ_REG(MR_SUBG_GLOB_STATUS->RADIO_FSM_INFO);
|
|
||||||
return (uint8_t)(fsmState & MR_SUBG_GLOB_STATUS_RADIO_FSM_INFO_RADIO_FSM_STATE_Msk);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Send a text frame. Buf is not malloc'ed, can be static in ram
|
|
||||||
*/
|
|
||||||
BOOL SendTextFrame(char *srcCall, uint16_t srcPort, char *destCall, uint16_t dstPort, char *buf, uint16_t length, BOOL repeat)
|
|
||||||
{
|
|
||||||
IP400_FRAME *txFrame;
|
|
||||||
|
|
||||||
if((txFrame=malloc(sizeof(IP400_FRAME))) == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if((txFrame->buf=malloc(length + MAX_CALL_BUFFER)) == NULL)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
txFrame->flagfld.allflags = 0; // start with all flags cleared
|
|
||||||
|
|
||||||
// format the header
|
|
||||||
uint8_t offset = callEncode(srcCall, srcPort, txFrame, SRC_CALLSIGN, 0);
|
|
||||||
offset = callEncode(destCall, dstPort, txFrame, DEST_CALLSIGN, offset);
|
|
||||||
|
|
||||||
// copy the payload in
|
|
||||||
uint8_t *f = (uint8_t *)txFrame->buf;
|
|
||||||
f += offset*sizeof(uint32_t);
|
|
||||||
memcpy(f, (const uint8_t *)buf, length);
|
|
||||||
|
|
||||||
txFrame->length = length + offset;
|
|
||||||
txFrame->flagfld.flags.hop_count = 0;
|
|
||||||
txFrame->flagfld.flags.coding |= UTF8_TEXT_PACKET;
|
|
||||||
txFrame->flagfld.flags.repeat = repeat;
|
|
||||||
txFrame->seqNum = nextSeq++;
|
|
||||||
|
|
||||||
QueueTxFrame(txFrame);
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* compose and send a beacon frame (ping frame with broadcast destination
|
|
||||||
*/
|
|
||||||
void SendBeaconFrame(char *srcCall, uint8_t *payload, int bcnlen)
|
|
||||||
{
|
|
||||||
IP400_FRAME *bcnFrame;
|
|
||||||
|
|
||||||
if((bcnFrame=malloc(sizeof(IP400_FRAME))) == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if((bcnFrame->buf=malloc(bcnlen + MAX_CALL_BUFFER)) == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bcnFrame->flagfld.allflags = 0; // start with all flags cleared
|
|
||||||
|
|
||||||
// broadcast frame
|
|
||||||
uint8_t offset = callEncode(srcCall, ICMP_TYPE, bcnFrame, SRC_CALLSIGN, 0);
|
|
||||||
callEncode("FFFF", 0, bcnFrame, DEST_CALLSIGN, 0);
|
|
||||||
|
|
||||||
// adjust starting data point, add payload
|
|
||||||
uint8_t *f = (uint8_t *)bcnFrame->buf;
|
|
||||||
f += offset*sizeof(uint32_t);
|
|
||||||
memcpy(f, payload, bcnlen);
|
|
||||||
|
|
||||||
bcnFrame->length = bcnlen + offset;
|
|
||||||
bcnFrame->flagfld.flags.hop_count = 0;
|
|
||||||
bcnFrame->flagfld.flags.coding |= PING_PACKET;
|
|
||||||
bcnFrame->flagfld.flags.repeat = TRUE;
|
|
||||||
bcnFrame->seqNum = nextSeq++;
|
|
||||||
|
|
||||||
QueueTxFrame(bcnFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
// check to see if a frame came from me
|
|
||||||
// returns true if I originated the frame
|
|
||||||
BOOL FrameisMine(IP400_FRAME *frame)
|
|
||||||
{
|
|
||||||
char decCall[30];
|
|
||||||
uint16_t port;;
|
|
||||||
|
|
||||||
// check the originator call sign
|
|
||||||
callDecode(&frame->source, decCall, &port);
|
|
||||||
return(CompareToMyCall(decCall));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Repeat a frame. Do not send it if we were the originator
|
|
||||||
*/
|
|
||||||
void RepeatFrame(IP400_FRAME *frame)
|
|
||||||
{
|
|
||||||
IP400_FRAME *rptFrame;
|
|
||||||
|
|
||||||
// copy the frame
|
|
||||||
if((rptFrame=malloc(sizeof(IP400_FRAME))) == NULL)
|
|
||||||
return;
|
|
||||||
memcpy(rptFrame, frame, sizeof(IP400_FRAME));
|
|
||||||
|
|
||||||
// copy the data
|
|
||||||
rptFrame->length = frame->length;
|
|
||||||
if((rptFrame->buf=malloc(frame->length)) == NULL)
|
|
||||||
return;
|
|
||||||
memcpy(rptFrame->buf, frame->buf, frame->length);
|
|
||||||
|
|
||||||
// tick the hop count
|
|
||||||
rptFrame->flagfld.flags.hop_count += 1;
|
|
||||||
|
|
||||||
Stats.nRepeated++;
|
|
||||||
QueueTxFrame(rptFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* queue a frame for transmission by the tx task
|
|
||||||
*/
|
|
||||||
void QueueTxFrame(IP400_FRAME *txframe)
|
|
||||||
{
|
|
||||||
enqueFrame(&txQueue, txframe);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Enable the receiver
|
|
||||||
*/
|
|
||||||
void EnableRx(void)
|
|
||||||
{
|
|
||||||
__HAL_MRSUBG_SET_RX_MODE(RX_NORMAL);
|
|
||||||
__HAL_MRSUBG_SET_DATABUFFER_SIZE(MAX_FRAME_SIZE);
|
|
||||||
MR_SUBG_GLOB_STATIC->DATABUFFER0_PTR = (uint32_t)&rawRxFrame;
|
|
||||||
|
|
||||||
// set the command
|
|
||||||
radioCmd = CMD_RX;
|
|
||||||
__HAL_MRSUBG_STROBE_CMD(radioCmd);
|
|
||||||
|
|
||||||
SetLEDMode(BICOLOR_GREEN);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* main entry for tx task. Pick frames from the transmit queue
|
|
||||||
*/
|
|
||||||
void Frame_Txtask_exec(void)
|
|
||||||
{
|
|
||||||
static IP400_FRAME *tFrame;
|
|
||||||
int frameLen = 0;
|
|
||||||
|
|
||||||
switch(txState) {
|
|
||||||
|
|
||||||
// idle: waiting for work
|
|
||||||
case TX_IDLE:
|
|
||||||
|
|
||||||
tFrame = dequeFrame(&txQueue);
|
|
||||||
uint8_t *rawFrame = (uint8_t *)rawTxFrame;
|
|
||||||
|
|
||||||
if(tFrame == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
frameLen = tFrame->length;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Build the raw frame bytes: see IP400_FRAME struct
|
|
||||||
*/
|
|
||||||
// Source call + port (6 bytes)
|
|
||||||
memcpy(rawFrame, (uint8_t *)&tFrame->source, IP_400_CALL_SIZE);
|
|
||||||
rawFrame += IP_400_CALL_SIZE;
|
|
||||||
// Dest call + port (6 bytes)
|
|
||||||
memcpy(rawFrame, (uint8_t *)&tFrame->dest, IP_400_CALL_SIZE);
|
|
||||||
rawFrame += IP_400_CALL_SIZE;
|
|
||||||
// flag byte (2 byte)
|
|
||||||
memcpy(rawFrame, (uint8_t *)&tFrame->flagfld, IP_400_FLAG_SIZE);
|
|
||||||
rawFrame += IP_400_FLAG_SIZE;
|
|
||||||
// frame sequence number (4 bytes)
|
|
||||||
memcpy(rawFrame, (uint32_t *)&tFrame->seqNum, sizeof(uint32_t));
|
|
||||||
rawFrame += sizeof(uint32_t);
|
|
||||||
// frame length (2 bytes)
|
|
||||||
memcpy(rawFrame, (uint8_t *)&tFrame->length, sizeof(uint16_t));
|
|
||||||
rawFrame += IP_400_LEN_SIZE;
|
|
||||||
|
|
||||||
// and now the data...
|
|
||||||
if((tFrame->buf != NULL) && (tFrame->length != 0))
|
|
||||||
memcpy(rawFrame, tFrame->buf, tFrame->length);
|
|
||||||
|
|
||||||
// free the allocations in the reverse order...
|
|
||||||
if(tFrame->buf != NULL)
|
|
||||||
free(tFrame->buf);
|
|
||||||
|
|
||||||
free(tFrame);
|
|
||||||
|
|
||||||
// ensure packet length is a multiple of 4 bytes
|
|
||||||
int pktLen = (rawFrame - rawTxFrame) + frameLen;
|
|
||||||
pktLen += (pktLen % 4);
|
|
||||||
|
|
||||||
HAL_MRSubG_PktBasicSetPayloadLength(frameLen + pktLen);
|
|
||||||
|
|
||||||
// abort the current rx operation
|
|
||||||
if(radioCmd == CMD_RX) {
|
|
||||||
__HAL_MRSUBG_STROBE_CMD(CMD_SABORT);
|
|
||||||
uint32_t reject=0, abortDone=0;
|
|
||||||
do {
|
|
||||||
subgIRQStatus = READ_REG(MR_SUBG_GLOB_STATUS->RFSEQ_IRQ_STATUS);
|
|
||||||
reject = subgIRQStatus & MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_COMMAND_REJECTED_F;
|
|
||||||
abortDone = subgIRQStatus & MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_SABORT_DONE_F;
|
|
||||||
} while ((abortDone == 0) && (reject == 0));
|
|
||||||
if(abortDone)
|
|
||||||
__HAL_MRSUBG_CLEAR_RFSEQ_IRQ_FLAG(MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_SABORT_DONE_F);
|
|
||||||
if(reject)
|
|
||||||
__HAL_MRSUBG_CLEAR_RFSEQ_IRQ_FLAG(MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_COMMAND_REJECTED_F);
|
|
||||||
}
|
|
||||||
|
|
||||||
__HAL_MRSUBG_SET_DATABUFFER0_POINTER((uint32_t)rawTxFrame);
|
|
||||||
__HAL_MRSUBG_SET_TX_MODE(TX_NORMAL);
|
|
||||||
|
|
||||||
txDone = FALSE;
|
|
||||||
prevCmd = radioCmd;
|
|
||||||
radioCmd = CMD_TX;
|
|
||||||
__HAL_MRSUBG_STROBE_CMD(radioCmd);
|
|
||||||
|
|
||||||
// set tx indication: bicolor off and Tx on
|
|
||||||
SetLEDMode(BICOLOR_OFF);
|
|
||||||
SetLEDMode(TX_LED_ON);
|
|
||||||
|
|
||||||
txState = TX_SENDING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// sending a frame
|
|
||||||
case TX_SENDING:
|
|
||||||
// still busy sending
|
|
||||||
if(!txDone)
|
|
||||||
return;
|
|
||||||
|
|
||||||
txState = TX_DONE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// done
|
|
||||||
case TX_DONE:
|
|
||||||
// restart the receiver, if needed
|
|
||||||
EnableRx();
|
|
||||||
|
|
||||||
SetLEDMode(TX_LED_OFF);
|
|
||||||
txState = TX_IDLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Main entry of the rx task
|
|
||||||
*/
|
|
||||||
void Frame_Rxtask_exec(void)
|
|
||||||
{
|
|
||||||
// wait for completion..
|
|
||||||
if(!rxReady)
|
|
||||||
return;
|
|
||||||
rxReady = FALSE;
|
|
||||||
|
|
||||||
uint8_t *RxRaw = rawRxFrame;
|
|
||||||
uint8_t *cpyDest;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Do the opposite of the transmitter...
|
|
||||||
*/
|
|
||||||
// Source call + port (6 bytes)
|
|
||||||
cpyDest = (uint8_t *)&rFrame.source.callbytes.bytes;
|
|
||||||
memcpy(cpyDest, RxRaw, IP_400_CALL_SIZE);
|
|
||||||
RxRaw += IP_400_CALL_SIZE;
|
|
||||||
|
|
||||||
// Dest call + port (6 bytes)
|
|
||||||
cpyDest = (uint8_t *)&rFrame.dest.callbytes.bytes;
|
|
||||||
memcpy(cpyDest, RxRaw, IP_400_CALL_SIZE);
|
|
||||||
RxRaw += IP_400_CALL_SIZE;
|
|
||||||
|
|
||||||
// flag byte (2 byte)
|
|
||||||
cpyDest = (uint8_t *)&rFrame.flagfld.allflags;
|
|
||||||
memcpy(cpyDest, RxRaw, IP_400_FLAG_SIZE);
|
|
||||||
RxRaw += IP_400_FLAG_SIZE;
|
|
||||||
|
|
||||||
// frame sequence number (4 bytes)
|
|
||||||
cpyDest = (uint8_t *)&rFrame.seqNum;
|
|
||||||
memcpy(cpyDest, RxRaw, sizeof(uint32_t));
|
|
||||||
RxRaw += sizeof(uint32_t);
|
|
||||||
|
|
||||||
// frame length (2 bytes)
|
|
||||||
cpyDest = (uint8_t *)&rFrame.length;
|
|
||||||
memcpy(cpyDest, RxRaw, sizeof(uint16_t));
|
|
||||||
RxRaw += IP_400_LEN_SIZE;
|
|
||||||
|
|
||||||
rFrame.buf = RxRaw;
|
|
||||||
|
|
||||||
// find a reason to reject a frame...
|
|
||||||
BOOL isMine, isUniqueFrame;
|
|
||||||
isMine = FrameisMine(&rFrame);
|
|
||||||
if(!isMine)
|
|
||||||
isUniqueFrame = Mesh_Accept_Frame((void *)&rFrame, Stats.lastRSSI);
|
|
||||||
else
|
|
||||||
isUniqueFrame = FALSE;
|
|
||||||
|
|
||||||
// process the frame if it is not mine and unique
|
|
||||||
if(isUniqueFrame && !isMine) {
|
|
||||||
|
|
||||||
switch(rFrame.source.port) {
|
|
||||||
|
|
||||||
// process a beacon frame
|
|
||||||
case ICMP_TYPE:
|
|
||||||
Mesh_ProcessBeacon((void *)&rFrame, Stats.lastRSSI);
|
|
||||||
#if __DUMP_BEACON
|
|
||||||
EnqueChatFrame((void *)&rFrame);
|
|
||||||
#endif
|
|
||||||
Stats.nBeacons++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TEXT_TYPE:
|
|
||||||
EnqueChatFrame((void *)&rFrame);
|
|
||||||
Stats.framesOK++;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// these will be supported later....
|
|
||||||
case VIDEO_TYPE:
|
|
||||||
case ENC_AX25_TYPE:
|
|
||||||
case ENC_IP_TYPE:
|
|
||||||
case AUDIO_TYPE:
|
|
||||||
default:
|
|
||||||
Stats.dropped++;
|
|
||||||
logger(LOG_ERROR, "Frame Received for unknown port: %d\r\n", rFrame.source.port);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// repeat the frame if the repeat flag is set and the hop count is not exhausted
|
|
||||||
if(!isMine) {
|
|
||||||
if(rFrame.flagfld.flags.repeat && (rFrame.flagfld.flags.hop_count < MAX_HOP_COUNT))
|
|
||||||
RepeatFrame(&rFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
// update stats
|
|
||||||
if(!isUniqueFrame)
|
|
||||||
Stats.duplicates++;
|
|
||||||
if(isMine)
|
|
||||||
Stats.dropped++;
|
|
||||||
|
|
||||||
// restart the receiver
|
|
||||||
EnableRx();
|
|
||||||
|
|
||||||
}
|
|
||||||
// frame interrupt callback
|
|
||||||
void HAL_MRSubG_IRQ_Callback(void)
|
|
||||||
{
|
|
||||||
subgIRQStatus = READ_REG(MR_SUBG_GLOB_STATUS->RFSEQ_IRQ_STATUS);
|
|
||||||
|
|
||||||
// Process transmitter interrupts
|
|
||||||
if(subgIRQStatus & MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_TX_DONE_F) {
|
|
||||||
__HAL_MRSUBG_CLEAR_RFSEQ_IRQ_FLAG(MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_TX_DONE_F);
|
|
||||||
Stats.TxFrameCnt++;
|
|
||||||
txDone = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process receiver interrupts
|
|
||||||
if(subgIRQStatus & MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_RX_CRC_ERROR_F) {
|
|
||||||
Stats.CRCErrors++;
|
|
||||||
__HAL_MRSUBG_CLEAR_RFSEQ_IRQ_FLAG(MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_RX_CRC_ERROR_F);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subgIRQStatus & MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_RX_TIMEOUT_F) {
|
|
||||||
Stats.TimeOuts++;
|
|
||||||
__HAL_MRSUBG_CLEAR_RFSEQ_IRQ_FLAG(MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_RX_TIMEOUT_F);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subgIRQStatus & MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_RX_OK_F ) {
|
|
||||||
Stats.RxFrameCnt++;
|
|
||||||
__HAL_MRSUBG_CLEAR_RFSEQ_IRQ_FLAG(MR_SUBG_GLOB_STATUS_RFSEQ_IRQ_STATUS_RX_OK_F);
|
|
||||||
Stats.lastRSSI = READ_REG_FIELD(MR_SUBG_GLOB_STATUS->RX_INDICATOR, MR_SUBG_GLOB_STATUS_RX_INDICATOR_RSSI_LEVEL_ON_SYNC);
|
|
||||||
// shut off Rx until we are done with the frame
|
|
||||||
//__HAL_MRSUBG_STROBE_CMD(CMD_NOP);
|
|
||||||
|
|
||||||
rxReady = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
EnableRx();
|
|
||||||
}
|
|
|
@ -1,48 +0,0 @@
|
||||||
/* insque(3C) routines
|
|
||||||
This file is in the public domain. */
|
|
||||||
|
|
||||||
/*
|
|
||||||
|
|
||||||
@deftypefn Supplemental void insque (struct qelem *@var{elem}, @
|
|
||||||
struct qelem *@var{pred})
|
|
||||||
@deftypefnx Supplemental void remque (struct qelem *@var{elem})
|
|
||||||
|
|
||||||
Routines to manipulate queues built from doubly linked lists. The
|
|
||||||
@code{insque} routine inserts @var{elem} in the queue immediately
|
|
||||||
after @var{pred}. The @code{remque} routine removes @var{elem} from
|
|
||||||
its containing queue. These routines expect to be passed pointers to
|
|
||||||
structures which have as their first members a forward pointer and a
|
|
||||||
back pointer, like this prototype (although no prototype is provided):
|
|
||||||
|
|
||||||
@example
|
|
||||||
struct qelem @{
|
|
||||||
struct qelem *q_forw;
|
|
||||||
struct qelem *q_back;
|
|
||||||
char q_data[];
|
|
||||||
@};
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@end deftypefn
|
|
||||||
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct qelem {
|
|
||||||
struct qelem *q_forw;
|
|
||||||
struct qelem *q_back;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
void insque (struct qelem *elem, struct qelem *pred)
|
|
||||||
{
|
|
||||||
elem -> q_forw = pred -> q_forw;
|
|
||||||
pred -> q_forw -> q_back = elem;
|
|
||||||
elem -> q_back = pred;
|
|
||||||
pred -> q_forw = elem;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void remque (struct qelem *elem)
|
|
||||||
{
|
|
||||||
elem -> q_forw -> q_back = elem -> q_back;
|
|
||||||
elem -> q_back -> q_forw = elem -> q_forw;
|
|
||||||
}
|
|
|
@ -1,289 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: led.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: Handler for the LED's on nucleo or PI boards
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* notes for different implementations.
|
|
||||||
* On the Pi there are two LED's a dedicated red and a bicolor red-green.
|
|
||||||
* TX: On when transmitting
|
|
||||||
* BICOLOR: Green solid when Rx is enabled
|
|
||||||
* Red solid when HAL error or NMI occurred
|
|
||||||
*
|
|
||||||
* On the NUCLEO board, there are three, red, green and blue
|
|
||||||
* BLUE (LD1) Duplicats the TX LED
|
|
||||||
* GREEN (LD2) Duplicates the GREEN bi-color function
|
|
||||||
* RED (LD3) Duplicates the RED Bi-color function
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "led.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include <config.h>
|
|
||||||
|
|
||||||
// include LED defs from the right place
|
|
||||||
#if _BOARD_TYPE==NUCLEO_BOARD
|
|
||||||
#include <stm32wl3x_nucleo.h>
|
|
||||||
#else
|
|
||||||
#include <main.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// config
|
|
||||||
#define REVERSE_LEADS 1 // reverse Bi-color LED leads
|
|
||||||
|
|
||||||
// local defines
|
|
||||||
#define FLASH_OFF 0 // LED flashing: off state
|
|
||||||
#define FLASH_ON 1 // LED flashing: on state
|
|
||||||
|
|
||||||
// timer for 1/2 second when flashing
|
|
||||||
#define LED_TIMER 5 // timer
|
|
||||||
#define TEST_TIMER 20 // test timer
|
|
||||||
|
|
||||||
// internals
|
|
||||||
void SetLEDMode(uint8_t mode);
|
|
||||||
void LED_SetOff(void);
|
|
||||||
void LED_SetRed(void);
|
|
||||||
void LED_SetGreen(void);
|
|
||||||
void LED_SetError(void);
|
|
||||||
void setTxLED(BOOL state);
|
|
||||||
|
|
||||||
// vars
|
|
||||||
BOOL ToggleEnable; // led toggling enabled
|
|
||||||
uint8_t ledColour; // direction (colour)
|
|
||||||
uint8_t ledMode; // led mode
|
|
||||||
uint8_t ledState; // state on/off
|
|
||||||
uint8_t ledTimer; // timer for led test
|
|
||||||
uint8_t testNum; // test number
|
|
||||||
uint8_t testTimer; // test timer
|
|
||||||
uint8_t saveMode; // saved mode
|
|
||||||
|
|
||||||
//
|
|
||||||
// Notes on timer setup for STM32H732
|
|
||||||
// Prescaler value of 0 allows 64MHz clock to drive timer
|
|
||||||
// 1 reduces it to 32MHz
|
|
||||||
// Period divider of 6400 yeilds 100uSec time base
|
|
||||||
//
|
|
||||||
#define N_LED 5
|
|
||||||
struct led_tests_t {
|
|
||||||
char *testName;
|
|
||||||
uint8_t testMode;
|
|
||||||
} LEDTests[N_LED] = {
|
|
||||||
{"Bicolor RED On", BICOLOR_RED },
|
|
||||||
{"Bicolor GREEN On", BICOLOR_GREEN },
|
|
||||||
{"Bicolor off", BICOLOR_OFF },
|
|
||||||
{"Tx LED On", TX_LED_ON },
|
|
||||||
{"Tx LED Off", TX_LED_OFF }
|
|
||||||
};
|
|
||||||
// Initialization
|
|
||||||
void Led_Task_Init(void)
|
|
||||||
{
|
|
||||||
ToggleEnable = FALSE;
|
|
||||||
ledColour = BICOLOR_RED;
|
|
||||||
ledState = BICOLOR_OFF;
|
|
||||||
ledTimer = LED_TIMER;
|
|
||||||
LED_SetOff();
|
|
||||||
setTxLED(FALSE);
|
|
||||||
testTimer = 0;
|
|
||||||
testNum = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We handle the flashing here...
|
|
||||||
// for the bicolor led, we can be solid red, solid green,
|
|
||||||
// or red-green flashing
|
|
||||||
void Led_Task_Exec(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(ToggleEnable) {
|
|
||||||
|
|
||||||
if(ledTimer != 0) {
|
|
||||||
ledTimer--;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ledTimer--;
|
|
||||||
|
|
||||||
// blink LED if enabled
|
|
||||||
switch(ledMode) {
|
|
||||||
|
|
||||||
case BICOLOR_RED_FLASH:
|
|
||||||
case BICOLOR_GREEN_FLASH:
|
|
||||||
ledState = (ledState == FLASH_ON) ? FLASH_OFF : FLASH_ON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BICOLOR_RED_GREEN:
|
|
||||||
ledState = (ledState == FLASH_ON) ? FLASH_OFF : FLASH_ON;
|
|
||||||
ledColour = (ledColour == BICOLOR_RED) ? BICOLOR_GREEN : BICOLOR_RED;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// update the LED state
|
|
||||||
if(ledState == FLASH_OFF) {
|
|
||||||
LED_SetOff();
|
|
||||||
} else {
|
|
||||||
if(ledColour == BICOLOR_RED)
|
|
||||||
LED_SetRed();
|
|
||||||
else
|
|
||||||
LED_SetGreen();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// led test mode
|
|
||||||
BOOL LedTest(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
if(testTimer == 0) {
|
|
||||||
if(testNum == 0)
|
|
||||||
saveMode = ledMode;
|
|
||||||
if(testNum == N_LED) {
|
|
||||||
testNum = 0;
|
|
||||||
SetLEDMode(saveMode);
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
USART_Print_string("%s\r\n", LEDTests[testNum].testName);
|
|
||||||
SetLEDMode(LEDTests[testNum].testMode);
|
|
||||||
testTimer = TEST_TIMER;
|
|
||||||
testNum++;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
testTimer--;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// API routines: set the LED mode
|
|
||||||
void SetLEDMode(uint8_t mode)
|
|
||||||
{
|
|
||||||
ledMode = mode;
|
|
||||||
|
|
||||||
switch(ledMode) {
|
|
||||||
|
|
||||||
case BICOLOR_OFF:
|
|
||||||
LED_SetOff();
|
|
||||||
ToggleEnable = FALSE;
|
|
||||||
ledState = FLASH_OFF;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BICOLOR_RED:
|
|
||||||
LED_SetRed();
|
|
||||||
ToggleEnable = FALSE;
|
|
||||||
ledColour = BICOLOR_RED;
|
|
||||||
ledState = FLASH_ON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BICOLOR_RED_FLASH:
|
|
||||||
LED_SetRed();
|
|
||||||
ToggleEnable = TRUE;
|
|
||||||
ledColour = BICOLOR_RED;
|
|
||||||
ledState = FLASH_ON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BICOLOR_GREEN:
|
|
||||||
LED_SetGreen();
|
|
||||||
ToggleEnable = FALSE;
|
|
||||||
ledColour = BICOLOR_GREEN;
|
|
||||||
ledState = FLASH_ON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BICOLOR_GREEN_FLASH:
|
|
||||||
LED_SetGreen();
|
|
||||||
ToggleEnable = TRUE;
|
|
||||||
ledColour = BICOLOR_GREEN;
|
|
||||||
ledState = FLASH_ON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case BICOLOR_RED_GREEN:
|
|
||||||
LED_SetRed();
|
|
||||||
ToggleEnable = TRUE;
|
|
||||||
ledColour = BICOLOR_RED;
|
|
||||||
ledState = FLASH_ON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TX_LED_ON:
|
|
||||||
setTxLED(TRUE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TX_LED_OFF:
|
|
||||||
setTxLED(FALSE);
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// do the actual updates
|
|
||||||
void LED_SetOff(void)
|
|
||||||
{
|
|
||||||
#if _BOARD_TYPE
|
|
||||||
BSP_LED_Off(LED_RED);
|
|
||||||
BSP_LED_Off(LED_GREEN);
|
|
||||||
BSP_LED_Off(LED_BLUE);
|
|
||||||
#else
|
|
||||||
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
|
|
||||||
HAL_GPIO_WritePin(LED_A_GPIO_Port, LED_A_Pin, GPIO_PIN_RESET);
|
|
||||||
HAL_GPIO_WritePin(LED_K_GPIO_Port, LED_K_Pin, GPIO_PIN_RESET);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void setTxLED(BOOL state)
|
|
||||||
{
|
|
||||||
#if _BOARD_TYPE
|
|
||||||
if(state)
|
|
||||||
BSP_LED_On(LED_BLUE);
|
|
||||||
else
|
|
||||||
BSP_LED_Off(LED_BLUE);
|
|
||||||
#else
|
|
||||||
if(state)
|
|
||||||
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
|
|
||||||
else
|
|
||||||
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
// set fwd direction for bidir LED
|
|
||||||
#if REVERSE_LEADS
|
|
||||||
void LED_SetGreen(void)
|
|
||||||
#else
|
|
||||||
void LED_SetRed(void)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
#if _BOARD_TYPE
|
|
||||||
BSP_LED_On(LED_GREEN);
|
|
||||||
#else
|
|
||||||
HAL_GPIO_WritePin(LED_A_GPIO_Port, LED_A_Pin, GPIO_PIN_SET);
|
|
||||||
HAL_GPIO_WritePin(LED_K_GPIO_Port, LED_K_Pin, GPIO_PIN_RESET);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// set bwd direction for bidir LED
|
|
||||||
#if REVERSE_LEADS
|
|
||||||
void LED_SetRed(void)
|
|
||||||
#else
|
|
||||||
void LED_SetGreen(void)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
#if _BOARD_TYPE
|
|
||||||
BSP_LED_On(LED_RED);
|
|
||||||
#else
|
|
||||||
HAL_GPIO_WritePin(LED_A_GPIO_Port, LED_A_Pin, GPIO_PIN_RESET);
|
|
||||||
HAL_GPIO_WritePin(LED_K_GPIO_Port, LED_K_Pin, GPIO_PIN_SET);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,63 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: MMDLTX
|
|
||||||
|
|
||||||
Module: Logger
|
|
||||||
|
|
||||||
File Name: audio.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Revision: 1.00
|
|
||||||
|
|
||||||
Description: Log an error message. On the nucleo, we send it out to the
|
|
||||||
console UAR/T, on the E04, it goes out to the LPUART which
|
|
||||||
is connected to the VCOM port.
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include "usart.h"
|
|
||||||
|
|
||||||
char errmsg[200];
|
|
||||||
|
|
||||||
// need to figure out how to talk to UART on board...
|
|
||||||
void logger(int severity, char *format, ...)
|
|
||||||
{
|
|
||||||
|
|
||||||
// process the arg list
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, format);
|
|
||||||
vsprintf(errmsg,format, argptr);
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
switch(severity) {
|
|
||||||
|
|
||||||
case LOG_NOTICE:
|
|
||||||
USART_Print_string("Notice: %s\r\n", errmsg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG_ERROR:
|
|
||||||
USART_Print_string("Notice: %s\r\n", errmsg);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case LOG_SEVERE:
|
|
||||||
USART_Print_string("Notice: %s\r\n", errmsg);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,785 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: menu.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: Menu handler
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "streambuffer.h"
|
|
||||||
#include "setup.h"
|
|
||||||
#include "tasks.h"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "tod.h"
|
|
||||||
#include "config.h"
|
|
||||||
|
|
||||||
// menu state
|
|
||||||
uint8_t menuState; // menu state
|
|
||||||
enum {
|
|
||||||
MENU_OFF, // off
|
|
||||||
MENU_SHOWING, // showing the menu
|
|
||||||
MENU_SELECTING, // getting a selection
|
|
||||||
MENU_SELECTED, // item has been selected
|
|
||||||
MENU_PAUSED // pausing a while...
|
|
||||||
};
|
|
||||||
|
|
||||||
// key entry state
|
|
||||||
uint8_t entryState; // state of keyboard entry
|
|
||||||
enum {
|
|
||||||
NO_ENTRY=0, // no entry yet..
|
|
||||||
ENTERING, // entering a value
|
|
||||||
VALIDATING, // validating the entry
|
|
||||||
};
|
|
||||||
|
|
||||||
// menu items
|
|
||||||
#define NO_ITEM -1 // no item selected
|
|
||||||
|
|
||||||
// DEC VT100 Escape sequences
|
|
||||||
#define ASCII_TAB 0x09
|
|
||||||
#define ASCII_RET 0x0D
|
|
||||||
#define ASCII_ESC 0x1B // escape char
|
|
||||||
#define DEC_LEADIN '[' // lead-in character
|
|
||||||
#define MAX_SEQ 6 // max sequence length
|
|
||||||
|
|
||||||
// control codes..
|
|
||||||
enum {
|
|
||||||
CONTROL_CLEAR=0, // clear screen
|
|
||||||
CONTROL_HOME, // cursor home
|
|
||||||
CONTROL_DOUBLE_TOP, // double wide and height (top)
|
|
||||||
CONTROL_DOUBLE_BOTTOM, // double wide and height (bottom)
|
|
||||||
CONTROL_SINGLE, // single wide and height
|
|
||||||
NCONTROL_CODES // number of conrol codes
|
|
||||||
};
|
|
||||||
|
|
||||||
struct controlCodes_t {
|
|
||||||
char sequence[MAX_SEQ]; // sequence
|
|
||||||
uint8_t len; // length
|
|
||||||
} controlCodes[NCONTROL_CODES] = {
|
|
||||||
{{ASCII_ESC, DEC_LEADIN, '2', 'J'}, 4},
|
|
||||||
{{ASCII_ESC, DEC_LEADIN, 'H'}, 3},
|
|
||||||
{{ASCII_ESC, '#', '3'}, 3},
|
|
||||||
{{ASCII_ESC, '#', '4'}, 3},
|
|
||||||
{{ASCII_ESC, '#', '5'}, 3},
|
|
||||||
};
|
|
||||||
|
|
||||||
// strings common to all menu types
|
|
||||||
char *whatItem = "??Try again->";
|
|
||||||
char *menuSpacer = "\r\n\n";
|
|
||||||
char *pauseString = "Hit enter to continue->";
|
|
||||||
char *selectItem = "Select an item->";
|
|
||||||
|
|
||||||
static char menu[100]; // Buffer for file items
|
|
||||||
int sel_item = 0; // selected item
|
|
||||||
uint8_t activeMenu; // active menu
|
|
||||||
|
|
||||||
// forward refs in this module
|
|
||||||
void printMenu(void); // print the menu
|
|
||||||
int getMenuItem(void); // get a menu item
|
|
||||||
void sendControlCode(uint8_t code);
|
|
||||||
BOOL pause(void);
|
|
||||||
void Print_Frame_stats(FRAME_STATS *stats);
|
|
||||||
void Print_Radio_errors(uint32_t errs);
|
|
||||||
void Print_FSM_state(uint8_t state);
|
|
||||||
uint8_t getEntry(int activeMenu, int item);
|
|
||||||
uint8_t getKeyEntry(void);
|
|
||||||
|
|
||||||
// list of menus
|
|
||||||
enum {
|
|
||||||
MAIN_MENU=0, // main menu
|
|
||||||
RADIO_MENU, // radio params menu
|
|
||||||
STATION_MENU, // Station params menu
|
|
||||||
N_MENUS // number of menus
|
|
||||||
};
|
|
||||||
|
|
||||||
// menu return functions
|
|
||||||
enum {
|
|
||||||
RET_MORE=0, // more to do
|
|
||||||
RET_DONE, // done
|
|
||||||
RET_PAUSE // pause before leaving
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* The first part of this code contains the menus and processing routines
|
|
||||||
* handle the various menu options
|
|
||||||
* return TRUE if done, else FALSE
|
|
||||||
*/
|
|
||||||
uint8_t printAllSetup(void)
|
|
||||||
{
|
|
||||||
TIMEOFDAY tod;
|
|
||||||
getTOD(&tod);
|
|
||||||
|
|
||||||
USART_Print_string("Current firmware is at %d.%d\r\n",def_params.params.FirmwareVerMajor,
|
|
||||||
def_params.params.FirmwareVerMinor);
|
|
||||||
USART_Print_string("System time is %02d:%02d:%02d\r\n\n", tod.Hours, tod.Minutes, tod.Seconds);
|
|
||||||
|
|
||||||
printStationSetup();
|
|
||||||
printRadioSetup();
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
uint8_t printStnSetup(void)
|
|
||||||
{
|
|
||||||
printStationSetup();
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
//
|
|
||||||
uint8_t printRadSetup(void)
|
|
||||||
{
|
|
||||||
printRadioSetup();
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
// list mesh status
|
|
||||||
uint8_t listMesh(void)
|
|
||||||
{
|
|
||||||
Mesh_ListStatus();
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// enter chat mode
|
|
||||||
uint8_t chatMode(void)
|
|
||||||
{
|
|
||||||
if(Chat_Task_exec())
|
|
||||||
return RET_PAUSE;
|
|
||||||
return RET_MORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// dump the rx stats
|
|
||||||
uint8_t showstats(void)
|
|
||||||
{
|
|
||||||
Print_Frame_stats(GetFrameStats());
|
|
||||||
Print_Radio_errors(GetRadioStatus());
|
|
||||||
Print_FSM_state(GetFSMState());
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the radio entry mode
|
|
||||||
uint8_t setRadio(void)
|
|
||||||
{
|
|
||||||
activeMenu = RADIO_MENU;
|
|
||||||
menuState = MENU_OFF;
|
|
||||||
return RET_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the station entry mode
|
|
||||||
uint8_t setStation(void)
|
|
||||||
{
|
|
||||||
activeMenu = STATION_MENU;
|
|
||||||
menuState = MENU_OFF;
|
|
||||||
return RET_DONE;
|
|
||||||
}
|
|
||||||
// enter chat mode
|
|
||||||
uint8_t ledTest(void)
|
|
||||||
{
|
|
||||||
if(LedTest())
|
|
||||||
return RET_PAUSE;
|
|
||||||
return RET_MORE;
|
|
||||||
}
|
|
||||||
// write the flash memory
|
|
||||||
uint8_t writeSetup(void)
|
|
||||||
{
|
|
||||||
if(!UpdateSetup()) {
|
|
||||||
USART_Print_string("Error in writing flash: setup may be corrupt\r\n");
|
|
||||||
} else {
|
|
||||||
USART_Print_string("Flash written successfully\r\n");
|
|
||||||
}
|
|
||||||
menuState = MENU_OFF;
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
// exit the current menu
|
|
||||||
uint8_t exitMenu(void)
|
|
||||||
{
|
|
||||||
activeMenu = MAIN_MENU;
|
|
||||||
menuState = MENU_OFF;
|
|
||||||
return RET_DONE;
|
|
||||||
}
|
|
||||||
// set a parameter value
|
|
||||||
uint8_t setParam(void)
|
|
||||||
{
|
|
||||||
return(getEntry(activeMenu, sel_item));
|
|
||||||
}
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
uint8_t gpsEcho(void)
|
|
||||||
{
|
|
||||||
GPSEcho();
|
|
||||||
return(getKeyEntry());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* main menu definition
|
|
||||||
* 1) define the number of line items
|
|
||||||
* 2) create menuitms struct
|
|
||||||
* 3) add to menucontents struct
|
|
||||||
*/
|
|
||||||
struct menuItems_t {
|
|
||||||
char *menuLine; // text of menu line
|
|
||||||
char selChar; // character to select it
|
|
||||||
uint8_t (*func)(void); // processing function
|
|
||||||
};
|
|
||||||
|
|
||||||
// main menu
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
#define N_MAINMENU 11 // additional menu item for GPS
|
|
||||||
#else
|
|
||||||
#define N_MAINMENU 10 // number of lines in the menu
|
|
||||||
#endif
|
|
||||||
|
|
||||||
struct menuItems_t mainMenu[N_MAINMENU] = {
|
|
||||||
{ "List setup parameters\r\n", 'A', printAllSetup },
|
|
||||||
{ "Mesh Status\r\n", 'B', listMesh },
|
|
||||||
{ "Chat Mode\r\n", 'C', chatMode },
|
|
||||||
{ "Dump Frame stats\r\n", 'D', showstats },
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
{ "GPS Echo mode\r\n", 'G', gpsEcho },
|
|
||||||
#endif
|
|
||||||
{ "LED test\r\n", 'L', ledTest },
|
|
||||||
{ "Set Radio Parameters\r\n", 'R', setRadio },
|
|
||||||
{ "Set Station Parameters\r\n", 'S', setStation },
|
|
||||||
{ "Set clock (HH:MM)\r\n\n", 'T', setParam },
|
|
||||||
{ "Write Setup Values\r\n", 'W', writeSetup },
|
|
||||||
{ "Exit\r\n\n", 'X', exitMenu }
|
|
||||||
};
|
|
||||||
|
|
||||||
// radio menu
|
|
||||||
#define N_RADIOMENU 8
|
|
||||||
struct menuItems_t radioMenu[N_RADIOMENU] = {
|
|
||||||
{ "RF Frequency\r\n", 'A', setParam },
|
|
||||||
{ "Data Rate\r\n", 'B', setParam },
|
|
||||||
{ "Peak Deviation\r\n", 'C', setParam },
|
|
||||||
{ "Channel Filter BW\r\n", 'D', setParam },
|
|
||||||
{ "Output Power (dBm)\r\n", 'E', setParam },
|
|
||||||
{ "Rx Squelch (dBm)\r\n\n", 'F', setParam },
|
|
||||||
{ "List Settings\r\n", 'L', printRadSetup },
|
|
||||||
{ "Return to main menu\r\n\n", 'X', exitMenu }
|
|
||||||
};
|
|
||||||
|
|
||||||
// these need to correspond to the items above
|
|
||||||
|
|
||||||
// station menu
|
|
||||||
#define N_STATIONMENU 8
|
|
||||||
struct menuItems_t stationMenu[N_STATIONMENU] = {
|
|
||||||
{ "Callsign\r\n", 'A', setParam },
|
|
||||||
{ "Latitude\r\n", 'B', setParam },
|
|
||||||
{ "Longitude\r\n", 'C', setParam },
|
|
||||||
{ "Grid Square\r\n", 'D', setParam },
|
|
||||||
{ "Repeat Default\r\n", 'E', setParam },
|
|
||||||
{ "Beacon Interval\r\n\n", 'F', setParam },
|
|
||||||
{ "List Settings\r\n", 'L', printStnSetup },
|
|
||||||
{ "Return to main menu\r\n\n", 'X', exitMenu }
|
|
||||||
};
|
|
||||||
|
|
||||||
// menu contents
|
|
||||||
struct menuContents_t {
|
|
||||||
char *title; // title of the menu
|
|
||||||
int nMenuLines; // number of lines
|
|
||||||
struct menuItems_t *menus; // menu items
|
|
||||||
} menuContents[N_MENUS] = {
|
|
||||||
#if _BOARD_TYPE==NUCLEO_BOARD
|
|
||||||
{ " IP400 Nucleo Main menu\r\n", N_MAINMENU, mainMenu },
|
|
||||||
#else
|
|
||||||
{ " IP400 Pi menu\r\n", N_MAINMENU, mainMenu },
|
|
||||||
#endif
|
|
||||||
{ " Radio setup menu\r\n", N_RADIOMENU, radioMenu },
|
|
||||||
{ " Station Setup menu\r\n", N_STATIONMENU, stationMenu }
|
|
||||||
};
|
|
||||||
|
|
||||||
// menu (main) task
|
|
||||||
void Menu_Task_Init(void)
|
|
||||||
{
|
|
||||||
// start off with the menu showing
|
|
||||||
activeMenu = MAIN_MENU;
|
|
||||||
menuState = MENU_SHOWING;
|
|
||||||
entryState = NO_ENTRY;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a control code
|
|
||||||
void sendControlCode(uint8_t code)
|
|
||||||
{
|
|
||||||
USART_Send_String(controlCodes[code].sequence, controlCodes[code].len);
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a control code
|
|
||||||
void sendTextString(char *string)
|
|
||||||
{
|
|
||||||
strcpy(menu, string);
|
|
||||||
USART_Send_String(menu, strlen(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
// process our time slot
|
|
||||||
void Menu_Task_Exec(void)
|
|
||||||
{
|
|
||||||
int nBytesinBuff = 0;
|
|
||||||
char c;
|
|
||||||
struct menuItems_t *m;
|
|
||||||
|
|
||||||
switch(menuState) {
|
|
||||||
|
|
||||||
// if there is a return in the console buffer,
|
|
||||||
// bring up the menu
|
|
||||||
case MENU_OFF:
|
|
||||||
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
||||||
return;
|
|
||||||
for(int i=0;i<nBytesinBuff;i++)
|
|
||||||
if((c=databuffer_get(0)) == ASCII_RET)
|
|
||||||
menuState = MENU_SHOWING;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MENU_SHOWING:
|
|
||||||
printMenu();
|
|
||||||
menuState = MENU_SELECTING;
|
|
||||||
return;
|
|
||||||
|
|
||||||
case MENU_SELECTING:
|
|
||||||
if((sel_item=getMenuItem()) == NO_ITEM)
|
|
||||||
return;
|
|
||||||
menuState = MENU_SELECTED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MENU_SELECTED:
|
|
||||||
m=menuContents[activeMenu].menus;
|
|
||||||
m += sel_item;
|
|
||||||
switch((*m->func)()) {
|
|
||||||
|
|
||||||
case RET_MORE:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RET_PAUSE:
|
|
||||||
sendTextString(pauseString);
|
|
||||||
menuState = MENU_PAUSED;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RET_DONE:
|
|
||||||
menuState = MENU_SHOWING;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case MENU_PAUSED:
|
|
||||||
if(pause())
|
|
||||||
menuState = MENU_SHOWING;
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// print the main menu
|
|
||||||
void printMenu(void)
|
|
||||||
{
|
|
||||||
struct menuItems_t *m;
|
|
||||||
|
|
||||||
// title
|
|
||||||
sendControlCode(CONTROL_CLEAR);
|
|
||||||
sendControlCode(CONTROL_HOME);
|
|
||||||
|
|
||||||
#if _BOARD_TYPE==NUCLEO_BOARD
|
|
||||||
// only use double wide mode with Nucleo
|
|
||||||
sendControlCode(CONTROL_DOUBLE_TOP);
|
|
||||||
sendTextString(menuContents[activeMenu].title);
|
|
||||||
sendControlCode(CONTROL_DOUBLE_BOTTOM);
|
|
||||||
sendTextString(menuContents[activeMenu].title);
|
|
||||||
sendControlCode(CONTROL_SINGLE);
|
|
||||||
sendTextString(menuSpacer);
|
|
||||||
#else
|
|
||||||
sendTextString(menuContents[activeMenu].title);
|
|
||||||
sendTextString(menuSpacer);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// lines
|
|
||||||
int nMenuLines = menuContents[activeMenu].nMenuLines;
|
|
||||||
for(int i=0;i<nMenuLines;i++) {
|
|
||||||
m=menuContents[activeMenu].menus;
|
|
||||||
m += i;
|
|
||||||
menu[0] = m->selChar;
|
|
||||||
strcpy(&menu[1], ") ");
|
|
||||||
strcat(menu, m->menuLine);
|
|
||||||
USART_Send_String(menu, strlen(menu));
|
|
||||||
}
|
|
||||||
|
|
||||||
// selection
|
|
||||||
sendTextString(selectItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a menu item and dispatch the correct processing routine
|
|
||||||
int getMenuItem(void)
|
|
||||||
{
|
|
||||||
int nBytesinBuff =0;
|
|
||||||
struct menuItems_t *m;
|
|
||||||
char c;
|
|
||||||
|
|
||||||
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
||||||
return NO_ITEM;
|
|
||||||
|
|
||||||
for(int i=0;i<nBytesinBuff;i++) {
|
|
||||||
if((c=databuffer_get(0)) != BUFFER_NO_DATA) {
|
|
||||||
|
|
||||||
// translate and echo
|
|
||||||
c = islower(c) ? toupper(c) : c;
|
|
||||||
USART_Send_Char(c);
|
|
||||||
|
|
||||||
// find the correct processing routine
|
|
||||||
int nMenuLines = menuContents[activeMenu].nMenuLines;
|
|
||||||
for(int j=0;j<nMenuLines;j++) {
|
|
||||||
m=menuContents[activeMenu].menus;
|
|
||||||
m += j;
|
|
||||||
if(m->selChar == c) {
|
|
||||||
sendTextString(menuSpacer);
|
|
||||||
return j;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sendTextString(whatItem);
|
|
||||||
return NO_ITEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOL pause(void)
|
|
||||||
{
|
|
||||||
if(databuffer_bytesInBuffer() == 0)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
if(databuffer_get(0) == ASCII_RET)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This part pertains to getting an entry and validating it..
|
|
||||||
*/
|
|
||||||
|
|
||||||
// keys in entry mode
|
|
||||||
#define KEY_EOL 0x0D // carriage return
|
|
||||||
#define KEY_ESC 0x1B // escape key
|
|
||||||
#define KEY_DEL 0x7F // delete key
|
|
||||||
#define KEY_BKSP 0x08 // backspace key
|
|
||||||
|
|
||||||
#define MAX_ENTRY 40 // max entry chars
|
|
||||||
|
|
||||||
BOOL delMode = FALSE;
|
|
||||||
int pos = 0;
|
|
||||||
char keyBuffer[MAX_ENTRY];
|
|
||||||
|
|
||||||
// forward refs
|
|
||||||
uint8_t validateEntry(int activeMenu, int item, char *keyBuffer);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get a key entry: basically stolen from chat.c
|
|
||||||
*/
|
|
||||||
uint8_t getKeyEntry(void)
|
|
||||||
{
|
|
||||||
|
|
||||||
char c;
|
|
||||||
int nBytesinBuff;
|
|
||||||
|
|
||||||
if((nBytesinBuff=databuffer_bytesInBuffer()) == 0)
|
|
||||||
return RET_MORE;
|
|
||||||
|
|
||||||
for(int i=0;i<nBytesinBuff;i++) {
|
|
||||||
|
|
||||||
c=databuffer_get(0);
|
|
||||||
|
|
||||||
if(delMode) {
|
|
||||||
if((c != KEY_DEL) && (c != KEY_BKSP)) {
|
|
||||||
USART_Print_string("\\%c", c);
|
|
||||||
if(pos < MAX_ENTRY)
|
|
||||||
keyBuffer[pos++] = c;
|
|
||||||
delMode = FALSE;
|
|
||||||
} else {
|
|
||||||
if(pos > 0) {
|
|
||||||
USART_Print_string("%c", keyBuffer[--pos]);
|
|
||||||
} else {
|
|
||||||
USART_Print_string("\\\r\n");
|
|
||||||
delMode = FALSE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
// processing a key
|
|
||||||
|
|
||||||
switch (c) {
|
|
||||||
|
|
||||||
// EOL key: sent the packet
|
|
||||||
case KEY_EOL:
|
|
||||||
USART_Print_string("\r\n");
|
|
||||||
keyBuffer[pos++] = '\0';
|
|
||||||
return RET_DONE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// escape key: abort the entry
|
|
||||||
case KEY_ESC:
|
|
||||||
return RET_PAUSE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case KEY_DEL:
|
|
||||||
case KEY_BKSP:
|
|
||||||
USART_Print_string("\\%c", keyBuffer[--pos]);
|
|
||||||
delMode = TRUE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
USART_Send_Char(c);
|
|
||||||
if(pos < MAX_ENTRY)
|
|
||||||
keyBuffer[pos++] = c;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return RET_MORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get an entry and validate it
|
|
||||||
*/
|
|
||||||
uint8_t getEntry(int activeMenu, int item)
|
|
||||||
{
|
|
||||||
struct menuItems_t *m;
|
|
||||||
|
|
||||||
switch(entryState) {
|
|
||||||
|
|
||||||
case NO_ENTRY:
|
|
||||||
delMode = FALSE;
|
|
||||||
pos = 0;
|
|
||||||
entryState = ENTERING;
|
|
||||||
m=menuContents[activeMenu].menus;
|
|
||||||
m += item;
|
|
||||||
USART_Print_string("%s->", m->menuLine);
|
|
||||||
return RET_MORE;
|
|
||||||
|
|
||||||
case ENTERING:
|
|
||||||
int keyStat = getKeyEntry();
|
|
||||||
if(keyStat == RET_DONE) {
|
|
||||||
entryState = VALIDATING;
|
|
||||||
return RET_MORE;
|
|
||||||
}
|
|
||||||
return keyStat;
|
|
||||||
|
|
||||||
case VALIDATING:
|
|
||||||
entryState = NO_ENTRY;
|
|
||||||
return validateEntry(activeMenu, item, keyBuffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return RET_MORE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// data types we are updating
|
|
||||||
enum {
|
|
||||||
uint8_type, // uint8 field
|
|
||||||
int16_type, // int16 field
|
|
||||||
uint32_type, // uint32 field
|
|
||||||
float_type, // floating point
|
|
||||||
char_type, // character type
|
|
||||||
field_type // field type
|
|
||||||
};
|
|
||||||
|
|
||||||
// struct to hold validation values
|
|
||||||
typedef struct field_validator_t {
|
|
||||||
int MinVal; // minimum value
|
|
||||||
int MaxVal; // maximum value
|
|
||||||
void *setupVal; // pointer to setup value
|
|
||||||
int type; // type of entry
|
|
||||||
uint32_t scalar; // scalar to convert to decimal
|
|
||||||
} FIELD_VALIDATOR;
|
|
||||||
|
|
||||||
// validators for radio mmenu
|
|
||||||
FIELD_VALIDATOR radioValidators[] = {
|
|
||||||
{ MIN_FREQ, 450000000, &setup_memory.params.radio_setup.lFrequencyBase, uint32_type, 1000000 },
|
|
||||||
{ 9600, 600000, &setup_memory.params.radio_setup.lDatarate, uint32_type, 1000 },
|
|
||||||
{ 12500, 150000, &setup_memory.params.radio_setup.lFreqDev, uint32_type, 1000 },
|
|
||||||
{ 2600, 1600000, &setup_memory.params.radio_setup.lBandwidth, uint32_type, 1000 },
|
|
||||||
{ 0, 20, &setup_memory.params.radio_setup.outputPower, uint8_type, 1 },
|
|
||||||
{ -115, 0, &setup_memory.params.radio_setup.rxSquelch, int16_type, 1 },
|
|
||||||
};
|
|
||||||
|
|
||||||
FIELD_VALIDATOR stationValidators[] = {
|
|
||||||
{ 4, 6, &setup_memory.params.setup_data.stnCall, char_type, 0 },
|
|
||||||
{ 2, 14, &setup_memory.params.setup_data.latitude, char_type, 0 },
|
|
||||||
{ 2, 14, &setup_memory.params.setup_data.longitude, char_type, 0 },
|
|
||||||
{ 6, 6, &setup_memory.params.setup_data.gridSq, char_type, 0 },
|
|
||||||
{ 0, 0x8, &setup_memory.params.setup_data.flags, field_type, 0 },
|
|
||||||
{ 1, 100, &setup_memory.params.setup_data.beaconInt, int16_type, 0 }
|
|
||||||
};
|
|
||||||
|
|
||||||
uint8_t validateEntry(int activeMenu, int item, char *keyBuffer)
|
|
||||||
{
|
|
||||||
|
|
||||||
int newValue, min, max;
|
|
||||||
|
|
||||||
//NB: the cases here must jive with the menu items
|
|
||||||
switch(activeMenu) {
|
|
||||||
|
|
||||||
case MAIN_MENU: // the only menu item here is the clock
|
|
||||||
setTOD(keyBuffer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RADIO_MENU:
|
|
||||||
// convert a floating point entry to the required decimal
|
|
||||||
if(isfloat(keyBuffer))
|
|
||||||
newValue = (int)(ascii2double(keyBuffer)*radioValidators[item].scalar);
|
|
||||||
else newValue = ascii2Dec(keyBuffer);
|
|
||||||
max = radioValidators[item].MaxVal;
|
|
||||||
min = radioValidators[item].MinVal;
|
|
||||||
if((newValue<min) || (newValue>max)) {
|
|
||||||
USART_Print_string("Must be in the range of %d to %d\r\n", min, max);
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
switch(radioValidators[item].type){
|
|
||||||
|
|
||||||
case uint8_type:
|
|
||||||
uint8_t *v8 = (uint8_t *)radioValidators[item].setupVal;
|
|
||||||
*v8 = (uint8_t)newValue;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case int16_type:
|
|
||||||
int16_t *v16 = (int16_t *)radioValidators[item].setupVal;
|
|
||||||
*v16 = (int16_t)newValue;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case uint32_type:
|
|
||||||
uint32_t *v32 = (uint32_t *)radioValidators[item].setupVal;
|
|
||||||
*v32 = (uint32_t)newValue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case STATION_MENU:
|
|
||||||
switch(stationValidators[item].type){
|
|
||||||
|
|
||||||
case int16_type:
|
|
||||||
newValue = ascii2Dec(keyBuffer);
|
|
||||||
max = stationValidators[item].MaxVal;
|
|
||||||
min = stationValidators[item].MinVal;
|
|
||||||
if((newValue<min) || (newValue>max)) {
|
|
||||||
USART_Print_string("Must be in the range of %d to %d\r\n", min, max);
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
uint16_t *v8 = (uint16_t *)stationValidators[item].setupVal;
|
|
||||||
*v8 = (uint16_t)newValue;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case char_type:
|
|
||||||
size_t len = strlen(keyBuffer);
|
|
||||||
max = stationValidators[item].MaxVal;
|
|
||||||
min = stationValidators[item].MinVal;
|
|
||||||
if((len<min) || (len>max)) {
|
|
||||||
USART_Print_string("String must be %d to %d in length\r\n", min, max);
|
|
||||||
return RET_PAUSE;
|
|
||||||
}
|
|
||||||
strcpy((char *)stationValidators[item].setupVal, keyBuffer);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case field_type:
|
|
||||||
uint8_t val = keyBuffer[0] == 'T' ? 1 : 0;
|
|
||||||
uint8_t *f8= (uint8_t *)stationValidators[item].setupVal;
|
|
||||||
if(val)
|
|
||||||
*f8 |= (uint8_t)stationValidators[item].MinVal;
|
|
||||||
else
|
|
||||||
*f8 &= (uint8_t)stationValidators[item].MinVal;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// falls to here when done...
|
|
||||||
return RET_DONE;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print the frame stats
|
|
||||||
*/
|
|
||||||
void Print_Frame_stats(FRAME_STATS *stats)
|
|
||||||
{
|
|
||||||
USART_Print_string("Frame Statistics\r\n\n");
|
|
||||||
|
|
||||||
USART_Print_string("Transmitted frames->%d\r\n", stats->TxFrameCnt);
|
|
||||||
USART_Print_string("CRC Errors->%d\r\n", stats->CRCErrors);
|
|
||||||
USART_Print_string("Rx Timeouts->%d\r\n", stats->TimeOuts);
|
|
||||||
USART_Print_string("Frames with good CRC->%d\r\n", stats->RxFrameCnt);
|
|
||||||
USART_Print_string("Beacon frames->%d\r\n", stats->nBeacons);
|
|
||||||
USART_Print_string("Repeated frames->%d\r\n", stats->nRepeated);
|
|
||||||
|
|
||||||
USART_Print_string("Processed Frames->%d\r\n", stats->RxFrameCnt);
|
|
||||||
USART_Print_string("Dropped frames->%d\r\n", stats->dropped);
|
|
||||||
USART_Print_string("Duplicate frames->%d\r\n", stats->duplicates);
|
|
||||||
USART_Print_string("Repeated frames->%d\r\n", stats->duplicates);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Print the radio error stats
|
|
||||||
*/
|
|
||||||
struct radio_errs_t {
|
|
||||||
uint32_t mask;
|
|
||||||
char *errmsg;
|
|
||||||
} radio_errs[N_RADIO_ERRS] = {
|
|
||||||
{ SEQ_COMPLETE_ERR, "Sequencer Error" },
|
|
||||||
{ SEQ_ACT_TIMEOUT, "Sequencer action timeout" },
|
|
||||||
{ PLL_CALAMP_ERR, "VCO Amplitude calibration error" },
|
|
||||||
{ PLL_CALFREQ_ERR, "VCO Frequency calibration error" },
|
|
||||||
{ PLL_UNLOCK_ERR, "PLL Unlocked" },
|
|
||||||
{ PLL_LOCK_FAIL, "PLL Lock failure" },
|
|
||||||
{ DBM_FIFO_ERR, "Data buffer FIFO error" }
|
|
||||||
};
|
|
||||||
//
|
|
||||||
void Print_Radio_errors(uint32_t errs)
|
|
||||||
{
|
|
||||||
if(errs == 0){
|
|
||||||
USART_Print_string("No radio errors\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for(int i=0;i<N_RADIO_ERRS;i++)
|
|
||||||
if(errs & radio_errs[i].mask)
|
|
||||||
USART_Print_string("%s\r\n", radio_errs[i].errmsg);
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* Print the FSM state
|
|
||||||
*/
|
|
||||||
char *fsm_states[FSM_N_FSM_STATES] = {
|
|
||||||
"Idle",
|
|
||||||
"Enable RF registers",
|
|
||||||
"Wait for active 2",
|
|
||||||
"Active 2",
|
|
||||||
"Enable current",
|
|
||||||
"Synth setup",
|
|
||||||
"VCO calibration",
|
|
||||||
"Lock Rx and Rx",
|
|
||||||
"Llock on Rx",
|
|
||||||
"Enable PA",
|
|
||||||
"Transmit",
|
|
||||||
"Analog power down",
|
|
||||||
"End transmit",
|
|
||||||
"lock on Rx",
|
|
||||||
"Enable Rx",
|
|
||||||
"Enable LNA",
|
|
||||||
"Recieve",
|
|
||||||
"End rx",
|
|
||||||
"Synth power down"
|
|
||||||
};
|
|
||||||
void Print_FSM_state(uint8_t state)
|
|
||||||
{
|
|
||||||
if(state > FSM_N_FSM_STATES) {
|
|
||||||
USART_Print_string("\r\n?Unknown FSM state\r\n");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
USART_Print_string("\r\nRadio FSM State: %d: %s\r\n", state, fsm_states[state]);
|
|
||||||
}
|
|
|
@ -1,262 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: mesh.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: This code builds and lists the mesh status
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <cmsis_os2.h>
|
|
||||||
#include <sys/queue.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <FreeRTOS.h>
|
|
||||||
#include <task.h>
|
|
||||||
#include <malloc.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "tasks.h"
|
|
||||||
#include "frame.h"
|
|
||||||
#include "usart.h"
|
|
||||||
#include "dataq.h"
|
|
||||||
#include "setup.h"
|
|
||||||
#include "tod.h"
|
|
||||||
|
|
||||||
#define EXPIRY_TIME 100 // seconds since last heard
|
|
||||||
#define RSSI_SCALAR 161 // 95-Gain(rx), appros 65
|
|
||||||
|
|
||||||
char *FSKSpeeds[] = {
|
|
||||||
"FSK 1200",
|
|
||||||
"FSK 9600",
|
|
||||||
"FSK_56K",
|
|
||||||
"FSK_100K",
|
|
||||||
"FSK_200K",
|
|
||||||
"FSK_300K",
|
|
||||||
"FSK_400K",
|
|
||||||
"FSK_600K"
|
|
||||||
};
|
|
||||||
|
|
||||||
// mesh entry struct
|
|
||||||
struct mesh_entry_t {
|
|
||||||
struct mesh_entry_t *q_forw; // forward pointer
|
|
||||||
struct mesh_entry_t *q_back; // backward pointer
|
|
||||||
IP400_CALL encCall; // encoded callsign
|
|
||||||
uint32_t nextSeq; // next sequence number
|
|
||||||
int16_t lastRssi; // signal strength
|
|
||||||
uint8_t txPower; // transmit power
|
|
||||||
SETUP_FLAGS capabilities; // capabilities
|
|
||||||
TIMEOFDAY lastHeard; // last heard
|
|
||||||
uint8_t hopCount; // hop count
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Since V0.4, the raw rx frame has already been decoded
|
|
||||||
* however, the capabilities are in the data buffer
|
|
||||||
* this may look cumbersome but it grows if the flags do
|
|
||||||
*/
|
|
||||||
BEACON_HEADER mesh_bcn_hdr; // beacon header
|
|
||||||
struct mesh_entry_t meshHead; // head of mesh chain
|
|
||||||
int nMeshEntries = 0;
|
|
||||||
uint32_t seqNum; // sequence number received
|
|
||||||
|
|
||||||
// forward refs in this module
|
|
||||||
struct mesh_entry_t *findCall(IP400_CALL *call);
|
|
||||||
void AddMeshEntry(IP400_FRAME *frameData, int16_t rssi, BOOL isBeacon);
|
|
||||||
|
|
||||||
// task initialization
|
|
||||||
void Mesh_Task_Init(void)
|
|
||||||
{
|
|
||||||
meshHead.q_forw = &meshHead;
|
|
||||||
meshHead.q_back = &meshHead;
|
|
||||||
}
|
|
||||||
|
|
||||||
// process a beacon packet: if we don't have it, enter it
|
|
||||||
// otherwise update the last time heard
|
|
||||||
void Mesh_ProcessBeacon(void *rxFrame, uint32_t rssi)
|
|
||||||
{
|
|
||||||
struct mesh_entry_t *newEntry;
|
|
||||||
IP400_FRAME *frameData = (IP400_FRAME *)rxFrame;
|
|
||||||
|
|
||||||
TIMEOFDAY current;
|
|
||||||
getTOD(¤t);
|
|
||||||
|
|
||||||
int16_t actRSSI = rssi/2 - RSSI_SCALAR;
|
|
||||||
|
|
||||||
// see if we already know about it
|
|
||||||
// if so, just update last heard, expected sequence and rssi
|
|
||||||
// NB: firt frame is sent with an all '1's sequence number
|
|
||||||
if((newEntry = findCall(&frameData->source)) != NULL) {
|
|
||||||
|
|
||||||
// if it is repeated frame with a higher hop count, ignore it
|
|
||||||
if(newEntry->hopCount < frameData->flagfld.flags.hop_count)
|
|
||||||
return;
|
|
||||||
|
|
||||||
newEntry->lastHeard.Hours = current.Hours;
|
|
||||||
newEntry->lastHeard.Minutes = current.Minutes;
|
|
||||||
newEntry->lastHeard.Seconds = current.Seconds;
|
|
||||||
newEntry->lastRssi = actRSSI;
|
|
||||||
newEntry->nextSeq = frameData->seqNum == 0xFFFFFFFF ? 0 : ++frameData->seqNum;
|
|
||||||
|
|
||||||
//ugly, but necessary
|
|
||||||
memset(mesh_bcn_hdr.hdrBytes, 0, sizeof(BEACON_HEADER));
|
|
||||||
uint8_t *p = (uint8_t *)frameData->buf;
|
|
||||||
mesh_bcn_hdr.hdrBytes[0] = *p++;
|
|
||||||
mesh_bcn_hdr.hdrBytes[4] = *p;
|
|
||||||
|
|
||||||
newEntry->capabilities = mesh_bcn_hdr.setup.flags;
|
|
||||||
newEntry->txPower = mesh_bcn_hdr.setup.txPower;
|
|
||||||
|
|
||||||
// all done
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// beacon from a new station
|
|
||||||
AddMeshEntry(frameData, actRSSI, TRUE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* add a new station to the mesh table
|
|
||||||
*/
|
|
||||||
void AddMeshEntry(IP400_FRAME *frameData, int16_t actRSSI, BOOL isBeacon)
|
|
||||||
{
|
|
||||||
struct mesh_entry_t *newEntry;
|
|
||||||
|
|
||||||
TIMEOFDAY current;
|
|
||||||
getTOD(¤t);
|
|
||||||
|
|
||||||
// create a new entry
|
|
||||||
if((newEntry = (struct mesh_entry_t *)malloc(sizeof(struct mesh_entry_t))) == NULL) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// grab call and capabilities
|
|
||||||
newEntry->encCall = frameData->source;
|
|
||||||
newEntry->lastHeard.Hours = current.Hours;
|
|
||||||
newEntry->lastHeard.Minutes = current.Minutes;
|
|
||||||
newEntry->lastHeard.Seconds = current.Seconds;
|
|
||||||
newEntry->nextSeq = frameData->seqNum == 0xFFFFFFFF ? 0 : ++frameData->seqNum;
|
|
||||||
newEntry->lastRssi = actRSSI;
|
|
||||||
newEntry->txPower = 0;
|
|
||||||
newEntry->hopCount = frameData->flagfld.flags.hop_count;
|
|
||||||
|
|
||||||
if(isBeacon) {
|
|
||||||
memcpy(mesh_bcn_hdr.hdrBytes, (struct beacon_hdr_t *)frameData->buf, sizeof(BEACON_HEADER));
|
|
||||||
newEntry->capabilities = mesh_bcn_hdr.setup.flags;
|
|
||||||
newEntry->txPower = mesh_bcn_hdr.setup.txPower;
|
|
||||||
} else {
|
|
||||||
memset(&newEntry->capabilities, 0, sizeof(SETUP_FLAGS));
|
|
||||||
}
|
|
||||||
|
|
||||||
// insert this at the end of the queue
|
|
||||||
insque((struct qelem *)newEntry, (struct qelem *)meshHead.q_back);
|
|
||||||
nMeshEntries++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* reject a duplicate frame that may have been repeated
|
|
||||||
* TRUE: keep it, FALSE: reject it
|
|
||||||
*/
|
|
||||||
BOOL Mesh_Accept_Frame(void *rxFrame, uint32_t rssi)
|
|
||||||
{
|
|
||||||
IP400_FRAME *frameData = (IP400_FRAME *)rxFrame;
|
|
||||||
struct mesh_entry_t *meshEntry;
|
|
||||||
|
|
||||||
if((meshEntry = findCall(&frameData->source)) != NULL) {
|
|
||||||
// rebooted
|
|
||||||
if(frameData->seqNum == 0xFFFFFFFF)
|
|
||||||
meshEntry->nextSeq = 0;
|
|
||||||
// reject if the seq is lower
|
|
||||||
if(frameData->seqNum < meshEntry->nextSeq)
|
|
||||||
return FALSE;
|
|
||||||
meshEntry->nextSeq = frameData->seqNum + 1;
|
|
||||||
return TRUE;
|
|
||||||
} else {
|
|
||||||
// ok to process: but don't know the sender yet, so add him
|
|
||||||
int16_t actRSSI = rssi/2 - RSSI_SCALAR;
|
|
||||||
AddMeshEntry(frameData, actRSSI, FALSE);
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find a callsign in the list
|
|
||||||
struct mesh_entry_t *findCall(IP400_CALL *call)
|
|
||||||
{
|
|
||||||
struct mesh_entry_t *elem = meshHead.q_forw;
|
|
||||||
|
|
||||||
for(int i=0;i<nMeshEntries;i++) {
|
|
||||||
if(elem->encCall.callbytes.encoded == call->callbytes.encoded)
|
|
||||||
return elem;
|
|
||||||
elem = elem->q_forw;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char capabilties[50];
|
|
||||||
// return the capabilites of a node
|
|
||||||
char *GetCapabilities(SETUP_FLAGS cap)
|
|
||||||
{
|
|
||||||
mesh_bcn_hdr.setup.flags = cap;
|
|
||||||
|
|
||||||
if(mesh_bcn_hdr.hdrBytes[0] == 0) {
|
|
||||||
strcpy(capabilties, "Unknown");
|
|
||||||
}
|
|
||||||
|
|
||||||
// modes
|
|
||||||
if(cap.fsk) {
|
|
||||||
sprintf(capabilties, "%s", FSKSpeeds[cap.rate]);
|
|
||||||
}
|
|
||||||
else if(cap.ofdm) {
|
|
||||||
strcat(capabilties, " OFDM");
|
|
||||||
}
|
|
||||||
else if(cap.aredn) {
|
|
||||||
strcat(capabilties, "AREDN");
|
|
||||||
}
|
|
||||||
|
|
||||||
// repeat mode is on..
|
|
||||||
if(cap.repeat) {
|
|
||||||
strcat(capabilties, " RPT");
|
|
||||||
}
|
|
||||||
|
|
||||||
return capabilties;
|
|
||||||
}
|
|
||||||
|
|
||||||
// list the mesh status: walk the mesh entries
|
|
||||||
void Mesh_ListStatus(void)
|
|
||||||
{
|
|
||||||
USART_Print_string("Stations Heard: %d\r\n", nMeshEntries);
|
|
||||||
if(nMeshEntries == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// process the list
|
|
||||||
struct mesh_entry_t *elem = meshHead.q_forw;
|
|
||||||
char decodedCall[20];
|
|
||||||
uint16_t port;
|
|
||||||
|
|
||||||
USART_Print_string("Call(Port)\tRSSI\tNext Seq\tLast Heard\tHops\tCapabilities\r\n");
|
|
||||||
|
|
||||||
for(int i=0;i<nMeshEntries;i++) {
|
|
||||||
callDecode(&elem->encCall, decodedCall, &port);
|
|
||||||
USART_Print_string("%s(%d)\t%-03d\t%04d\t\t%02d:%02d:%02d\t%d\t%s %d dBm\r\n",
|
|
||||||
decodedCall, port,
|
|
||||||
elem->lastRssi,
|
|
||||||
elem->nextSeq,
|
|
||||||
elem->lastHeard.Hours, elem->lastHeard.Minutes, elem->lastHeard.Seconds,
|
|
||||||
elem->hopCount,
|
|
||||||
GetCapabilities(elem->capabilities), elem->txPower);
|
|
||||||
elem = elem->q_forw;
|
|
||||||
}
|
|
||||||
USART_Print_string("\r\n\n");
|
|
||||||
}
|
|
|
@ -1,305 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: setup.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: Holds and displays the setup data
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <main.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "setup.h"
|
|
||||||
#include "usart.h"
|
|
||||||
|
|
||||||
#define USE_HAL
|
|
||||||
|
|
||||||
// flash stuff
|
|
||||||
#define FLASH_PAGE_ADDR ((uint32_t)0x1007F800)
|
|
||||||
#define FLASH_PAGE_NUM 127
|
|
||||||
static FLASH_EraseInitTypeDef EraseInitStruct;
|
|
||||||
|
|
||||||
// Default Setup Data
|
|
||||||
SETUP_MEMORY setup_memory;
|
|
||||||
|
|
||||||
SETUP_MEMORY def_params = {
|
|
||||||
.params.setup_data.flags = { 1, 0, 0 , 1, 0, FSK_100K }, // LSB specified first
|
|
||||||
.params.setup_data.stnCall ="NOCALL",
|
|
||||||
.params.setup_data.gridSq = "DO21vd",
|
|
||||||
.params.setup_data.latitude = "51.08",
|
|
||||||
.params.setup_data.longitude = "-114.10",
|
|
||||||
.params.setup_data.beaconInt = 5,
|
|
||||||
//
|
|
||||||
.params.radio_setup.lFrequencyBase = 445750000,
|
|
||||||
.params.radio_setup.xModulationSelect = MOD_4FSK,
|
|
||||||
.params.radio_setup.lDatarate = 100000,
|
|
||||||
.params.radio_setup.lFreqDev = 25000,
|
|
||||||
.params.radio_setup.lBandwidth = 200000,
|
|
||||||
.params.radio_setup.dsssExp = 0,
|
|
||||||
.params.radio_setup.outputPower = 14,
|
|
||||||
.params.radio_setup.PADrvMode = PA_DRV_TX_HP,
|
|
||||||
.params.radio_setup.rxSquelch = -95,
|
|
||||||
//
|
|
||||||
.params.FirmwareVerMajor = 0, // current rev is 0.4
|
|
||||||
.params.FirmwareVerMinor = 4,
|
|
||||||
.params.Magic = SETUP_MAGIC,
|
|
||||||
.params.SetupCRC = 0
|
|
||||||
};
|
|
||||||
|
|
||||||
char prtBuf[100];
|
|
||||||
|
|
||||||
// enum fields in setup struct
|
|
||||||
// modulation type
|
|
||||||
char *modTypes[] = {
|
|
||||||
"2FSK",
|
|
||||||
"4FSK",
|
|
||||||
"2GFSK05",
|
|
||||||
"2GFSK1",
|
|
||||||
"4GFSK05",
|
|
||||||
"4GFSK1",
|
|
||||||
"ASK",
|
|
||||||
"OOK",
|
|
||||||
"POLAR",
|
|
||||||
"CW"
|
|
||||||
};
|
|
||||||
|
|
||||||
// PA modes
|
|
||||||
char *paModes[] = {
|
|
||||||
"TX 10dBm Max",
|
|
||||||
"HP 14dBm Max",
|
|
||||||
"TX_HP 20dBm Max"
|
|
||||||
};
|
|
||||||
|
|
||||||
// return the setup struct
|
|
||||||
STN_PARAMS *GetStationParams(void) // get the station params
|
|
||||||
{
|
|
||||||
return &setup_memory.params;
|
|
||||||
}
|
|
||||||
|
|
||||||
// compare call to station callsign
|
|
||||||
// returns true if callsigns match
|
|
||||||
BOOL CompareToMyCall(char *call)
|
|
||||||
{
|
|
||||||
char expCall[20];
|
|
||||||
|
|
||||||
// make sure call sign is padded out to 6 characters b4 comparison
|
|
||||||
strcpy(expCall, setup_memory.params.setup_data.stnCall);
|
|
||||||
strcat(expCall, " ");
|
|
||||||
|
|
||||||
if(!strncmp(call, expCall, MAX_CALL))
|
|
||||||
return TRUE;
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print the setup struct
|
|
||||||
*/
|
|
||||||
void printStationSetup(void)
|
|
||||||
{
|
|
||||||
// station callsign first
|
|
||||||
USART_Print_string("Station Callsign->%s\r\n", setup_memory.params.setup_data.stnCall);
|
|
||||||
if(setup_memory.params.setup_data.flags.ext)
|
|
||||||
USART_Print_string("Extended Callsign->%s\r\n");
|
|
||||||
|
|
||||||
USART_Print_string("Latitude->%s\r\n", setup_memory.params.setup_data.latitude);
|
|
||||||
USART_Print_string("Longitude->%s\r\n", setup_memory.params.setup_data.longitude);
|
|
||||||
USART_Print_string("Grid Square->%s\r\n", setup_memory.params.setup_data.gridSq);
|
|
||||||
|
|
||||||
USART_Print_string("Capabilities->");
|
|
||||||
if(setup_memory.params.setup_data.flags.fsk)
|
|
||||||
USART_Print_string("FSK ");
|
|
||||||
if(setup_memory.params.setup_data.flags.ofdm)
|
|
||||||
USART_Print_string("OFDM ");
|
|
||||||
if(setup_memory.params.setup_data.flags.aredn)
|
|
||||||
USART_Print_string("AREDN ");
|
|
||||||
if(setup_memory.params.setup_data.flags.repeat)
|
|
||||||
USART_Print_string("\r\nRepeat mode on by default\r\n");
|
|
||||||
else
|
|
||||||
USART_Print_string("\r\nRepeat mode off by default\r\n");
|
|
||||||
USART_Print_string("Beacon Interval->%d mins\r\n\n", setup_memory.params.setup_data.beaconInt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void printRadioSetup(void)
|
|
||||||
{
|
|
||||||
// dump the radio init struct
|
|
||||||
uint16_t fWhole = setup_memory.params.radio_setup.lFrequencyBase/1e6;
|
|
||||||
uint16_t fFract = setup_memory.params.radio_setup.lFrequencyBase/1e3 - fWhole*1e3;
|
|
||||||
USART_Print_string("RF Frequency->%d.%d MHz\r\n", fWhole, fFract);
|
|
||||||
|
|
||||||
USART_Print_string("Modulation method->%s\r\n", modTypes[setup_memory.params.radio_setup.xModulationSelect]);
|
|
||||||
|
|
||||||
uint16_t dWhole = setup_memory.params.radio_setup.lDatarate/1000;
|
|
||||||
uint16_t dFract = setup_memory.params.radio_setup.lDatarate - dWhole*1000;
|
|
||||||
USART_Print_string("Data Rate->%d.%d Kbps\r\n", dWhole, dFract);
|
|
||||||
|
|
||||||
uint16_t pWhole = setup_memory.params.radio_setup.lFreqDev/1000;
|
|
||||||
uint16_t pFract = setup_memory.params.radio_setup.lFreqDev - pWhole*1000;
|
|
||||||
USART_Print_string("Peak Deviation->%d.%d KHz\r\n", pWhole, pFract);
|
|
||||||
|
|
||||||
uint16_t bWhole = setup_memory.params.radio_setup.lBandwidth/1000;
|
|
||||||
uint16_t bFract = setup_memory.params.radio_setup.lBandwidth - bWhole*1000;
|
|
||||||
USART_Print_string("Channel Filter Bandwidth->%d.%d KHz\r\n", bWhole, bFract);
|
|
||||||
|
|
||||||
USART_Print_string("Output Power->%d dBm\r\n", setup_memory.params.radio_setup.outputPower);
|
|
||||||
USART_Print_string("PA Mode->%s\r\n", paModes[setup_memory.params.radio_setup.PADrvMode]);
|
|
||||||
USART_Print_string("Rx Squelch->%d\r\n\n\n", setup_memory.params.radio_setup.rxSquelch);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This code manages saving and reading the setup params
|
|
||||||
*/
|
|
||||||
// internals
|
|
||||||
uint32_t CalcSetupCRC(void);
|
|
||||||
|
|
||||||
BOOL UpdateSetup(void)
|
|
||||||
{
|
|
||||||
// update CRC before writing
|
|
||||||
setup_memory.params.SetupCRC = CalcSetupCRC();
|
|
||||||
|
|
||||||
if(WriteSetup() != HAL_OK) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!ReadSetup()) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!VerifySetup()) {
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE; // only one iteration required
|
|
||||||
}
|
|
||||||
|
|
||||||
// verify that the current setup record is valid
|
|
||||||
BOOL VerifySetup(void)
|
|
||||||
{
|
|
||||||
// if the magic number matches, then all is well
|
|
||||||
if(setup_memory.params.Magic != SETUP_MAGIC)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
uint32_t SetupCRC = CalcSetupCRC();
|
|
||||||
|
|
||||||
if(SetupCRC == setup_memory.params.SetupCRC)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the default setup
|
|
||||||
void SetDefSetup(void)
|
|
||||||
{
|
|
||||||
memcpy((void *)&setup_memory.bytes, (const void *)&def_params.bytes, sizeof(SETUP_MEMORY));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read setup from Flash memory
|
|
||||||
// data is stored in the last flash page
|
|
||||||
BOOL ReadSetup(void)
|
|
||||||
{
|
|
||||||
__IO uint32_t data32 = 0;;
|
|
||||||
|
|
||||||
uint32_t memAddr = FLASH_PAGE_ADDR;
|
|
||||||
|
|
||||||
uint32_t *dst_addr = setup_memory.flashwords;
|
|
||||||
uint16_t nwords = sizeof(STN_PARAMS)/sizeof(uint32_t);
|
|
||||||
|
|
||||||
while(nwords--){
|
|
||||||
data32 = *(__IO uint32_t *)memAddr;
|
|
||||||
*dst_addr++ = data32;
|
|
||||||
memAddr += sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// write the setup to OTP memory
|
|
||||||
HAL_StatusTypeDef WriteSetup(void)
|
|
||||||
{
|
|
||||||
HAL_StatusTypeDef status=0;
|
|
||||||
uint32_t PageError;
|
|
||||||
|
|
||||||
__HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_ALL_ERRORS);
|
|
||||||
|
|
||||||
// erase it first
|
|
||||||
EraseInitStruct.TypeErase = FLASH_TYPEERASE_PAGES;
|
|
||||||
EraseInitStruct.Page = FLASH_PAGE_NUM;
|
|
||||||
EraseInitStruct.NbPages = 1;
|
|
||||||
if ((status=HAL_FLASHEx_Erase(&EraseInitStruct, &PageError)) != HAL_OK)
|
|
||||||
return status;
|
|
||||||
|
|
||||||
// waste some time...
|
|
||||||
for(int i=0;i<1000;i++);
|
|
||||||
|
|
||||||
// now write
|
|
||||||
uint32_t memAddr = FLASH_PAGE_ADDR;
|
|
||||||
uint32_t *src_addr = setup_memory.flashwords;
|
|
||||||
uint16_t nwords = sizeof(SETUP_MEMORY)/sizeof(uint32_t);
|
|
||||||
|
|
||||||
while(nwords--)
|
|
||||||
{
|
|
||||||
uint32_t data32 = *(__IO uint32_t *)src_addr++;
|
|
||||||
|
|
||||||
if ((status=HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, memAddr, data32)) != HAL_OK)
|
|
||||||
return status;
|
|
||||||
memAddr += sizeof(uint32_t);
|
|
||||||
}
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
// calcuate the setup CRC
|
|
||||||
uint32_t CalcSetupCRC(void)
|
|
||||||
{
|
|
||||||
uint32_t CRCValue;
|
|
||||||
#ifdef USE_HAL
|
|
||||||
CRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t *)&setup_memory.bytes, sizeof(setup_memory) - sizeof(uint32_t));
|
|
||||||
#else
|
|
||||||
|
|
||||||
uint32_t cnt, count = sizeof(setup_memory) - sizeof(uint32_t);
|
|
||||||
uint8_t *arr = setup_memory.bytes;
|
|
||||||
|
|
||||||
/* Reset CRC data register if necessary */
|
|
||||||
CRC->CR = CRC_CR_RESET;
|
|
||||||
|
|
||||||
|
|
||||||
/* Calculate number of 32-bit blocks */
|
|
||||||
cnt = count >> 2;
|
|
||||||
|
|
||||||
/* Calculate */
|
|
||||||
while (cnt--) {
|
|
||||||
/* Set new value */
|
|
||||||
CRC->DR = *(uint32_t *)arr;
|
|
||||||
|
|
||||||
/* Increase by 4 */
|
|
||||||
arr += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Calculate remaining data as 8-bit */
|
|
||||||
cnt = count % 4;
|
|
||||||
|
|
||||||
/* Calculate */
|
|
||||||
while (cnt--) {
|
|
||||||
/* Set new value */
|
|
||||||
*((uint8_t *)&CRC->DR) = *arr++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Return data */
|
|
||||||
CRCValue = CRC->DR;
|
|
||||||
#endif
|
|
||||||
return(CRCValue);
|
|
||||||
}
|
|
|
@ -1,80 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: tod.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: Time of Day clock
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include "types.h"
|
|
||||||
#include "tod.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
TIMEOFDAY tod = { 0, 0, 0 }; // where we hold the TOD
|
|
||||||
|
|
||||||
// routines
|
|
||||||
void TOD_10SecTimer(void) // 10 second timer
|
|
||||||
{
|
|
||||||
// handle seconds
|
|
||||||
tod.Seconds += 10;
|
|
||||||
if(tod.Seconds >= 60) {
|
|
||||||
tod.Minutes += tod.Seconds/60;
|
|
||||||
tod.Seconds %= 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle minutes
|
|
||||||
if(tod.Minutes >= 60) {
|
|
||||||
tod.Hours += tod.Minutes/60;
|
|
||||||
tod.Minutes %= 60;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle hours
|
|
||||||
if(tod.Hours > 24)
|
|
||||||
tod.Hours %= 24;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return pointer to Time of Day
|
|
||||||
void getTOD(TIMEOFDAY *time)
|
|
||||||
{
|
|
||||||
time->Hours = tod.Hours;
|
|
||||||
time->Minutes = tod.Minutes;
|
|
||||||
time->Seconds = tod.Seconds;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the TOD from HH:MM string
|
|
||||||
// somewhat brute force parser
|
|
||||||
BOOL setTOD(char *todString)
|
|
||||||
{
|
|
||||||
char *todValues[5];
|
|
||||||
|
|
||||||
int nParams = explode_string(todString, todValues, 5, ':', '"');
|
|
||||||
if(nParams != 2)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
int nHours = ascii2Dec(todValues[0]);
|
|
||||||
if((nHours < 0) || (nHours > 24))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
int nMins = ascii2Dec(todValues[1]);
|
|
||||||
if((nHours < 0) || (nHours > 60))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
tod.Hours = nHours;
|
|
||||||
tod.Minutes = nMins;
|
|
||||||
tod.Seconds = 0;
|
|
||||||
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
|
@ -1,300 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: IP400 Modem
|
|
||||||
|
|
||||||
File Name: usart.c
|
|
||||||
|
|
||||||
Author: Martin C. Alcock, VE6VH
|
|
||||||
|
|
||||||
Revision: 1.05
|
|
||||||
|
|
||||||
Description: API for USART handling
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
|
|
||||||
#include <cmsis_os2.h>
|
|
||||||
#include <FreeRTOS.h>
|
|
||||||
#include <semphr.h>
|
|
||||||
|
|
||||||
#include "config.h"
|
|
||||||
#include "stream_buffer.h"
|
|
||||||
#include "types.h"
|
|
||||||
#include "streambuffer.h"
|
|
||||||
#include "usart.h"
|
|
||||||
|
|
||||||
// local defines
|
|
||||||
#define RX_TIMEOUT 10000 // 10 second rx timeout
|
|
||||||
#define TX_TIMEOUT 1000 // 1s transmit timeout
|
|
||||||
|
|
||||||
// stream buffer
|
|
||||||
StreamBufferHandle_t USART_RxBuffer; // handle to buffer
|
|
||||||
StaticStreamBuffer_t USART_StreamBuffer;
|
|
||||||
|
|
||||||
// UART/T Support
|
|
||||||
SemaphoreHandle_t txCompleted; // tx completed semaphore
|
|
||||||
static DATA_ELEMENT USARTRxChar[10]; // last received character
|
|
||||||
|
|
||||||
uint8_t usart_data[bufferSIZE];
|
|
||||||
char usartPrintBuffer[200];
|
|
||||||
|
|
||||||
// fwd refs here...
|
|
||||||
void USART_Receive_char(void);
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
#define LPUART_DMA_SIZE 32
|
|
||||||
static DATA_ELEMENT LPUARTRxChar[LPUART_DMA_SIZE];
|
|
||||||
|
|
||||||
void LPUART_Receive_char(void);
|
|
||||||
|
|
||||||
StreamBufferHandle_t LPUART_RxBuffer; // handle to buffer
|
|
||||||
StaticStreamBuffer_t LPUART_StreamBuffer;
|
|
||||||
uint8_t gps_data[bufferSIZE];
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* API for the rx data buffer
|
|
||||||
*/
|
|
||||||
void USART_API_init(void)
|
|
||||||
{
|
|
||||||
// create the tx completed semaphore
|
|
||||||
txCompleted = xSemaphoreCreateBinary();
|
|
||||||
|
|
||||||
// start USART
|
|
||||||
USART_RxBuffer = xStreamBufferCreateStatic(bufferSIZE, 1, usart_data, &USART_StreamBuffer);
|
|
||||||
USART_RxBuffer_reset();
|
|
||||||
USART_Receive_char();
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
LPUART_RxBuffer = xStreamBufferCreateStatic(bufferSIZE, 1, gps_data, &LPUART_StreamBuffer);
|
|
||||||
LPUART_RxBuffer_reset();
|
|
||||||
LPUART_Receive_char();
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// reset the data buffer
|
|
||||||
void USART_RxBuffer_reset(void)
|
|
||||||
{
|
|
||||||
xStreamBufferReset(USART_RxBuffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// reset the LPUART Buffer
|
|
||||||
void LPUART_RxBuffer_reset(void)
|
|
||||||
{
|
|
||||||
xStreamBufferReset(LPUART_RxBuffer);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// return the number of byte in the buffer
|
|
||||||
size_t databuffer_bytesInBuffer(void)
|
|
||||||
{
|
|
||||||
size_t nBytes = xStreamBufferBytesAvailable(USART_RxBuffer);
|
|
||||||
return nBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get a byte from the buffer: blocks if timeout is zero,
|
|
||||||
// else returns BUFFER_NO_DATA if timeout exceeded
|
|
||||||
DATA_ELEMENT databuffer_get(UART_TIMEOUT_T timeout)
|
|
||||||
{
|
|
||||||
DATA_ELEMENT retval;
|
|
||||||
|
|
||||||
TickType_t tickTimeout;
|
|
||||||
|
|
||||||
if(timeout == 0)
|
|
||||||
tickTimeout = portMAX_DELAY;
|
|
||||||
else
|
|
||||||
tickTimeout = pdMS_TO_TICKS(timeout);
|
|
||||||
|
|
||||||
if(xStreamBufferReceive(USART_RxBuffer, &retval, 1, tickTimeout) == 0)
|
|
||||||
return BUFFER_NO_DATA;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Similar but from GPS buffer
|
|
||||||
*/
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// return the number of byte in the buffer
|
|
||||||
size_t gpsbuffer_bytesInBuffer(void)
|
|
||||||
{
|
|
||||||
size_t nBytes = xStreamBufferBytesAvailable(LPUART_RxBuffer);
|
|
||||||
return nBytes;
|
|
||||||
}
|
|
||||||
// get a bytes
|
|
||||||
DATA_ELEMENT gpsbuffer_get(UART_TIMEOUT_T timeout)
|
|
||||||
{
|
|
||||||
DATA_ELEMENT retval;
|
|
||||||
|
|
||||||
TickType_t tickTimeout;
|
|
||||||
|
|
||||||
if(timeout == 0)
|
|
||||||
tickTimeout = portMAX_DELAY;
|
|
||||||
else
|
|
||||||
tickTimeout = pdMS_TO_TICKS(timeout);
|
|
||||||
|
|
||||||
if(xStreamBufferReceive(LPUART_RxBuffer, &retval, 1, tickTimeout) == 0)
|
|
||||||
return BUFFER_NO_DATA;
|
|
||||||
|
|
||||||
return retval;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// see if the buffer contains a keyword, save data up to it if needed
|
|
||||||
BOOL databuffer_contains(const char *tag, UART_TIMEOUT_T rx_timeout, BOOL saveData, char *SaveBuffer)
|
|
||||||
{
|
|
||||||
DATA_ELEMENT c;
|
|
||||||
|
|
||||||
uint8_t tagSize = (uint8_t)(strlen(tag) & 0xff);
|
|
||||||
uint8_t tagLen = tagSize;
|
|
||||||
|
|
||||||
const char *tagAddr = tag;
|
|
||||||
|
|
||||||
while ((c = databuffer_get(rx_timeout)) != BUFFER_NO_DATA) {
|
|
||||||
if (c == *tagAddr) {
|
|
||||||
if (--tagLen == 0) {
|
|
||||||
if(saveData) {
|
|
||||||
*SaveBuffer++ = c;
|
|
||||||
*SaveBuffer = '\0';
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
tagAddr++;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
tagAddr = tag;
|
|
||||||
tagLen = tagSize;
|
|
||||||
}
|
|
||||||
if(saveData)
|
|
||||||
*SaveBuffer++ = c;
|
|
||||||
}
|
|
||||||
if(saveData)
|
|
||||||
*SaveBuffer = '\0';
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Low level HAL interaction functions
|
|
||||||
*/
|
|
||||||
|
|
||||||
// send a packet (with timeout)
|
|
||||||
BOOL USART_Send_String(const char *string, size_t len)
|
|
||||||
{
|
|
||||||
// send using DMA
|
|
||||||
uint16_t dataLen = (uint16_t)len;
|
|
||||||
if((HAL_UART_Transmit_DMA(&huart1, (const uint8_t *)string, dataLen)) != HAL_OK)
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
// wait for completion..
|
|
||||||
if((xSemaphoreTake(txCompleted, pdMS_TO_TICKS(TX_TIMEOUT))) == pdTRUE)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// send a packet (with timeout)
|
|
||||||
BOOL USART_Send_Char(const char c)
|
|
||||||
{
|
|
||||||
|
|
||||||
// send using interrupt
|
|
||||||
HAL_UART_Transmit_IT(&huart1, (const uint8_t *)&c, 1);
|
|
||||||
|
|
||||||
// wait for completion..
|
|
||||||
if((xSemaphoreTake(txCompleted, pdMS_TO_TICKS(TX_TIMEOUT))) == pdTRUE)
|
|
||||||
return TRUE;
|
|
||||||
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// print a string to the UAR/T
|
|
||||||
void USART_Print_string(char *format, ...)
|
|
||||||
{
|
|
||||||
// process the arg list
|
|
||||||
va_list argptr;
|
|
||||||
va_start(argptr, format);
|
|
||||||
vsprintf(usartPrintBuffer,format, argptr);
|
|
||||||
va_end(argptr);
|
|
||||||
|
|
||||||
USART_Send_String(usartPrintBuffer, strlen(usartPrintBuffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Transmit completed: trigger semaphore
|
|
||||||
void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
|
|
||||||
{
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// Not interested in LPUART
|
|
||||||
if(huart->Instance == LPUART1)
|
|
||||||
return;
|
|
||||||
#endif
|
|
||||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
|
||||||
xSemaphoreGiveFromISR(txCompleted, &xHigherPriorityTaskWoken);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// receive a byte with DMA, wait for DMA completed interrupt
|
|
||||||
void USART_Receive_char(void)
|
|
||||||
{
|
|
||||||
HAL_UART_Receive_IT(&huart1,(uint8_t *)USARTRxChar,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// callback function when rx is completed: overrides previous
|
|
||||||
// __weak definition
|
|
||||||
// NB: Console USART and GPS LPUART share the same HAL routine
|
|
||||||
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
|
|
||||||
{
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// service the LPUART
|
|
||||||
if(huart->Instance == LPUART1) {
|
|
||||||
xStreamBufferSendFromISR(LPUART_RxBuffer, LPUARTRxChar, 1, NULL);
|
|
||||||
HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)LPUARTRxChar,1);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
// service the USART
|
|
||||||
xStreamBufferSendFromISR(USART_RxBuffer, USARTRxChar, 1, NULL);
|
|
||||||
HAL_UART_Receive_IT(&huart1,(uint8_t *)USARTRxChar,1);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if __ENABLE_GPS
|
|
||||||
// send a string to the LPUART
|
|
||||||
void LPUART_Send_String(char *str, uint16_t len)
|
|
||||||
{
|
|
||||||
// send using interrupt
|
|
||||||
HAL_UART_Transmit_IT(&hlpuart1, (const uint8_t *)str, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// receive a byte with DMA, wait for DMA completed interrupt
|
|
||||||
void LPUART_Receive_char(void)
|
|
||||||
{
|
|
||||||
HAL_UART_Receive_IT(&hlpuart1,(uint8_t *)LPUARTRxChar,1);
|
|
||||||
// HAL_UARTEx_ReceiveToIdle_DMA(&hlpuart1,(uint8_t *)LPUARTRxChar,LPUART_DMA_SIZE);
|
|
||||||
//__HAL_DMA_DISABLE_IT(&hlpuart1, DMA_IT_HT);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// callback from GPS Rx
|
|
||||||
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
|
|
||||||
{
|
|
||||||
xStreamBufferSendFromISR(LPUART_RxBuffer, LPUARTRxChar, Size, NULL);
|
|
||||||
HAL_UARTEx_ReceiveToIdle_DMA(&hlpuart1,(uint8_t *)LPUARTRxChar,LPUART_DMA_SIZE);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
|
@ -1,146 +0,0 @@
|
||||||
/*---------------------------------------------------------------------------
|
|
||||||
Project: WL33_NUCLEO_UART
|
|
||||||
|
|
||||||
File Name: utils.c
|
|
||||||
|
|
||||||
Author: MartinA
|
|
||||||
|
|
||||||
Description: utility routines
|
|
||||||
|
|
||||||
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 of the License, or
|
|
||||||
(at your option) any later version, provided this copyright notice
|
|
||||||
is included.
|
|
||||||
|
|
||||||
Copyright (c) Alberta Digital Radio Communications Society
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Revision History:
|
|
||||||
|
|
||||||
---------------------------------------------------------------------------*/
|
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
// ascii to decimal
|
|
||||||
int ascii2Dec(char *dec)
|
|
||||||
{
|
|
||||||
int retval = 0;
|
|
||||||
int sgn = 1;
|
|
||||||
while (*dec) {
|
|
||||||
if(*dec == '-')
|
|
||||||
sgn = -1;
|
|
||||||
else retval = retval*10 + (*dec - '0');
|
|
||||||
dec++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return retval*sgn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// nibble to ascii
|
|
||||||
char nib2ascii(uint8_t nib)
|
|
||||||
{
|
|
||||||
char anib = (char)(nib + '0');
|
|
||||||
anib = (anib > '9') ? anib+('A'-'9') : anib;
|
|
||||||
return anib;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hex to ascii
|
|
||||||
void hex2ascii(uint8_t hex, char *buf)
|
|
||||||
{
|
|
||||||
*buf++= nib2ascii(hex>>4);
|
|
||||||
*buf = nib2ascii(hex & 0xf);
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if an entry is floating point
|
|
||||||
BOOL isfloat(char *val)
|
|
||||||
{
|
|
||||||
while(*val)
|
|
||||||
if(*val++ == '.')
|
|
||||||
return 1U;
|
|
||||||
return 0U;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert an ascii string to a double
|
|
||||||
// until we encounter the decimal place, treat it the same as an integer.
|
|
||||||
// after that, scale each digit down appropriately
|
|
||||||
//
|
|
||||||
double ascii2double(char *val)
|
|
||||||
{
|
|
||||||
double retval = 0;
|
|
||||||
int power = -1, inc = 1;
|
|
||||||
int sgn = 1;
|
|
||||||
|
|
||||||
while(*val) {
|
|
||||||
|
|
||||||
switch(*val) {
|
|
||||||
|
|
||||||
case '-':
|
|
||||||
sgn = -1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '.':
|
|
||||||
power = -1;
|
|
||||||
inc = -1;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
if(inc > 0) {
|
|
||||||
retval = retval*10 + (*val - '0');
|
|
||||||
} else {
|
|
||||||
retval += pow(10.0, power) * (*val - '0');
|
|
||||||
power += inc;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
val++;
|
|
||||||
}
|
|
||||||
return retval * sgn;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Your basic linux-stle (argv, argc) parser based on delimiters
|
|
||||||
// string is destroyed
|
|
||||||
int explode_string(char *str, char *strp[], int limit, char delim, char quote)
|
|
||||||
{
|
|
||||||
int i,l,inquo;
|
|
||||||
|
|
||||||
inquo = 0;
|
|
||||||
i = 0;
|
|
||||||
strp[i++] = str;
|
|
||||||
if (!*str)
|
|
||||||
{
|
|
||||||
strp[0] = 0;
|
|
||||||
return(0);
|
|
||||||
}
|
|
||||||
for(l = 0; *str && (l < limit) ; str++)
|
|
||||||
{
|
|
||||||
if(quote)
|
|
||||||
{
|
|
||||||
if (*str == quote)
|
|
||||||
{
|
|
||||||
if (inquo)
|
|
||||||
{
|
|
||||||
*str = 0;
|
|
||||||
inquo = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
strp[i - 1] = str + 1;
|
|
||||||
inquo = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if ((*str == delim) && (!inquo))
|
|
||||||
{
|
|
||||||
*str = 0;
|
|
||||||
l++;
|
|
||||||
strp[i++] = str + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
strp[i] = 0;
|
|
||||||
return(i);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
Binary file not shown.
Binary file not shown.
11
code/Read,me
11
code/Read,me
|
@ -1,11 +0,0 @@
|
||||||
This directory is the new home of the code, starting with release 0.4. There are two directories, platform and IP400. The platform directory contains the CubeIDE project and
|
|
||||||
IOC file (everything needed to build the hardware specific code), for different platforms. These directories may not contain the latest code. Copy the contents of the IP400
|
|
||||||
directories into the platform directory and then compile.
|
|
||||||
|
|
||||||
The current source code is at Rev level 0.4a, the older code has been removed.
|
|
||||||
|
|
||||||
As of this rev, the supported platforms are:
|
|
||||||
Nucleo CC2 board.
|
|
||||||
Pi Zero HAT with discrete WL33 radio (400 MHz version only). Coming soon.
|
|
||||||
|
|
||||||
Release notes are in the appropriate directory.
|
|
Loading…
Reference in a new issue