const definition in a header file, using macro constants causes linker multiple definition errors - header

G'day! While I have previously found solutions to my programming issues here by Googling, this is the first time I've asked a question, since I couldn't find an answer by Googling.
I'm a professional electronics engineer, but not a software engineer. My (limited) software skills are self-taught, and I particularly struggle with C programming, from lack of understanding. So please treat me as an absolute novice, and explain in simple terms what I've done wrong, and suggestions on how to fix it , if possible.
I'm compiling/linking a program for an old DOS-based PC using the Phar Lap compiler/linker suite. Several of my C modules have #include "codes.c", and I've included an extract from that header file below. Just the relevant lines in sequential order, with intermediate irrelevant lines omitted. (Incidentally, the value 'LAST_IRTYPE' is defined earlier in the file, with a value of 9.)
#ifndef CODES_H
#define CODES_H
#include "AStypes.h" // Typedefs for common types
#define IRtime(x) ((x/IRtimeClkPer_us) + 0.5)
const uShort_16 cusarIRtimes[LAST_IRTYPE + 1][6] = /* carrier pulse-times expressed in timer counts.
NB: IRtimeClkPer_us MUST be #defined (not in
this file!) for every project using this file!
(comment times are in ms:
start-pulse, start-gap, '0', '1', bit-gap, inter-command gap) */
{
{IRtime(250), IRtime(2474), IRtime(2474), IRtime(3582), IRtime(250), IRtime(7000)}, // 0 = dbx 4BX (0.25, 2.474, 2.474, 3.582, 0.25, 7)
{IRtime(2348), IRtime(580), IRtime(580), IRtime(1168), IRtime(580), IRtime(25000)}, // 1 = Sony 12-bit (2.348, 0.58, 0.58, 1.168, 0.58, 25)
{IRtime(2348), IRtime(580), IRtime(580), IRtime(1168), IRtime(580), IRtime(25000)}, // 2 = Sony 16-bit (2.348, 0.58, 0.58, 1.168, 0.58, 25)
{IRtime(8424), IRtime(4192), IRtime(520), IRtime(1576), IRtime(520), IRtime(20000)}, // 3 = JVC (8.424, 4.192, 0.52, 1.576, 0.52, 20)
{IRtime(9040), IRtime(4560), IRtime(552), IRtime(1672), IRtime(552), IRtime(40000)}, // 4 = Squeezebox 3 (9.04, 4.56, 0.552, 1.672, 0.552, 40)
{IRtime(9000), IRtime(4560), IRtime(552), IRtime(1672), IRtime(552), IRtime(40000)}, // 5 = Medion, 5BX, Oppo, Toppy (9, 4.56, 0.552, 1.672, 0.552, 40)
{IRtime(4500), IRtime(4500), IRtime(560), IRtime(1680), IRtime(470), IRtime(45000)}, // 6 = LG BD, Samsung (4.55, 4.55, 0.560, 1.68, 0.515, 45)
{IRtime(8512), IRtime(4272), IRtime(536), IRtime(1592), IRtime(536), IRtime(40000)}, // 7 = Pioneer GR-777 (8.512, 4.272, 0.536, 1.592, 0.536, 40)
{IRtime(8512), IRtime(4272), IRtime(536), IRtime(1592), IRtime(536), IRtime(26000)} // 8 = Pioneer DVD (8.512, 4.272, 0.536, 1.592, 0.536, 26)
};
// Bits per code for 4BX, Sony1, Sony2, JVC, SB3, DTV, LGBD, STV, Pioneer1, Pioneer2:
const uChar_8 cucarBitsPerCode[LAST_IRTYPE + 1] = {6, 12, 15, 16, 32, 32, 32, 32, 32};
/* Whether bits are sent as 'high' (IR on +) or 'low' (IR off -) for
4BX, Sony1, Sony2, JVC, SB3, DTV, LGBD, STV, Pioneer1, Pioneer2: */
const Bool_8 bIRbitsHigh[LAST_IRTYPE + 1] = {bFALSE, bTRUE, bTRUE, bFALSE, bFALSE, bFALSE, bFALSE, bFALSE, bFALSE};
#endif
My understanding of using #ifndef CODES_H / #define CODES_H is that the compiler will only parse/compile the file's contents the first time it's encountered, so any variables defined within will only be defined once, but this doesn't seem to be happening.
When I compile/link my program, I get a series of linker errors like the following, repeated for all but one of the C files that #include codes.h
386|LINK: 8.02 -- Copyright (C) 1986-96 Phar Lap Software, Inc.
Error LINK.3070: Duplicate definition of the symbol "cusarIRtimes" in module "funcs.c".
Error LINK.3070: Duplicate definition of the symbol "cucarBitsPerCode" in module "funcs.c".
Error LINK.3070: Duplicate definition of the symbol "bIRbitsHigh" in module "funcs.c".
Using Notepad++ with all .C and .H files loaded, and doing a search across all open files for cusarIRtimes, it is only in that one place, as above.
Can anyone please explain why the linker finds duplicate definitions, and how I might correct this? Thank you.
Daniel

My understanding of using #ifndef CODES_H / #define CODES_H is that the compiler will only parse/compile the file's contents the first time it's encountered, so any variables defined within will only be defined once, but this doesn't seem to be happening.
It is happening, but it's once per translation unit (C module), which are compiled independently from each other. You can correct this by moving the definitions of cusarIRtimes, cucarBitsPerCode and bIRbitsHigh into one of your C modules, and in the include file replacing them by declarations:
extern const uShort_16 cusarIRtimes[LAST_IRTYPE + 1][6];
extern const uChar_8 cucarBitsPerCode[LAST_IRTYPE + 1];
extern const Bool_8 bIRbitsHigh[LAST_IRTYPE + 1];

Related

Why does my usb HID output rubbish? STM32Cube

I'm trying to make a force feedback wheel, but software isn't my cup of tea.
This is supposed to toggle button 0 and it doesn't.
typedef struct{
uint8_t buttons;
int8_t relativeMvt;
}steer_t;
steer_t steer = {0, 0};
while (1)
{
HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
if(steer.buttons) steer.buttons = 0b00000000;
else steer.buttons = 0b00000001;
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, steer, sizeof(steer));
HAL_Delay(500);
}
My Report descriptor (this is the first time I'm using one):
Running that code, the buttons are static "ON" like so:
They DO change (randomly) only when the "relativeMvt" variable is changed, very weird.
What I've tried:
Swap relativeMvt and buttons in the typeDef
Check the report descriptor size etc
Cry
#define USBD_CUSTOMHID_OUTREPORT_BUF_SIZE 2
#define USBD_CUSTOM_HID_REPORT_DESC_SIZE 45
#define CUSTOM_HID_EPIN_SIZE 2
What do I have to change to make it work? Thanks!
I've solved it. I was missing:
#include "usbd_customhid.h"
and I forgot the "&" when passing my variables:
USBD_CUSTOM_HID_SendReport(&hUsbDeviceFS, &steer, sizeof(steer));

Ambiguous process calcChecksum

CONTEXT
I'm using a code written to work with a GPS module that connects to the Arduino through serial communication. The module starts each packet with a header (0xb5, 0x62), continues with the information you requested and ends with to bytes of checksum, CK_A, and CK_B. I don't understand the code that calculates that checksum. More info about the algorithm of checksum (8-Bit Fletcher Algorithm) in the module protocol (https://www.u-blox.com/sites/default/files/products/documents/u-blox7-V14_ReceiverDescriptionProtocolSpec_%28GPS.G7-SW-12001%29_Public.pdf), page 74 (87 with index).
MORE INFO
Just wanted to understand the code, it works fine. In the UBX protocol, I mentioned there is also a piece of code that explains how it works (isn't write in c++)
struct NAV_POSLLH {
//Here goes the struct
};
NAV_POSLLH posllh;
void calcChecksum(unsigned char* CK) {
memset(CK, 0, 2);
for (int i = 0; i < (int)sizeof(NAV_POSLLH); i++) {
CK[0] += ((unsigned char*)(&posllh))[i];
CK[1] += CK[0];
}
}
In the link you provide, you can find a link to RFC 1145, containing that Fletcher 8 bit algorithm as well and explaining
It can be shown that at the end of the loop A will contain the 8-bit
1's complement sum of all octets in the datagram, and that B will
contain (n)*D[0] + (n-1)*D[1] + ... + D[n-1].
n = sizeof byte D[];
Quote adjusted to C syntax
Try it with a couple of bytes, pen and paper, and you'll see :)

STM32F4 Timing Problem with systick after switching IDE (coocox to TrueStudio)

I am working on a weird problem: As a part of my project, I migrated a firmware from CooCox to TrueStudio. Both, CooCox and TrueStudio automatically create some standard files while creating a project for a specific Microcontroller. The Microcontroller used here is the STM32F407VGT6. I am using ms - delay and s - delay which are derived from the µs - Delay function I will show you.
*edit2: I should mention, that the original project is a pure C project. I am trying to make the Project a C++/C project in TrueStudio.
What I will try now is to migrate the firmware into a TrueStudio pure C project and see if the problem still exists.
I will inform you about the results
**Results: The problem is actually gone now in the pure C Project, but I would really like to implement classes etc using C++. Any ideas how to solve this?
**
*
The initializing systick code is (HCLK Frequency = 168MHz).
*edit1: the HCLK Frequency equals the SYSCLK *
void systick_init(void){
RCC_ClocksTypeDef RCC_Clocks;
Systick_Delay=0;
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config((RCC_Clocks.HCLK_Frequency / 1000000) - 1);
}
The function for the 1µs Delay looks like this:
void delay_us(volatile uint32_t delay)
{
Systick_Delay = delay;
while(Systick_Delay != 0);
}
The Systick Handler contains the following Code:
void SysTick_Handler(void)
{
// Tick für Delay
if(Systick_Delay != 0x00)
{
Systick_Delay--;
}
}
When I create a .hex file to flash the µC with using Coocox, the timing function works (with some minor accuracy mistakes that don't bother me).
When I create the .hex file with TrueStudio, the delays have massive inaccuracys. For example, a delay of 500ms becomes a delay of roughly 2s.
Since the Code is written dependant on the actual HCLK_Frequency, I can't understand the mistake and in my understanding, even if the HCLK should differ, the 1µs Delay should still take about 1µs.
My next step will be comparing the automatically created system files, but maybe anyone has a different approach / another idea?
*edit 3: I normally include my systick - header with the command ' extern "C" '. So my systick source file is a .c file. When I rename the file to systick.cpp, and I include the header without 'extern "C"', the delay function does not work at all. Maybe, that helps with the solution?
*
You are either running off a different clock or have different PLL settings. Looks like your clock speed is 1/4 of what you had before.
The basic startup code provided does not always set the maximum speed for the board. Have a look in some of the examples in the stm32cube.zip code. You will find some System Clock Configuration code for your board which will select the correct clock and pll settings. (this will be in your code somewhere as well).
Look in main.c under stm32cubef4/projects/STM32F4-Discovery\Demonstrations\src.
You will find the following code which sets up the clock:
/**
* #brief System Clock Configuration
* The system Clock is configured as follow :
* System Clock source = PLL (HSE)
* SYSCLK(Hz) = 168000000
* HCLK(Hz) = 168000000
* AHB Prescaler = 1
* APB1 Prescaler = 4
* APB2 Prescaler = 2
* HSE Frequency(Hz) = 8000000
* PLL_M = 8
* PLL_N = 336
* PLL_P = 2
* PLL_Q = 7
* VDD(V) = 3.3
* Main regulator output voltage = Scale1 mode
* Flash Latency(WS) = 5
* #param None
* #retval None
*/
static void SystemClock_Config(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct;
RCC_OscInitTypeDef RCC_OscInitStruct;
/* Enable Power Control clock */
__HAL_RCC_PWR_CLK_ENABLE();
/* The voltage scaling allows optimizing the power consumption when the device is
clocked below the maximum system frequency, to update the voltage scaling value
regarding system frequency refer to product datasheet. */
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/* Enable HSE Oscillator and activate PLL with HSE as source */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = 8;
RCC_OscInitStruct.PLL.PLLN = 336;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = 7;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
/* Select PLL as system clock source and configure the HCLK, PCLK1 and PCLK2
clocks dividers */
RCC_ClkInitStruct.ClockType = (RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2);
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5);
/* STM32F405x/407x/415x/417x Revision Z devices: prefetch is supported */
if (HAL_GetREVID() == 0x1001)
{
/* Enable the Flash prefetch */
__HAL_FLASH_PREFETCH_BUFFER_ENABLE();
}
}
I found the solution now!
For anyone having similar problems:
You need to declare the SysTick_Handler function as
extern "C" void SysTick_Handler(void)
{
//Tick für Delay
if(Systick_Delay != 0x00)
{
Systick_Delay--;
}
}
Now it is working like it is supposed to do.

Doing "uint8x8x4_t - 128" then divising this by 2

I'm a bit mixed up about how to achieve a division by a scalar on Neon in a specific case.
In a c++ context, I'm achieving a contrast effect with a very rudimentary algorithm:
if (currentEffect == "contrast_with_cpp")
{
r += ((r - 128) / 2);
g += ((g - 128) / 2);
b += ((b - 128) / 2);
}
I would like to port this algorithm to neon intrinsics.
I've tried, but I'm totally newbie to this approach, and I cannot debug this code in Visual Studio. It is compiled at startup and integrated to a Windows Phone application.
if (currentEffect == "contrast_with_neon") /* Experimental, not working *
{
// To test
copy_rgb = rgb;
// Substract 128 from the copy, prevent it should be a signed variable
?
// Get half value from copy and put it in another copy
uint8x8x4_t otherCopy = interleaved;
otherCopy.val[2] = vmul_n_f32(copy_rgb.val[2], 0.5);
otherCopy.val[1] = vmul_n_f32(copy_rgb.val[1], 0.5);
otherCopy.val[0] = vmul_n_f32(copy_rgb.val[0], 0.5);
// Add it to the first copy
copy_rgb.val[2] = vadd_u8(copy_rgb.val[2], otherCopy.val[2]);
copy_rgb.val[1] = vadd_u8(copy_rgb.val[2], otherCopy.val[1]);
copy_rgb.val[0] = vadd_u8(copy_rgb.val[2], otherCopy.val[0]);
rgb = copy_rgb;
}
Is this achievable using intrinsics?
[Edit] I guess the color data structure is similar to this
Stop wasting your time with intrinsics. It's a real pain, especially with gcc.
Try this in assembly :
vmov.i16 qMdeian, #128 // put this line outside of loop
// -----------------------------------------------
vmovl.u8 qRed, dRed
vmovl.u8 qGrn, dGrn
vmovl.u8 qBlu, dBlu
vsub.s16 qRedTemp, qRed, qMedian
vsub.s16 qGrnTemp, qGrn, qMedian
vsub.s16 qBluTemp, qBlu, qMedian
vshr.s16 qRedTemp, #2
vshr.s16 qGrnTemp, #2
vshr.s16 qBluTemp, #2
vadd.s16 qRed, qRedTemp
vadd.s16 qGrn, qGrnTemp
vadd.s16 qBlu, qBluTemp
vqmovun.s16 dRed, qRed
vqmovun.s16 dGrn, qGrn
vqmovun.s16 dBlu, qBlu
If the does saturate at 255, and any negative values will become zeros which I assume is intended.
PS : What are you doing with float?

GNU Radio File Format for the recorded samples

Do you know the format in which GNU Radio ( File Sink in GNU Radio Companion) stores the samples in the Binary File?
I need to read these samples in Matlab, but the problem is the file is too big to be read in Matlab.
I am writing the program in C++ to read this binary file.
The file sink is just a dump of the data stream. If the data stream content was simple bytes then the content of the file is straightforward. If the data stream contained complex numbers then the file will contain a list of complex numbers where each complex number is given by two floats and each float by (usually) 4 bytes.
See the files gnuradio/gnuradio-core/src/lib/io/gr_file_sink.cc and gr_file_source.cc for the implementations of the gnuradio file reading and writing blocks.
You could also use python and gnuradio to convert the files into some other format.
from gnuradio import gr
# Assuming the data stream was complex numbers.
src = gr.file_source(gr.sizeof_gr_complex, "the_file_name")
snk = gr.vector_sink_c()
tb = gr.top_block()
tb.connect(src, snk)
tb.run()
# The complex numbers are then accessible as a python list.
data = snk.data()
Ben's answer still stands – but it's from a time long past (the module organization points at GNU Radio 3.6, I think). Organizationally, things are different now; data-wise, the File Sink remained the same.
GNU Radio now has relatively much block documentation in their wiki. In particular, the File Sink documentation page has a section on Handling File Sink data; not to overquote that:
// This is C++17
#include <algorithm>
#include <cmath>
#include <complex>
#include <cstddef>
#include <filesystem>
#include <fstream>
#include <string_view>
#include <vector>
#include <fmt/format.h>
#include <fmt/ranges.h>
using sample_t = std::complex<float>;
using power_t = float;
constexpr std::size_t read_block_size = 1 << 16;
int main(int argc, char *argv[]) {
// expect exactly one argument, a file name
if (argc != 2) {
fmt::print(stderr, "Usage: {} FILE_NAME", argv[0]);
return -1;
}
// just for convenience; we could as well just use `argv[1]` throughout the
// code
std::string_view filename(argv[1]);
// check whether file exists
if (!std::filesystem::exists(filename.data())) {
fmt::print(stderr, "file '{:s}' not found\n", filename);
return -2;
}
// calculate how many samples to read
auto file_size = std::filesystem::file_size(std::filesystem::path(filename));
auto samples_to_read = file_size / sizeof(sample_t);
// construct and reserve container for resulting powers
std::vector<power_t> powers;
powers.reserve(samples_to_read);
std::ifstream input_file(filename.data(), std::ios_base::binary);
if (!input_file) {
fmt::print(stderr, "error opening '{:s}'\n", filename);
return -3;
}
// construct and reserve container for read samples
// if read_block_size == 0, then read the whole file at once
std::vector<sample_t> samples;
if (read_block_size)
samples.resize(read_block_size);
else
samples.resize(samples_to_read);
fmt::print(stderr, "Reading {:d} samples…\n", samples_to_read);
while (samples_to_read) {
auto read_now = std::min(samples_to_read, samples.size());
input_file.read(reinterpret_cast<char *>(samples.data()),
read_now * sizeof(sample_t));
for (size_t idx = 0; idx < read_now; ++idx) {
auto magnitude = std::abs(samples[idx]);
powers.push_back(magnitude * magnitude);
}
samples_to_read -= read_now;
}
// we're not actually doing anything with the data. Let's print it!
fmt::print("Power\n{}\n", fmt::join(powers, "\n"));
}